Insertion sort algorithm, weird behaviour - c

I am learning C programming and I'm currently on a classic one, the insertion sort algorithm.
For contextualization, I have a set of 3 arrays to test on :
the first one which is disordered
the second one is in a descending order
and the last one is is the ordered one but with a swap between 2 elements.
Here is my code :
int insertionSort(int* tab, int n){
int i;
for (i=1; i<n; i++){
int j = i;
while(tab[j] < tab[j-1]) {
swap(&tab[j-1], &tab[j]);
j-=1;
}
}
affiche(tab, n);
return 0;
}
For the 2 last arrays, it works fine.
But for the first one I got :
6 6 7 8 10 32521 14 15 17 19 20 21 23 25 26 28 28 28 32 32 34 35 38 38 39 43 44 46 48 49 50 58 59 62 64 65 69 71 75 79 79 79 81 84 86 89 92 93 97 99
instead of
3 6 6 7 8 10 14 15 17 19 20 21 23 25 26 28 28 28 32 32 34 35 38 38 39 43 44 46 48 49 50 58 59 62 64 65 69 71 75 79 79 79 81 84 86 89 92 93 97 99
As you can see, the algorithm works fine for a big part of the array, but for the sixth minimal values, I have random values (sometimes there are 92,93,97... for the first ones).
I don't have any core dump, which means that I am in the array's space in memory, but some values like 32521 let me think that my index j goes too far in memory.
Frankly, I don't see where the problem is.

Look at this loop
while(tab[j] < tab[j-1]) {
swap(&tab[j-1], &tab[j]);
j-=1;
}
j can run happily all over the place. There needs to be something that detects that j isnt < 0 (actually < 1 since you access 'tab[j-1]')
maybe
while((j >= 1) && (tab[j] < tab[j-1]) ) {
swap(&tab[j-1], &tab[j]);
j-=1;
}

Related

Output in read file and sort integers leaves a white space I can't find

My code takes in a text document argument and sorts the integers but when I run testing, it fails a simple white space at the end instead of a \n but I figure out how to stop the final number in the array with a new line instead of a space. Here is the code:
/* display values */
for (i = 0; i < count; i++ ) {
printf ("%ld ", sorted[i]);
}
Here is the test result and the issue:
Program Output
1: 1 2 3 4 5 5 7 8 9 9 9 10 10 11 11 12 14 17 18 20 20 20 24 24 25 25 26 26 27 27 28 28 29 30 30 30 30 31 33 35 35 36 38 40 40 41 42 42 42 47 47 47 48 48 48 48 50 50 51 52 52 52 54 54 57 57 57 57 57 60 61 61 62 62 62 63 64 66 66 66 67 67 69 70 72 72 73 73 75 77 80 82 83 83 83 84 85 86 87 88 88 88 89 91 92 93 94 94 96 97 97 99 [blank space]
Expected Program Output
1: 1 2 3 4 5 5 7 8 9 9 9 10 10 11 11 12 14 17 18 20 20 20 24 24 25 25 26 26 27 27 28 28 29 30 30 30 30 31 33 35 35 36 38 40 40 41 42 42 42 47 47 47 48 48 48 48 50 50 51 52 52 52 54 54 57 57 57 57 57 60 61 61 62 62 62 63 64 66 66 66 67 67 69 70 72 72 73 73 75 77 80 82 83 83 83 84 85 86 87 88 88 88 89 91 92 93 94 94 96 97 97 99
2: [new line]
I tried putting in a \n in printf ("%ld ", sorted[i]); after sorted[i] but it needs to go at the close of the array and I'm not certain how (or where) to add it with cause more issues.
/* display values */
for (i = 0; i < count; i++ ) {
printf ("%ld ", sorted[i]);
}
This outputs a space after each number. If that's not what you want, don't do it. Maybe you want this:
/* display values */
if (count > 0)
printf ("%ld", sorted[0]);
for (i = 1; i < count; i++ ) {
printf (" %ld", sorted[i]); // space before every number but first
}
If one doesn't want to duplicate code.
#include <stdio.h>
int main(void) {
const size_t count = 100;
size_t i;
/* display values */
for (i = 0; i < count; i++ ) {
printf ("%s%ld", i ? " " : "", i + 1 /*sorted[i]*/ );
}
fputc('\n', stdout);
return 0;
}
I expect it to be slower, but I think the intent of the code is clearer.

Printing from 1 to 100 in columns

