Search code examples
czeroqsort

qsort creates a non specific number of zeros


So my program reads integers from a file while skipping lines that start with #, stores then in an array and prints them sorted using the qsort function. However, when they are printed, at the beginning for some reason it prints a number of zeros and then the sorted numbers. If the pairs of numbers are 60 I get 21 zeros, if the pairs are 103688 it prints 60151 zeros.

The input file:

#Skip
#These
#Lines
25  8
25  19
25  23
25  28
25  29
25  30
25  33
25  35
25  50
25  54
25  55

The program is:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>


typedef struct {
    int start;
    int end;   
} path;

int cmp(const void *a,const void *b){
    int l=((path*)a)->start;
    int r=((path*)b)->start;

    if(l>r)
        return 1;
    if(l<r)
        return -1;
    if(l==r)
        return 0;
}

int doublesize(path** array,int n){
    path* new_array=malloc(n*2*sizeof(path));
    if(new_array==NULL){
        printf("Error allocating memory\n");
        abort();
    }

    for(int i=0;i<n;i++){
        new_array[i]=(*array)[i];
    }
    free(*array);
    *array=new_array;
    n*=2;
    return n;
}

int main()
{
    int maxsize=10;
    int test;
    path* array=malloc(maxsize*sizeof(path));
    if(array==NULL) {
        printf("Error allocating memory\n");
        abort();
    }

    FILE* fd=fopen("Test.txt","r");
    if(fd==NULL) {
        printf("Error opening file\n");
        abort();
    }
    char buff[200];
    int counter=0;

    char c;
    while(fgets(buff,200,fd)) {
        c=buff[0];
        if(c=='#') {
            continue;
        }
        sscanf(buff,"%d%d",&array[counter].start,&array[counter].end);
        counter++;
        if(counter==maxsize){
           maxsize=doublesize(&array,maxsize); 
        }
    }
    counter=0;
    qsort(&array[0],maxsize,sizeof(path),cmp);
    for(int i=0;i<maxsize;i++){
        printf("%d\t%d\n",array[i].start,array[i].end);
        if(array[i].start==0)
            counter++;
    }
    printf("%d\n",counter);
    fclose(fd);
    free(array);
    return 0;
}

Solution

  • You are sorting and then printing maxsize elements, when your array only contains counter elements (after your first while loop). You should use the exact number of elements when sorting and when printing.

    The fact that you see a lot of 0 is merely a coincidence. When you allocate space using malloc(), the content of your array is undefined, meaning that everything that you don't explicitly overwrite will have an undefined value (it could be 0 or it could be another random value). When you sort, all the 0s will be moved to the beginning, but anything else that was undefined (and not 0) will actually get in the middle of your data, possibly becoming indistinguishable from real data.

    This is not qsort's fault, it's malloc's fault (and really ultimately your fault).

    TL;DR: keep a variable holding the exact number of elements in the array and never operate after that number.

    A quick solution (I've marked the modifications with ^^^):

    int total = 0;
    //  ^^^^^
    int counter = 0;
    char c;
    
    while(fgets(buff, 200, fd)) {
        if(buff[0] == '#')
            continue;
    
        sscanf(buff,"%d%d", &array[counter].start, &array[counter].end);
        total++;
    //  ^^^^^
    
        if(total == maxsize)
    //     ^^^^^
            maxsize = doublesize(&array, maxsize);
    }
    
    qsort(&array[0], total, sizeof(path), cmp);
    //               ^^^^^
    
    for(int i = 0; i < total; i++){
    //                 ^^^^^
        printf("%d\t%d\n", array[i].start, array[i].end);
    
        if(array[i].start == 0)
            counter++;
    }