【问题标题】:Why does this program segfault为什么这个程序段错误
【发布时间】:2010-05-13 20:31:57
【问题描述】:

在编译并运行这个小程序以反转字符串时,在任何输出发生之前我都会遇到分段错误。如果这是一个明显的问题,请原谅我,我对 C 还是很陌生。

#include <stdio.h>

int reverse(char string[], int length); 

int main() {
char string[] = "reversed";

  printf("String at start of main = %s", string);
  reverse(string, sizeof(string));
  printf("%s\n", string);

return 0;

}

// Reverse string 
int reverse(char string[], int length) {
 int i;
 char reversed[] = {};
 int temp;

 for(i = 0; i < length; ++i) {
 temp = string[i];
 reversed[length - i] = temp;

 }
 return 0; 
}

【问题讨论】:

  • 代码不能编译为 C,因为空的 {} 是 C 中的语法错误。代码也不能编译为 C++,因为它试图创建一个大小为零的数组。这应该是什么语言?
  • @AndreyT - 应该是 C.
  • @Leda:如果这应该是 C,那么你需要让你的编译器遵循 C 语言的规则。 char reversed[] = {} 声明不能编译为 C 语言。需要编译器指出来。
  • @AndreyT。很明显,Leda 才刚刚开始学习 C。期望他/她了解 C/C++ 标准等之间的差异是不合理的。所以我想说“C”标签优先于代码中使用的任何 C++ 结构。编辑:我看到 Leda 回答了这个问题。
  • 我认为有足够多的“为什么会出现这个段错误”的问题来保证创建一个新站点。

标签: c string segmentation-fault reverse


【解决方案1】:

因为这个:

首先你创建一个零元素的数组:

char reversed[] = {};

稍后您尝试写入该数组超出其边界:

reversed[length - i] = temp;

更新:

上面的意思是你需要分配大小只有在运行时才知道的内存(它是length)。通常的 C 风格的做法是……将内存分配的负担推给调用者:

int reverse(const char* string, char* destination, int length);

此函数将写入调用者提供的缓冲区,现在调用者还必须确保:

  1. 缓冲区足够大
  2. 缓冲区的内存在应该被释放时被释放

【讨论】:

  • @Moron,我想你说我最初的帖子是错误的。在此期间对其进行了编辑。
  • 在 C 和 C++ 中都没有“零元素数组”之类的东西。此外,在 C 中没有 {} 这样的初始化程序。在 C 中,{} 之间总是需要至少一个表达式。
  • @AndreyT:你是对的。自从我上次使用 C 或在堆栈上分配一个数组以来已经有很多年了,所以我没有听懂。当说“零长度数组”时,我想到的是:char* buf = new char[length]; 即使length 为零,它也是合法的 C++。
【解决方案2】:

虽然它在这种情况下有效,但通常 sizeof(string) 应该是 `strlen(string)。通常,当使用 char 指针时,sizeof 运算符将只返回单个指针的大小 - 而不是整个数组。 . 在reverse()中,你的reverse数组没有分配,你可以这样分配:

char* reversed = (char*) malloc( length+1 );

我们将长度加一以说明字符串末尾的空字符。

【讨论】:

  • -1: sizeof(string) 不会返回指针的大小。它将以字节为单位返回数组的大小。试试看。
  • 没错。我更多地考虑一般情况。我已经更新了我的帖子以反映这一点。
【解决方案3】:

您的代码不能编译为 C。声明

char reversed[] = {};

无效。 C 语言中没有空的 {} 初始化器(它只存在于 C++ 中)。此外,空初始化器在未指定大小的数组声明中没有任何意义(这使得该代码也不能编译为 C++),因为在 C 和 C++ 中都没有零大小数组这样的东西。

要么发布真实代码,要么重新标记您的问题(如果这应该是 C++)。

【讨论】:

  • 但是在 gcc 中是允许的 -- gcc.gnu.org/onlinedocs/gcc/Zero-Length.html -- 并且甚至不使用-Wall 给出警告。
  • @Paul Stephenson:什么应该是警告,什么不应该是一个灰色区域,但即使-Wall 不会导致警告这一事实表明,默认情况下又多了一次行为 GCC 与真正的 C 关系非常松散。
【解决方案4】:

在 C 语言中,您必须仔细考虑变量和数组占用的内存。

当您编写char reversed[] = {} 时,您正在创建一个全新的零大小数组。 (这显然不是严格正确的 C,但它提问者的 gcc 编译器正在发生的事情。毕竟,报告是运行时的分段错误而不是编译时的语法错误。)

语句reversed[length - i] 然后尝试将数据写入您没有空间的数组元素,因为reversed 没有大小。

你有两个选择:

  • 创建一个大小合适的reversed 数组(也许像@Bob Kaufman 所说的那样使用malloc然后从reverse() 函数中返回它
  • 通过在string 自身内移动字符来“就地”反转字符串。

在适当的位置反转字符串可能更可取——如果您动态分配内存,那么您必须担心再次释放它,这可能会很痛苦。

【讨论】:

  • 不,您不会“创建全新的零大小数组”。在 C 中,{} 初始化程序始终是语法错误。除此之外,在 C 中始终禁止使用零大小的数组。
  • 提问者的代码使用 gcc 为我编译干净,打印 sizeof(reversed) 输出为零。这是 gcc 扩展吗?
猜你喜欢
  • 1970-01-01
  • 2011-12-07
  • 1970-01-01
  • 2019-04-17
  • 2021-09-22
  • 2014-03-31
  • 2020-10-16
  • 1970-01-01
相关资源
最近更新 更多