在运行以下代码时,我的程序意外崩溃!
#include<stdio.h>
#include<string.h>
int main(){
char *str = NULL;
strcpy(str, "swami");
printf("%s", str);
return 0;
}
但如果我喜欢这样:
#include<stdio.h>
#include<string.h>
int main(){
char *str;
strcpy(str, "swami");
printf("%s", str);
return 0;
}
此代码工作正常并生成正确的输出!
我正在使用gcc编译器(codeblocks IDE)。此外,这两个代码都会导致DevCpp中的程序崩溃。任何人都可以解释一下为什么会这样!?
答案 0 :(得分:23)
您无法写入NULL
指针。
在第二种情况下,您的指针被随机初始化为程序内存中的有效位置。这就是为什么你可以strcpy
进入它。
将两个程序更改为
str = malloc(size)
或calloc
之前的strcpy
选项。 (size
是您要保留的空间大小。)
根据评论,您还可以将str
的声明更改为char str[6]
(或更多)。
上次编辑:我将向您展示显示程序内存和指针的图片:
灰色区域和红色区域是禁止的(您不能写入或读取它们;顶部灰色区域用于内核内存,而其他区域是尚未回收的空间)。底部的红色区域是特殊的0页面。由于NULL
为0
,您的str = NULL
会指向此,并且您的计划将失败。
如果您没有为str
分配任何内容,它将最终随机指向。它仍然可以指向红色区域或灰色区域 - &gt;你的程序将失败。它可以指向绿色或蓝色(两个色调)区域,使您的程序工作(除了它指向只读位置并且您写入它的情况)。指针的分配区域使其指向绿色区域,将其放大到顶部。
另一个选项,str[6]
将堆栈区域放大到底部。所有局部变量都有空间保留到堆栈中,而分配有malloc
,realloc
,calloc
和其他朋友的所有空间都会进入堆中。
最后,请查看有关char[]
和char *
之间差异的blog article。
PS:如果你想使用GNU扩展,你可以查看asprintf
函数。它会为字符串分配空间并在那里写一些内容:
asprintf(&str, "swami");
或
asprintf(&str, "%d + %d == %d\n", 1, 2, 3);
但是,如果你想要便携性,那就远离这个功能。
答案 1 :(得分:4)
在两个版本中都没有分配内存来复制字符串,因此两者都调用未定义的行为。第一个崩溃是因为您明确地将str
初始化为NULL
,因此strcpy
取消引用NULL
指针,该指针在大多数系统上崩溃。在第二个中,str
指向任意内存,取消引用未初始化的指针可能会或可能不会崩溃。
答案 2 :(得分:2)
NULL
中的#define NULL ((void *)0)
为<stdlib.h>
。因此,您尝试写入无效的内存地址,导致程序崩溃。
答案 3 :(得分:1)
阅读此link
//destination =Pointer to the destination array where the content is to be copied.
char * strcpy ( char * destination, const char * source );
您将目标设置为NULL,因此您尝试将源复制为NULL。这就是崩溃的原因。你应该设置一些内存协助来复制字符串。
int main(){
char *str=malloc(6); //enough for "swami"+'\0'
strcpy(str, "swami");
printf("%s", str);
return 0;
}
答案 4 :(得分:1)
strcpy
只是复制,而不是为它创造空间。
在第一种情况下,您尝试将字符串写入代码段的开头:不是一个好主意。
在第二种情况下,你开始将字符串写入某个地方,并且在你的情况下没有崩溃做运气和编译器帮助。
您应该执行以下操作之一:
一个。分配记忆:str = new char[10]
湾使用strdup
将字符串复制到一个新位置。