Code:
for(int i = 1; i <= 100; i++){
if(i % 10 == 1)
printf("\n%d", i);
else printf("%4d",i);
}
Results:
(blank line)
1 2 3 4 5 6 7 8 9 10
11 12 13 14 15 16 17 18 19 20
21 22 23 24 25 26 27 28 29 30
31 32 33 34 35 36 37 38 39 40
41 42 43 44 45 46 47 48 49 50
51 52 53 54 55 56 57 58 59 60
61 62 63 64 65 66 67 68 69 70
71 72 73 74 75 76 77 78 79 80
81 82 83 84 85 86 87 88 89 90
91 92 93 94 95 96 97 98 99 100
How can I remove the first blank line without doing something like:
for(int i = 1; i <= 100; i++){
if(i == 1 || i % 10 == 1)
printf("\n%d", i);
else printf("%4d",i);
}
And how can I 'indent' the columns? As the last column isn't properly arranged, and I have no idea how to fix it using printf's.
At last, sorry for wrinting '(blank line)' as I don't know how to make a blank line, and thanks for the help.
Rather than printing a newline at the start of a line, print it at the end instead:
for (int i = 1; i <= 100; i++){
printf("%4d",i);
if (i % 10 == 0)
printf("\n");
}
This prints each number in a 4 character field, then prints a newline if the last number is divisible by 10.
Output:
1 2 3 4 5 6 7 8 9 10
11 12 13 14 15 16 17 18 19 20
21 22 23 24 25 26 27 28 29 30
31 32 33 34 35 36 37 38 39 40
41 42 43 44 45 46 47 48 49 50
51 52 53 54 55 56 57 58 59 60
61 62 63 64 65 66 67 68 69 70
71 72 73 74 75 76 77 78 79 80
81 82 83 84 85 86 87 88 89 90
91 92 93 94 95 96 97 98 99 100
The style is strange, a newline doesn't belong at the start of a string literal. A printf call should print the line and then output a newline if necessary:
"\nBad style"
"Good style\n"
To print the values correctly, change the logic. Always print the values of i, and then check if i is divisible by 10, and print the newline if it is.
for(int i = 1; i <= 100; i++)
printf("%*d%c", (i % 10 == 1)? 0 : (i == 2) ? 4 : 3, i, (i % 10) ? ' ' : '\n');
I have always done something like this:
#include <stdio.h>
int main (void) {
for (int i = 0; i < 100; i++) {
if (i && i % 10 == 0) putchar ('\n');
printf ("%4d", i + 1);
}
putchar ('\n');
return 0;
}
You can also you separate format strings to accomplish the same thing:
char *fmt = "%4d",
*fmtn = "%4d\n";
for (int i = 0; i < 100; i++)
printf ((i+1) % 10 == 0 ? fmtn : fmt, i + 1);
putchar ('\n');
(note: in both cases the loop is indexed from 0 to accommodate indexing arrays)
Example Use/Output
$ ./bin/arraycols
1 2 3 4 5 6 7 8 9 10
11 12 13 14 15 16 17 18 19 20
21 22 23 24 25 26 27 28 29 30
31 32 33 34 35 36 37 38 39 40
41 42 43 44 45 46 47 48 49 50
51 52 53 54 55 56 57 58 59 60
61 62 63 64 65 66 67 68 69 70
71 72 73 74 75 76 77 78 79 80
81 82 83 84 85 86 87 88 89 90
91 92 93 94 95 96 97 98 99 100

How to copy an array

