此代码生成“p = hello world”:
#include "stdio.h"
#include "string.h"
int main(){
char *p;
p="hello world";
printf("p is %s \n",p);
return 0;
}
但是这段代码产生了一个分段错误:
#include "stdio.h"
#include "string.h"
int main() {
char *p;
strcpy(p,"hello");
printf("p is %s \n",p);
return 0;
}
并且此代码生成“p = hello”
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
int main() {
char *p;
p=(char*)malloc (10);
strcpy(p,"hello");
printf("p is %s \n",p);
return 0;
}
答案 0 :(得分:12)
在p="hello world";
(此编辑时的第一种情况)的情况下,p
正在初始化为指向只读内存区域,其中包含字符串“hello world”(字符串文字)。此只读内存区域是在编译时创建的。
在导致分段错误的情况下(此编辑时的第二种情况),p
未初始化并且向其复制任何内容将产生不可预测的结果,因为内存中的位置p
是指向的未指定代码。
在将字符串复制到p
之前,必须指定p
指向的内存。
您可以在堆栈上分配此内存
char buf[BUFSIZ] = ""; /* local variable */
在堆上
char *buf = malloc(BUFSIZ); /* don't forget to free */
或__DATA段。
static char buf[BUFSIZ] = ""; /* global variable */
然后,您可以初始化p
以指向内存缓冲区。
char *p = buf;
这在概念上类似于初始化p
以指向只读内存中的字符串文字。与p
指向字符串文字的情况不同,您现在可以将字符串复制到字符指针,因为它不指向只读内存。
注意:我故意创建了一个单独的缓冲区并初始化p
以指向它以帮助说明我的观点。
答案 1 :(得分:5)
原因是当你声明一个指针时,它实际上并没有指向任何有用的东西。 strcpy
需要一块内存才能将字符串复制到其中。它不会自动为您执行此操作。
从文档(强调我的):
复制源指向的C字符串 进入目的地指向的数组, 包括终止null 字符。
为了避免溢出,的大小 目的地指向的数组应为 足够长,以包含相同的C. 字符串作为源(包括 终止空字符),和 不应该在内存中重叠 源。
你需要这样做,因为这是函数的前提条件。
另外,在参数部分:
目的地
Pointer to the destination array where the content is to be copied.
您需要确保destination
是指向数组的指针。
答案 2 :(得分:2)
没有免费的午餐 - 你需要抓住&管理记忆。如果你只是假设因为你有访问指针的内存应该存在,那么你将遇到未指定的行为(可能是段错误)。
答案 3 :(得分:2)
因为在第一个例子中,指针p
包含当时恰好在堆栈上的一些随机垃圾,可能是零,可能是其他任何东西,所以它指向......没人知道在哪里,例如,您的代码段。操作系统做正确的事情并告诉您,您违反规则并尝试写入不属于您的内存。阅读the fine description of segmentation faults here。
如果你绝对想要避免动态内存分配和你知道源代码串在编译时的大小,你可以抓住适当的堆栈空间,如下所示:
char buffer[6]; /* strlen( "hello" ) + 1 for zero terminator */
strcpy( buffer, "hello" );
但这是通往buffer overruns的危险道路。
答案 4 :(得分:2)
请注意两个工作示例的共同点:它们有p =
行,可以为p
指定一些内容。非工作示例不会这样做。
考虑这一行(来自第一个例子):
p = "hello world";
虽然它可能看起来像是“将字符串复制到字符指针”,但事实并非如此。它正在将字符串的位置复制到指向char的指针。这就像p
之类的指针一样存储 - char
s的连续块的位置。
同样,请考虑第三个例子中的这一行:
p = malloc(10);
这也是复制一个位置 - 它正在将10个未初始化的char
块的位置复制到p
。
strcpy(dest, source)
将source
指定位置的字符复制到dest
指定的位置。应该清楚的是,如果您从未将p
设置为有效位置,那么strcpy(p, "hello")
无法做任何明智的事情 - 在您的第二个示例中,p
是一个基本上随机的位置,而您然后让strcpy()
将某些内容复制到该位置。
答案 5 :(得分:1)
内存复制有两个不同的部分。第一个是您要复制的项目所占用的内存(使用malloc()函数在您的示例中创建),第二个是指向该内存块的指针(您将其称为p)。在进行复制之前,还必须为目标设置这两个实体。在第一个失败的示例中,您有不为目标设置内存块(但是当您声明字符串hello
时,它已隐式设置为源。)
答案 6 :(得分:1)
是的,这很烦人。您可以使用strdup
缩短它:
char *p = strdup("hello");
printf("p is %s \n",p);