【问题标题】:qsort() sorts one array of strings but segfaults on another oneqsort() 对一个字符串数组进行排序,但在另一个字符串上出现段错误
【发布时间】:2013-06-23 13:59:00
【问题描述】:

我正在尝试从 .txt 文件中读取一堆名称,并将它们复制到一个数组中。然后我想使用 qsort() 对数组进行排序。另外,我正在阅读的文件是来自Project Euler #22 的names.txt。代码如下:

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

/* create a pointer to point to s */
char *strdup(char *s)
{
    char *p;

    p = (char *) malloc(strlen(s)+1);
    if (p != NULL)
    strcpy(p, s);
    return p;
}

int compare(const void *a, const void *b)
{
    const char *ap = *(const char **) a;
    const char *bp = *(const char **) b;
    return strcmp(ap, bp);
}

int main(void)
{
    FILE *fp;
    int c, i, j=0;
    char name[100], *names[10000];

    fp = fopen("names.txt", "r");
    if (fp == NULL) {
    printf("can't open file\n");
    exit(0);
    }

    c = fgetc(fp); /* initialize c and skip first quotation mark */

    while (c != EOF) { /* loop until no names are left */
    i = 0;
    while ((c=fgetc(fp)) != '"') /* copy chars to name until " is reached */
        name[i++] = c;
    name[i] = '\0';
    names[j++] = strdup(name);
    fgetc(fp); /* skip comma */
    c = fgetc(fp);
    }

    size_t size  = sizeof(names[0]);
    size_t count = sizeof(names)/size;
    qsort((void **) names, count, size, &compare);

    return 0;

}

尝试对名称数组进行排序会导致段错误。但是,如果我尝试对明确声明的字符串数组进行排序,则它可以工作:

char *test[] = { "FOO", "BAR", "TEST" };

size_t size  = sizeof(test[0]);
size_t count = sizeof(test)/size;
qsort((void **) test, count, size, &compare);

for (i = 0; i < 3; ++i)
    printf("%s\n", test[i]);

return 0;

我怀疑段错误是由于我的数组“names”中的错误,但如果我在尝试排序之前循环并打印“names”的每个元素,这样做没有问题。

非常感谢任何帮助!

【问题讨论】:

    标签: c arrays string segmentation-fault qsort


    【解决方案1】:

    这一行:

    size_t count = sizeof(names)/size;
    

    将产生您的names 数组的整个 长度,而不仅仅是您初始化的值。如果您输入的名称少于 10000 个,那么您将有一些无效的指针,当您尝试对它们进行排序时 - KABOOM!

    您可以只使用j 而不是count,因为您使用它来跟踪输入了多少名称。

    【讨论】:

    • 用 j 替换 count 就像一个魅力!非常感谢!
    【解决方案2】:

    您缺少初始化names

    最简单的方法是这样的:

    names[10000] = {NULL};
    

    此外,比较函数不准备处理未使用的条目,您可以像这样修改它,将未使用的条目视为 emtpy 条目。

    int compare(const void *a, const void *b)
    {
      const char *ap = a ?*(const char **) a :"";
      const char *bp = b ?*(const char **) b :"";
    
      return strcmp(ap, bp);
    }
    

    或者,您可以将所有未使用的条目排序到最后:

    int compare(const void *a, const void *b)
    {
      if (*a && *b)
      {
        const char *ap = a ?*(const char **) a :"";
        const char *bp = b ?*(const char **) b :"";
    
        return strcmp(ap, bp);
      }
      else
      {
        if (*a)
          return -1;
        else (*b)
          return 1;
    
        return 0;
      }
    }
    

    您还告诉qsort() 始终检查names 的所有条目。这是不必要的。

    【讨论】:

    • 为什么要将未使用的条目排序到最后?他们已经结束了。既然如此,为什么还要初始化它们呢?
    • @CarlNorum:为了好玩……? S-) ... - 不,说真的:可能存在未按顺序分配的用例。
    猜你喜欢
    • 2013-03-23
    • 1970-01-01
    • 2021-03-27
    • 1970-01-01
    • 1970-01-01
    • 2019-08-07
    • 1970-01-01
    • 2013-01-02
    • 1970-01-01
    相关资源
    最近更新 更多