I have defined an array like this:
uint8_t brightnessvariants[4][101]={{1,2,...},{3,4,...},{5,6,...},{7,8,...}};
Now for my application i have to fill another array with one of the 4 arrays:
uint8_t brightnesstable[] = brightnessvariants[index][];
But that doesn't work. Index is counted from 0 to 3.
brightnesstable and brightnessvariants are defined in a header file as extern
How can I do it right?
Simply do
uint8_t brightnesstable[101];
memcpy(brightnessstable, brightnessvariants[index], 101*sizeof(uint8_t));
brightnessvariants[index] is the address of the first item in the (index+1)nth row and the number of bytes you want to copy is
ROWSIZE*sizeof(ITEM_SIZE).
It really depends on what you need to do. If you need to create separate storage for a duplication of one of the rows of brightnessvariants, then you can simply declare a separate array and copy the values as discussed in the comments and the other answer.
If, however, you simply need to access one of the rows of brightnessvariants in the current scope, then there is no need for separate storage and copying. All that is required is to declare a pointer and assign the starting address of the desired row. Then you can access the desired row of brightnessvariants as if it were a separate array. e.g.
uint8_t brightnessvariants[4][101] = {{0}}, *btable = NULL;
Above, btable (short for your brightnesstable) is simply a uint8_t pointer. It can be assigned the the address of any of the rows in brightnessvariants. e.g. for the second row
btable = brightnessvariants[1];
btable can then be used to access any value within the second row, just as if it were a separate array. Here is a short example that may help:
#include <stdio.h>
#include <stdint.h>
int main (void) {
uint8_t brightnessvariants[4][101] = {{0}}, *btable = NULL;
int nrows = sizeof brightnessvariants / sizeof *brightnessvariants;
for (int i = 0; i < 101; i++) {
brightnessvariants[0][i] = i + 1;
brightnessvariants[1][i] = i + 3;
brightnessvariants[2][i] = i + 5;
brightnessvariants[3][i] = i + 7;
}
for (int i = 0; i < nrows; i++) {
printf ("\nbrightnesstable[%d] :\n\n", i);
btable = brightnessvariants[i];
for (int j = 0; j < 101; j++) {
if (j && j % 10 == 0) putchar ('\n');
printf (" %3hhu", btable[j]);
}
putchar ('\n');
}
return 0;
}
Example Use/Output
$ ./bin/ptrtobtable
brightnesstable[0] :
1 2 3 4 5 6 7 8 9 10
11 12 13 14 15 16 17 18 19 20
21 22 23 24 25 26 27 28 29 30
31 32 33 34 35 36 37 38 39 40
41 42 43 44 45 46 47 48 49 50
51 52 53 54 55 56 57 58 59 60
61 62 63 64 65 66 67 68 69 70
71 72 73 74 75 76 77 78 79 80
81 82 83 84 85 86 87 88 89 90
91 92 93 94 95 96 97 98 99 100
101
brightnesstable[1] :
3 4 5 6 7 8 9 10 11 12
13 14 15 16 17 18 19 20 21 22
23 24 25 26 27 28 29 30 31 32
33 34 35 36 37 38 39 40 41 42
43 44 45 46 47 48 49 50 51 52
53 54 55 56 57 58 59 60 61 62
63 64 65 66 67 68 69 70 71 72
73 74 75 76 77 78 79 80 81 82
83 84 85 86 87 88 89 90 91 92
93 94 95 96 97 98 99 100 101 102
103
brightnesstable[2] :
5 6 7 8 9 10 11 12 13 14
15 16 17 18 19 20 21 22 23 24
25 26 27 28 29 30 31 32 33 34
35 36 37 38 39 40 41 42 43 44
45 46 47 48 49 50 51 52 53 54
55 56 57 58 59 60 61 62 63 64
65 66 67 68 69 70 71 72 73 74
75 76 77 78 79 80 81 82 83 84
85 86 87 88 89 90 91 92 93 94
95 96 97 98 99 100 101 102 103 104
105
brightnesstable[3] :
7 8 9 10 11 12 13 14 15 16
17 18 19 20 21 22 23 24 25 26
27 28 29 30 31 32 33 34 35 36
37 38 39 40 41 42 43 44 45 46
47 48 49 50 51 52 53 54 55 56
57 58 59 60 61 62 63 64 65 66
67 68 69 70 71 72 73 74 75 76
77 78 79 80 81 82 83 84 85 86
87 88 89 90 91 92 93 94 95 96
97 98 99 100 101 102 103 104 105 106
107
Look things over and let me know if you have any questions. If you need an example of copying instead of the use of a pointer, let me know and I'm happy to help.

Runtime error in codechef practice questions

