我试图每次用新的一个值更新的数组(城市)都“重新排序”并显示表的当前状态。
当我将函数排序放入for循环中时,排序无法正常工作,仅替换值即可。例如,首先,如果我给“ aba”,则打印“ aba”,其次,如果我给“ bad”,则打印“ aba,坏”,其次,如果我给“ dad”,则打印“ aba,dad”。排序将替换为最后一个值。 自相矛盾的是,在for循环之外它可以正常工作。任何建议将不胜感激。
>>> id(300)
140059023515344
>>> id(302 - 2)
140059037091600
>>> id(300) is id(302 - 2)
False
>>> 300 is 302 - 2
True
>>> id(300) == id(302 -2)
True
>>> id(302 - 2)
140059037090320
>>> id(302 - 2)
140059023514640
答案 0 :(得分:2)
cities[i]=(char*)calloc(3,sizeof(char));
城市名称中的空结尾字符只能再包含2个字符,在行为未定义后,您可能希望使用更长的名称
但在
scanf("%s",cities[i]);
可能您输入的字符超过2个...
您在调用 sort 时未指明输入了多少个引用,因此 sort 可以在3个城市使用,即使只有2个输入,也可以在初始化之前访问第三个字符串,当 strcmp 访问它时具有未定义的行为
在
temp = (char*)calloc(30, sizeof(char));
由于未释放 temp ,
而创建了内存泄漏没有理由在堆中分配要交换的内容:交换指针而不是内容
您也不会在主域名结尾处释放城市名称
您的代码中的提案,可以管理任意数量的城市,输入以EOF(control-d)结尾,城市名称限制为30个字符(请查看 scanf 中的保护)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void sort(char** cities, int n)
{
int i, j;
// Perform sort operation using bubble sort
for (i = 0; i < n - 1; i++) {
for (j = 0; j < n - i - 1; j++) {
if (strcmp(cities[j], cities[j + 1]) > 0) {
char* temp = cities[j];
cities[j] = cities[j + 1];
cities[j + 1] = temp;
}
}
}
}
int main() {
char ** cities = malloc(0);
char name[31];
int n = 0, i;
while (printf("Give City %d:\n", n), (scanf("%30s", name) == 1))
{
cities = realloc(cities, (++n) * sizeof(char *));
cities[n - 1] = strdup(name);
if (n == 1)
printf("%s\n",cities[0]); //1st case of nothing to compare
else {
sort(cities, n);
printf("\nArray after sorting %d time:\n", n);
for (i = 0; i < n; i++)
printf("%s\n", cities[i]); //print current array of cites sorted
}
}
for (i = 0; i < n; i++)
free(cities[i]);
free(cities);
return (EXIT_SUCCESS);
}
编译和执行:
pi@raspberrypi:/tmp $ gcc -pedantic -Wextra -Wall c.c
pi@raspberrypi:/tmp $ ./a.out
Give City 0:
qsd
qsd
Give City 1:
aze
Array after sorting 2 time:
aze
qsd
Give City 2:
wxc
Array after sorting 3 time:
aze
qsd
wxc
Give City 3:
<control-d>
在 valgrind 下执行:
pi@raspberrypi:/tmp $ valgrind ./a.out
==23191== Memcheck, a memory error detector
==23191== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==23191== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==23191== Command: ./a.out
==23191==
Give City 0:
qsdqsdqsd
qsdqsdqsd
Give City 1:
aze
Array after sorting 2 time:
aze
qsdqsdqsd
Give City 2:
wxcwxcwxcwxcwxc
Array after sorting 3 time:
aze
qsdqsdqsd
wxcwxcwxcwxcwxc
Give City 3:
<control-d>
==23191==
==23191== HEAP SUMMARY:
==23191== in use at exit: 0 bytes in 0 blocks
==23191== total heap usage: 9 allocs, 9 frees, 2,102 bytes allocated
==23191==
==23191== All heap blocks were freed -- no leaks are possible
==23191==
==23191== For counts of detected and suppressed errors, rerun with: -v
==23191== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 3)
答案 1 :(得分:2)
虽然@bruno是正确的,因为您为城市名称分配的内存不足,但解决此问题可能不会解决该问题,因为您有一个更深层次的算法问题。
您的排序函数本身看起来正确(-ish),用于对正好三个元素的数组进行排序。它确实会泄漏内存,并且仅在指针之间进行交换比复制字符串内容会更好,但是它应该成功地将元素按字典顺序递增。但是,正如我在评论中观察到的那样,不仅在读取所有城市数据之后,而且在仅读取前两个数据之后,您才调用它。考虑一下会发生什么。
答案:由于要通过calloc()
分配字符串数据,因此内容将初始化为全零。特别地,那么,最初,每个字符串中索引为零的字节为0,因此该字符串将被解释为空字符串。 当您仅填充了两个数组元素后进行排序时,位于第三个位置的空字符串将排序到数组的开头。 然后阅读第三个城市名称时,您将覆盖已排序到第三位的任何字符串。然后,当您在末尾打印城市时,您会忽略这样一个事实,即在城市列表的开头有一个额外的空白行,在该行中打印了您排在最前面的空字符串。
最好是等待排序,直到所有数据都输入为止。鉴于您要一次读取所有数据,因此在中间阶段进行排序几乎没有什么好处。但是,如果必须在仅输入了某些元素之后进行排序,那么必须确保仅对到目前为止已读取的元素进行排序。