【问题标题】:Output sorted in a weird way输出以一种奇怪的方式排序
【发布时间】:2013-09-29 20:27:24
【问题描述】:

我写了下面的代码,但从输出中可以看出有问题。 我可能犯了一个指针错误。你能帮忙吗?

未排序的名称:

纽约 乔治亚州 波士顿

排序后的名称:

博斯托克 乔治亚州 纽永

#include <stdio.h>
#include <stdlib.h>   
#include <string.h>
#define SIZE 3

void sort(char x[3][100]);
void swap(char **, char **);

int i,j;
char names[SIZE][100];
char *temp;

int main(void){

//get the names of the cities
puts("Enter names of cities");
for (i = 0; i < SIZE; i++)
{       
    fgets( names[i], 99, stdin );
}
//print entered names
puts("\nUnsorted Names:\n");
for (i = 0; i < SIZE; i++)
{
    printf("%s", names[i]);
}

sort(names);

//print sorted names
puts("\nSorted Names:\n");
for (i = 0; i < SIZE; i++)
{
    printf("%s", names[i]);
}

getch();
 }

//sorting function
void sort(char angut[3][100]){

for (i = 0; i < SIZE-1; i++)
{
    for (j = i+1; j < SIZE; j++)
    {
        if (strcmp( angut[i], angut[j] ) >0)
        {
            swap(&angut[i],&angut[j]);
        }

    }

}

}

  //swapping function
  void swap(char **first, char **second){

temp=*second;
*second=*first;
*first=temp;

}

【问题讨论】:

  • 我需要波士顿乔治亚纽约作为输出。
  • 你是在开玩笑还是什么?不好笑

标签: c sorting


【解决方案1】:

您处于未定义行为的领域。让我们用真正的编译器编译你的代码,比如 gcc。这是(相关的)输出:

a.c: In function 'sort':
a.c:50:13: warning: passing argument 1 of 'swap' from incompatible pointer type [enabled by default]
a.c:8:6: note: expected 'char **' but argument is of type 'char (*)[100]'
a.c:50:13: warning: passing argument 2 of 'swap' from incompatible pointer type [enabled by default]
a.c:8:6: note: expected 'char **' but argument is of type 'char (*)[100]'

如您所见,您向swap 提供了错误的论据。为什么这是一个糟糕的论点?原因如下:

angut 是一个二维数组,实际上它只是一个按行划分的单个数组。 angut[i] 是该数组的一行。请注意,这不是一个指针,它实际上是该数组的整行,类型为char [100]。 (旁注:如果你将它传递给一个函数,它衰减为一个指针)。现在您正在获取它的地址,即该数组中一行的地址,其类型为char (*)[100]。

现在这是您尝试传递给swap 的指针。但是等等,这不是指向指针(指向 char)的指针,而是指向数组行的指针。这就是不兼容的来源,这就是您得到错误结果的原因。


这应该足以解决您的问题,但这是下面发生的事情,因此会产生奇怪的结果。我们来看一个char **:

+----------+        +----------+        +----------+
| char **a |  ----> |  char *b |  ----> |  char c  |
+----------+        +----------+        +----------+

通过更改*a,您正在更改b。现在让我们看看您实际发送到该函数的内容:

+----------------+        +--------------+
| char (*a)[100] |  ----> |  char b[100] |
+----------------+        +--------------+

所以现在更改 *a 实际上会更改 b,这是您的数据,而不是指向您的数据的指针。 swap 函数不知道这一点,因此它认为 a 是 char **。那么swap 认为*a 的意思是指向某个字符串的指针,对吧?你实际上给它的是字符串本身。

因此,当您执行*a1 = *a2; 时,编译器从a2 指向的位置(在您的体系结构中)获取4 个字节,并将其写入a1 指向的4 个字节。

你知道发生了什么吗?基本上,你的字符串的前四个字节被交换,作为指针。这就是为什么您会看到 Bostork 和 Newyon 前四个字符被交换的原因。

【讨论】:

    【解决方案2】:

    尝试在您的交换函数中使用实际的字符串副本,虽然效率低下,但有效(而不是指针分配)。

     void swap(char **first, char **second){
    
        char temp[100];
        strcpy(temp, *second);
        strcpy(*second, *first);
        strcpy(*first, temp);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-01-17
      • 2017-12-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多