提问者:小点点

当数据被复制/扫描/读取到未初始化的指针时崩溃或“分段错误


此问题旨在作为以下性质的所有常见问题的参考:

为什么当我复制/扫描数据到一个未初始化的指针所指向的地址时,我会得到一个神秘的崩溃或“分段错误”?

例如:

char* ptr;
strcpy(ptr, "hello world"); // crash here!

char* ptr;
scanf("%s", ptr); // crash here!

共3个答案

匿名用户

指针是一种特殊类型的变量,它只能包含另一个变量的地址。 它不能包含任何数据。 您不能“将数据复制/存储到指针中”--这没有任何意义。 只能将指针设置为指向其他地方分配的数据。

这意味着为了使指针有意义,它必须始终指向有效的内存位置。 例如,它可以指向堆栈上分配的内存:

{
  int data = 0;
  int* ptr = &data;
  ...
}

或在堆上动态分配的内存:

int* ptr = malloc(sizeof(int));

在指针初始化之前使用它总是一个bug。 它还没有指向有效内存。

这些示例都可能导致程序崩溃或其他类型的意外行为,例如“分段错误”:

/*** examples of incorrect use of pointers ***/

// 1.
int* bad;
*bad = 42;

// 2.
char* bad;
strcpy(bad, "hello");

相反,您必须确保指针指向(足够的)分配内存:

/*** examples of correct use of pointers ***/

// 1.
int var;
int* good = &var;
*good = 42;

// 2.
char* good = malloc(5 + 1); // allocates memory for 5 characters *and*  the null terminator
strcpy(good, "hello");

请注意,您还可以将指针设置为指向定义良好的“nothere”,方法是让它指向null。 这使它成为一个空指针,这是一个保证不指向任何有效内存的指针。 这不同于让指针完全未初始化。

int* p1 = NULL; // pointer to nowhere
int* p2;        // uninitialized pointer, pointer to "anywhere", cannot be used yet

然而,如果您试图访问由空指针指向的内存,您可能会遇到与使用未初始化指针类似的问题:崩溃或分段错误。 在最好的情况下,您的系统注意到您正在尝试访问地址null,然后抛出“null指针异常”。

空指针异常错误的解决方案是相同的:您必须在使用指针之前将其设置为指向有效内存。

进一步阅读:

指向无效数据的指针
如何使用指针从其他函数访问局部变量?
局部变量的内存是否可以在其作用域之外访问?

分段错误和原因
什么是分段错误?
为什么写入以“char*s”而不是“chars[]”初始化的字符串时会出现分段错误?
chars[]和char*s之间有什么区别?
分段错误常见原因的明确列表
什么是总线错误?

匿名用户

>

  • 指针仅指向内存位置。 您创建了一个指针,但尚未绑定到内存位置。 strcpy希望您传递两个指针(第一个不能是常量),它们指向两个字符数组,如以下签名:

    char * strcpy ( char * destination, const char * source );
    
    char* ptr = malloc(32);  
    strcpy(ptr, "hello world");
    
    char str[32];  
    strcpy(str, "hello world");
    

    您可以尝试以下代码段读取字符串,直到到达换行符(*您还可以添加其他空格字符,如“%[^\t\n]s”(制表符,换行符)或“%[^\t\n]s”(空格,制表符,换行符))。

    char *ptr = malloc(32);
    scanf("%31[^\n]", ptr);
    

    (在实际生活中,不要忘记检查scanf()的返回值!)

  • 匿名用户

    学习C语言时经常出现的一种情况是尝试使用单引号表示字符串文字:

    char ptr[5];
    strcpy(ptr, 'hello'); // crash here!
    //            ^     ^   because of ' instead of "
    

    在C语言中,'h'是一个单字符文本,而“h”是一个字符串文本,包含一个'h'和一个空终止符\0(即一个2字符数组)。 另外,在C语言中,字符文本的类型是int,也就是说,sizeof('h')等价于sizeof(int),而sizeof(char)1

    char h = 'h';
    printf("Size: %zu\n", sizeof(h));     // Size: 1
    printf("Size: %zu\n", sizeof('h'));   // likely output: Size: 4