Weiheng Li Weiheng Li - 2 months ago 7
C Question

About qsort() in C, difference between ** buf and buf[][]

When I use qsort() in the C on my Mac, these code works well, It can sort every lines in one file well.

int compare(const void *p, const void *q) {
return strcmp(p,q);
}

void function_name(){
char buf[1024][1024];
int i=0;
FILE * fp;
if(!(fp=fopen(filename,"r"))){
perror("Open error!");
exit(0);
}
while(fgets(buf[i],1024,fp)){
//printf("%s",buf[i]);
i++;
}
qsort(buf, i, sizeof(buf[0]), compare);
}


However, when I use malloc to assign the space, it sucks. Why is that?
The code below shows I use malloc to make one two-dimension array. I print the content of buf before and after. It seems that lose all the information.

int i=0;
FILE * fp;
char ** buf;
buf = (char **)malloc(sizeof(char*)*1024);
if(!(fp=fopen(filename,"r"))){
perror("Open error!");
exit(0);
}
buf[0]=(char *)malloc(sizeof(char)*1024);
while(fgets(buf[i],1024,fp)){
i++;
buf[i]=(char *)malloc(sizeof(char)*1024);
}
for(int j=0;j<i;j++){
printf("%s",buf[j]);
}
printf("hehe%ld\n",sizeof(char)*1024);

qsort(buf, i, sizeof(char)*1024, compare);

printf("hehe\n");
for(int j=0;j<i;j++){
printf("%s",buf[j]);
}


output:

a
A
b
c
d
D
C

E
e
B
d
e
f
a
hehe1024
hehe
(null)(null)(null)(null)(null)(null)(null)(null)(null)(null)(null)(null)(null)(null)(null)(null)


Most important, how to fix my malloc version?

Answer

When you attempt to qsort buf declared as char **buf, you are using the wrong comparison function. As I noted in the comment, char buf[x][y] is an x array of character arrays of y chars, e.g. char (*)[y] when passed as a parameter. When you declare buf as char **buf;, you declare a pointer to a pointer to type char. In either case, you have a pointer to string, and you must dereference each value passed to qsort one additional level of indirection., e.g.

int cmpstrings (const void *a, const void *b) {
    return strcmp (*(char * const *)a, *(char * const *)b);
}

A short example using char **buf; would be:

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

/* qsort string comparison - for pointer to pointer to char */
int cmpstrings (const void *a, const void *b) {
    return strcmp (*(char * const *)a, *(char * const *)b);
}

int main (void) {

    char *ap[] = { "This is a tale",
                    "of captian Jack Sparrow",
                    "a pirate so brave",
                    "on the seven seas." },
        **buf = NULL;
    int n = sizeof ap/sizeof *ap;    

    if (!(buf = malloc (n * sizeof *buf))) { /* allocate pointers */
        fprintf (stderr, "error: virtual memory exhausted.\n");
        return 1;
    }

    for (int i = 0; i < n; i++)
        buf[i] = strdup (ap[i]);    /* allocate/copy strings */

    qsort (buf, n, sizeof *buf, cmpstrings);

    for (int i = 0; i < n; i++) {   /* print and free */
        printf ("buf[%d] : %s\n", i, buf[i]);
        free (buf[i]);
    }
    free (buf);

    return 0;
}

Example

$ ./bin/qsortptp
buf[0] : This is a tale
buf[1] : a pirate so brave
buf[2] : of captian Jack Sparrow
buf[3] : on the seven seas.
Comments