排序功能在循环内无法正常工作

时间:2019-04-02 21:36:00

标签: c sorting

我试图每次用新的一个值更新的数组(城市)都“重新排序”并显示表的当前状态。

当我将函数排序放入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

2 个答案:

答案 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,因此该字符串将被解释为空字符串。 当您仅填充了两个数组元素后进行排序时,位于第三个位置的空字符串将排序到数组的开头。 然后阅读第三个城市名称时,您将覆盖已排序到第三位的任何字符串。然后,当您在末尾打印城市时,您会忽略这样一个事实,即在城市列表的开头有一个额外的空白行,在该行中打印了您排在最前面的空字符串。

最好是等待排序,直到所有数据都输入为止。鉴于您要一次读取所有数据,因此在中间阶段进行排序几乎没有什么好处。但是,如果必须在仅输入了某些元素之后进行排序,那么必须确保仅对到目前为止已读取的元素进行排序。