关于C中的qsort(),** buf和buf [] []之间的区别

时间:2016-09-07 02:29:17

标签: c linux qsort

当我在Mac上的C中使用qsort()时,这些代码运行良好,它可以很好地对一个文件中的每一行进行排序。

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);
    }

然而,当我使用malloc分配空间时,它很糟糕。这是为什么? 下面的代码显示我使用malloc来制作一个二维数组。我打印之前和之后的buf内容。似乎丢失了所有信息。

    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]);
    }

输出:

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)

最重要的是,如何修复我的malloc版本?

2 个答案:

答案 0 :(得分:1)

当您尝试qsort buf声明为char **buf时,您使用了错误的比较功能。正如我在评论中指出的那样,char buf[x][y]是{em> x y字符字符数组的数组,例如作为参数传递时char (*)[y]。将buf声明为char **buf;时,声明指向类型为char 的指针的指针。在任何一种情况下,你都有一个指向字符串的指针,你必须取消引用传递给qsort一个额外级别的间接的每个值。例如。

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

使用char **buf;的简短示例是:

#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;
}

示例

$ ./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.

答案 1 :(得分:1)

qsortmemcpy和类似函数假定指针在数组处传递点。数组的定义是在相邻的存储单元中连续分配的x个项。例如char array [x][y];

关于使用指针到指针的广泛混淆。你可以使用一个老技巧来声明一个查找表,其中每个项指向一个可变长度的数组,如下所示:

char** ptr = malloc(x * sizeof(char*));
for(int i=0; i<x; i++)
{
  ptr[i] = malloc(y * sizeof(char));
}

这允许您使用类似于数组的语法ptr[i][j]来访问查找表。但意味着这是一个数组,指针指针和2D数组之间没有任何关系!这相当于x个段,其中每个段在堆上的任何位置分配。

如果你不需要它,那么上面的方法很简单并且总是不正确的 - 它在分配开销,堆碎片和糟糕的数据缓存使用方面都比实际数组慢得多。正如你所发现的那样,它甚至不能用作数组...因为它不是一个。

现在不幸的是,世界各地都有许多不称职的大师错误地将上述内容作为动态分配多维数组的方法。这完全是胡说八道。它不是一个多维数组,不能用作一个数组。 See this解释你实际上应该如何动态分配多维数组。