I'm getting "sigsegv" , a runtime error from the following code when i try to run it on codechef while the code works fine on my computer with various test inputs.I've also kept in mind the constraints given in the problem but I'm still unable to debug it. The question is not from any contest but a practice problem . Please point out any mistake you can find .
Actual codechef question
#include<stdio.h>
int cash[101][101]={0};
int rec[101][2];
int ri=0;
int sumx(int mat[101][101],int i,int j,int lines)
{
int n=0,a=0,b=0;
if(cash[i][j]!=0)
{
return cash[i][j];
}
else if(i==lines-2)
{
n=(mat[i+1][j]>mat[i+1][j+1])?mat[i+1][j]:mat[i+1][j+1];
cash[i][j]=n+mat[i][j];
rec[ri][0]=i;
rec[ri++][1]=j;
return n+mat[i][j];
}
else
{
a=sumx(mat,i+1,j,lines);
b=sumx(mat,i+1,j+1,lines);
n=(a>b)?a:b;
cash[i][j]=n+mat[i][j];
rec[ri][0]=i;
rec[ri++][1]=j;
return n+mat[i][j];
}
}
int main()
{
int i=0,k=0;
int lines=0,n=0;
int r=0;
int tc=0;
int mat[101][101];
scanf("%d",&tc);
while(tc--)
{
scanf("%d",&lines);
i=0;
k=0;
while(i<lines)
{
while(k<=i)
{
scanf("%d",&mat[i][k]);
k++;
}
k=0;
i++;
}
if(lines==1)
{
r=mat[0][0];
}
else
{
r=sumx(mat,0,0,lines);
}
i=0;
while(i<ri)
{
cash[(rec[i][0])][(rec[i][1])]=0;
rec[i][0]=0;
rec[i][1]=0;
i++;
}
ri=0;
printf("%d\n",r);
}
return 0;
}
The error is with lines
while(i<ri)
{
cash[(rec[i][0])][(rec[i][1])]=0;
rec[i][0]=0;
rec[i][1]=0;
i++;
}
the values of rec[i][0] rec[i][1] can be undefined in some cases ie they may return garbage values
You can Use memset instead to change the values to 0
memset(rec,0,sizeof(rec));
memset(cash,0,sizeof(cash));
I ran your solution , there's a bug in your algorithm implementation try finding it yourself
I can provide you a test case(using a testcase generator) for which it fails
21
79
89 28
14 6 63
96 58 67 48
80 8 22 27 8
24 21 23 96 97 72
38 90 95 83 57 60 94
13 96 9 24 65 27 67 40
26 20 58 42 29 8 52 49 37
80 65 65 34 79 10 89 11 20 84
57 59 72 79 51 67 84 70 43 62 96
16 4 18 9 5 40 34 2 15 4 28 50
29 1 60 39 28 92 38 65 95 57 10 71 37
25 78 96 43 17 51 88 19 0 30 20 80 39 35
55 41 63 76 4 20 97 72 43 93 76 11 82 33 25
61 85 41 77 42 90 20 5 69 51 4 54 41 18 83 72
12 56 21 82 7 1 84 26 47 26 22 52 84 39 75 70 89
12 39 83 92 49 20 35 20 31 96 66 75 48 79 13 51 49 50
42 81 0 58 70 40 16 83 27 34 79 64 14 26 19 22 38 55 93
64 81 26 29 47 22 73 61 3 2 61 99 18 43 33 10 13 46 24 53
5 56 0 0 3 0 71 12 82 34 17 11 14 51 1 82 73 53 85 75 89
correct answer is 1431 while your code returns 1299
#Randomizer : The code runs fine with the output as 1431 , not 1299 . Anyways , as you suggested about the garbage being generated from rec[i][0] rec[i][1], It never appeared to me that rec[i][0] rec[i][1] could be generating garbage as I only accessed the used up cells . However , memset eliminated the need of rec , so cash was easily reset to zero . All i did was remove the rec matrix and reset cash using memset and the code ran fine on codechef. I couldn't figure out how it could be generating garbage , still , its accepted on codechef since I removed rec part . Thank you for the help.

Openmp compiles, but "parallel for" isn't working as planned in C

I am working on Mac OSX 10.8.3, and I am programming in C. I am using bash as my shell and I am using gcc-mp-4.7 from macports, since I know the gcc from apple sometimes doesn't fully work with openmp. I have ran a few openmp files before and they typically work fine, however when I try to use the parallel for pragma, I doesn't work how I would think it would. An example of my .c file is below:
#include <omp.h>
#include <stdio.h>
int main (int argc, char *argv[]) {
int n;
#pragma omp for
for(n=0; n<100; ++n)
{
printf(" %d", n);
}
printf(".\n");
}
The output 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99., every single time (over 20 spams).
This shouldn't be happening if is it was running in parallel, there is nothing to protect the order like this. I believe it is obviously running in sequencial order ignoring the command to parallelize it.
Does anyone know what I might be doing wrong? Thanks for any help you can offer.
You should use #pragma omp parallel for:
#pragma omp parallel for
for(n=0; n<100; ++n)
{
printf(" %d", n);
}
or separate #pragma omp parallel and #pragma omp for, if you prefer:
#pragma omp parallel
{
#pragma omp for
for(n=0; n<100; ++n)
{
printf(" %d", n);
}
}
The important thing to note is that #pragma omp parallel creates a pool of threads and #pragma omp for uses the created pool. If you don't have a pool, it's just going to be single-threaded.
Make sure you're passing -fopenmp when building.
Example:
$ gcc -fopenmp example.c -o example
$ ./example
13 0 78 65 52 39 14 1 26 91 79 66 53 40 15 2 27 92 80
67 54 41 16 3 28 93 81 68 55 42 17 4 29 94 82 69 56 43
18 5 30 95 83 70 57 44 19 6 31 96 84 71 58 45 20 7 32
97 85 72 59 46 21 8 33 98 86 73 60 47 22 9 34 99 87 74
61 48 23 10 35 88 75 62 49 24 11 36 89 63 76 50 25 12
37 90 64 77 51 38.
The outer most loop must include the parallel keyword to create a new pool of threads. So it should be:
#pragma omp parallel for

Resources