7

所以我有一些C代码:

#include <stdio.h>
#include <string.h>

/* putting one of the "char*"s here causes a segfault */
void main() {
  char* path = "/temp";
  char* temp;
  strcpy(temp, path);
}

这会编译、运行并按其外观运行。但是,如果将一个或两个字符指针声明为全局变量,则 strcpy 会导致分段错误。为什么会这样?显然我对范围的理解存在错误。

4

8 回答 8

16

正如其他海报所提到的,问题的根源在于 temp 未初始化。当声明为堆栈上的自动变量时,它将包含该内存位置中发生的任何垃圾。显然,对于您正在运行的编译器+CPU+OS,该位置的垃圾是一个有效的指针。strcpy “成功”在于它没有段错误,但实际上它将字符串复制到内存中其他位置的任意位置。这种内存损坏问题让世界各地的 C 程序员感到恐惧,因为它非常难以调试。

当您将临时变量声明移动到全局范围时,它被放置在 BSS 部分并自动归零。尝试取消引用 *temp 然后会导致段错误。

当您将 *path 移动到全局范围时, *temp 会在堆栈上向上移动一个位置。该位置的垃圾显然不是有效的指针,因此取消引用 *temp 会导致段错误。

于 2008-09-23T18:43:36.600 回答
9

temp 变量不指向任何存储(内存)并且未初始化。

如果 temp 声明为,char temp[32];则无论在何处声明代码都将起作用。但是,用这样的固定大小声明 temp 还有其他问题,但这是另一天的问题。

现在,为什么它在全局而不是本地声明时会崩溃。运气...

当在本地声明时, temp 的值来自当时可能在堆栈上的任何值。幸运的是它指向了一个不会导致崩溃的地址。但是,它正在破坏其他人使用的内存。

当全局声明时,在大多数处理器上,这些变量将存储在将使用需求零页的数据段中。因此char *temp看起来好像它被宣布了char *temp=0

于 2008-09-23T18:39:46.143 回答
8

您忘记分配和初始化 temp:

temp = (char *)malloc(TEMP_SIZE);

只要确保 TEMP_SIZE 足够大。你也可以在运行时计算这个,然后确保大小足够(至少应该是 strlen(path))

于 2008-09-23T18:36:27.150 回答
3

如上所述,您忘记为 temp 分配空间。我更strdup喜欢malloc+strcpy. 它做你想做的事。

于 2008-09-23T18:43:09.613 回答
2

不 - 无论变量如何,这都不起作用 - 它看起来就像它那样,因为你(不)幸运。您需要分配空间来存储字符串的内容,而不是让变量未初始化。

堆栈上未初始化的变量将指向几乎随机的内存位置。如果这些地址碰巧是有效的,那么您的代码将践踏那里的所有内容,但您不会收到错误消息(但可能会在代码的其他地方出现与内存损坏相关的令人讨厌的错误)。

全局变量总是失败,因为它们通常被设置为指向未映射内存的特定模式。尝试取消引用这些会立即给您一个段错误(这更好 - 将其留到以后会使错误很难追踪)。

于 2008-09-23T18:43:29.143 回答
2

我想将第一个亚当的片段重写为

// Make temp a static array of 256 chars
char temp[256];
strncpy(temp, sizeof(temp), path);
temp[sizeof(temp)-1] = '\0';

这样你:

1. don't have magic numbers laced through the code, and
2. you guarantee that your string is null terminated.

第二点是丢失源字符串的最后一个字符,如果它的长度 >=256 个字符。

于 2008-09-23T18:57:04.337 回答
1

需要注意的重要部分:
目标字符串 dest 必须足够大以接收副本。
在您的情况下, temp 没有分配要复制到的内存。

从 strcpy 的手册页复制:

DESCRIPTION
   The  strcpy()  function  copies the string pointed to by src (including
   the terminating '\0' character) to the array pointed to by  dest.   The
   strings  may not overlap, and the destination string dest must be large
   enough to receive the copy.
于 2008-09-23T18:39:09.747 回答
1

您正在调用未定义的行为,因为您没有初始化temp变量。它指向内存中的一个随机位置,因此您的程序可能会工作,但很可能会出现段错误。你需要让你的目标字符串是一个数组,或者让它指向动态内存:

// Make temp a static array of 256 chars
char temp[256];
strncpy(temp, 256, path);

// Or, use dynamic memory
char *temp = (char *)malloc(256);
strncpy(temp, 256, path);

此外,使用strncpy()而不是strcpy()避免缓冲区溢出。

于 2008-09-23T18:39:53.647 回答