#include<stdio.h>
int main(void)
{
char * p= "strings are good";
printf("%s",*p);
return 0;
}
有人可以告诉我为什么我在这里遇到分段错误吗?
答案 0 :(得分:8)
有人可以告诉我为什么我在这里得到分段错误?
如果转换规范无效,则行为未定义.282)如果任何参数不是相应转换规范的正确类型,则行为为 未定义。
1 未定义的行为 在使用不可移植或错误的程序结构或错误数据时, 本国际标准没有要求。
2 注意可能的未定义行为范围从完全忽略不完全结果的情况到在翻译或程序执行期间以环境特征的文档化方式行事(有或没有发出诊断消息) ),终止翻译或执行(发布诊断消息)。
*p
的类型为char
。 %s
期望char *
类型的参数。这将调用未定义的行为。在这种情况下,一切都可能发生有时你可能得到预期的结果,有时候不会。这也可能导致程序崩溃或分段错误(这种情况就是这种情况)。
对于%s
,您需要传递sting / literal的起始地址。
更改
printf("%s",*p);
到
printf("%s",p);
答案 1 :(得分:3)
问题在于:
printf("%s",*p);
printf
将解析const char *
格式字符串,在您的情况下:"%s"
,并推断除格式之外的第一个参数也将是char *
。
现在,因为您取消引用指针,您传递的是一个字符{char
,而没有*
)
现在,如果将char的 size 与char 指针的大小进行比较:
printf("%d vs %d\n", sizeof(p), sizeof(*p));
你会看到一个char指针是4(或64位为8)乘以char的大小
考虑一下你实际做了什么,迫使printf
将char的值强制转换为指针,然后使用该指针读取字符串:
const char *p = "foobar";
printf("%p\nWhereas you wanted: %p\n", (void *) *p, (void *) p);
输出:
0x66 //not a valid pointer, too small
Whereas you wanted: 0x80485c8 //<-- actual address may vary
解决方案:
printf("%s\n", p);
不要取消引用指针,只是按原样传递它
只是一个小技巧:学会喜欢存储类修饰符const
。在这种情况下,这是一个有用的提醒:
char *p;
//some code
p = "a string";
//more code, or passing p to a function that attempts to do:
p[0] = 'A';//ERROR!!
鉴于:
const char *p;//I can SEE p points to a constant
p = "a string";
p[0] = 'A';//error, the declaration of p tells me why
const
是一个视觉提示,无论您要对p
做什么,都应该记住它指向常量,并且值无法编辑。
答案 2 :(得分:1)
您在printf格式的输出中传递单个字符串作为字符串类型(%s)。 将其更改为p