【问题标题】:qsort not sorting and strange outputqsort 不排序和奇怪的输出
【发布时间】:2011-09-01 10:40:49
【问题描述】:

所以我使用的是 C,我似乎无法让它正常工作。它是一个指向包含一些联系信息的结构的指针数组。我似乎无法让 qsort 正确排序。 这是我的代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 20
#define ELEMENTS 50

int sortZips(const void *a, const void *b);

typedef struct contactInfo {
char name[MAX];
char street[MAX];
char cityState[MAX];
char zipCode[MAX];
} contacts;


int main() {
int i = 0;
contacts **contactArray = malloc(ELEMENTS * sizeof(contacts *));     

/*  allocate array  */
for (i = 0; i < ELEMENTS; i++) {
    contactArray[i] = malloc(sizeof(contacts));
}
/*  populate array  */
for (i = 0; i < ELEMENTS; i++) {
    fgets(contactArray[i]->name,MAX,stdin);
    fgets(contactArray[i]->street,MAX,stdin);
    fgets(contactArray[i]->cityState,MAX,stdin);
    fgets(contactArray[i]->zipCode,MAX,stdin);

    printf("%s", contactArray[i]->name);
    printf("%s", contactArray[i]->street);
    printf("%s", contactArray[i]->cityState);
    printf("%s", contactArray[i]->zipCode);

}
printf("\n");


/*  qsort((void *)contactArray, ELEMENTS, sizeof(contacts *), sortZips);  */


for (i = 0; i < ELEMENTS; i++) {
    fputs(contactArray[i]->name,stdout);
    fputs(contactArray[i]->street,stdout);
    fputs(contactArray[i]->cityState,stdout);
    fputs(contactArray[i]->zipCode,stdout);
}


}


/*  sortZips() sort function for qsort  */

int sortZips(const void *a, const void *b) {

const contacts *ia = *(contacts **)a;
const contacts *ib = *(contacts **)b;
return strcmp(ia->zipCode, ib->zipCode);



}

输出是打印地址(我在输入文件中有 50 个),然后是一些随机字符,比如一大块它们,然后是排序列表,然后是混乱且排序不正确的列表。

如有任何帮助,我们将不胜感激。我需要了解这里出了什么问题以及为什么。 谢谢。

【问题讨论】:

    标签: c qsort


    【解决方案1】:

    第一条规则:始终检查输入函数 - 在这种情况下,fgets()。不检查就不知道一切是否正常。

    第二:一般使用enum,而不是#define

    通过检查早期 EOF,您的代码对我的示例数据(6 行)进行了干净的排序。它还可以干净地编译 - 这是非常不寻常的(这是一种恭维;我使用严格的警告,甚至我的代码也很少第一次编译干净)。我修改后的代码与您的非常相似:

    int main(void)
    {
        int i = 0;
        int num;
        contacts **contactArray = malloc(ELEMENTS * sizeof(contacts *));
    
        /*  allocate array  */
        for (i = 0; i < ELEMENTS; i++)
            contactArray[i] = malloc(sizeof(contacts));
    
        /*  populate array  */
        for (i = 0; i < ELEMENTS; i++)
        {
            if (fgets(contactArray[i]->name,MAX,stdin) == 0 ||
                fgets(contactArray[i]->street,MAX,stdin) == 0 ||
                fgets(contactArray[i]->cityState,MAX,stdin) == 0 ||
                fgets(contactArray[i]->zipCode,MAX,stdin) == 0)
                break;
            printf("%s", contactArray[i]->name);
            printf("%s", contactArray[i]->street);
            printf("%s", contactArray[i]->cityState);
            printf("%s", contactArray[i]->zipCode);
        }
        printf("\n");
        num = i;
    
        qsort(contactArray, num, sizeof(contacts *), sortZips);
    
        for (i = 0; i < num; i++)
        {
            fputs(contactArray[i]->name,stdout);
            fputs(contactArray[i]->street,stdout);
            fputs(contactArray[i]->cityState,stdout);
            fputs(contactArray[i]->zipCode,stdout);
        }
        return 0;
    }
    

    我使用的数据是 4 行的简单重复,如下所示:

    First LastName7
    7 Some Street
    City, CA
    95437
    

    请注意,我在输入中所做的“错误检查”是“有效”的最低要求。如果输入中出现过长的行,则一个字段将不包含换行符,而下一个字段将包含输入行的下一部分(可能是所有其余部分,也可能不是 - 这取决于该行的超长程度)。

    【讨论】:

    • 是的,我知道我应该专注于输入函数,看看混乱从哪里开始。我正在考虑排序以及我是否正确访问了结构的成员。这让我有点困惑。在此之前我从未使用过 qsort,我在理解将 void * 传递给排序函数的想法时遇到了一些麻烦。
    【解决方案2】:

    如果您的地址最后打印出垃圾,那几乎可以肯定是因为您没有为它们分配足够的空间。地址的 20 个字符有点偏低。

    可能发生的情况是您的地址如下:

    14237 Verylongstreetname Avenue
    

    而且,当您执行fgets (street,20,stdin); 时,只会读取14237 Verylongstree(19 个字符,为空终止符留出空间)。

    而且,关键在于:文件指针仍将指向tname Avenue 位,因此,当您尝试读取cityState 时,您会明白这一点。而且,当您尝试阅读 zipCode 时,您会看到 cityState 行,有效地填满您的排序。

    【讨论】:

    • 好的,谢谢您的回复,但是我没有意识到我的一件非常愚蠢的事情!它解决了这个问题,输入文件没有 50 个联系人输入值。有 18 个,将 'ELEMENTS' 设置为 18 可以解决问题,我还将 'MAX' 提高到 40,以防万一。所以我认为发生的事情是我为“contactArray”分配了 50 个元素并放入了 18 个数据元素,然后它只是在其余部分随机添加了垃圾并将其打印出来。
    【解决方案3】:

    我相信你有足够的空间。因为您使用的是 fgets 和您的 MAX 大小,所以字符串应该被剪裁以适合并在末尾有一个终止 NUL。

    两件事可能会搞砸:

    • 如果行太长,fgets 将从停止读取的位置开始读取。这将导致地址为“This is too long so”,“它将被剪切\n”。然后其余的输入将无处不在。
    • 如果您没有足够的输入来填充 ELEMENTS 项,那么您将获得 malloc 内存中的任何随机数据。如果您改用calloc,它会将您的内存归零。虽然更好的办法是使用计数器来计算实际读取了多少项目,而不是假设会有 ELEMENTS 项目。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-08-10
      • 1970-01-01
      • 1970-01-01
      • 2013-09-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-26
      相关资源
      最近更新 更多