Chinaunix首页 | 论坛 | 博客

  • 博客访问: 473803
  • 博文数量: 86
  • 博客积分: 2010
  • 博客等级: 大尉
  • 技术积分: 878
  • 用 户 组: 普通用户
  • 注册时间: 2008-11-06 14:11
文章分类

全部博文(86)

文章存档

2010年(12)

2009年(60)

2008年(14)

我的朋友

分类: LINUX

2009-04-29 13:44:27

转发自网上一段讨论

==================================

现有一程序如下:

main()

{

char *p="Hello";

strcat(p,"World");

printf("p is %s.\n",p);

}

运行结果为segmentation fault

如果改成char p[]="Hello";就正确运行.

我不理解的是,为什么必须p在栈里就正确,在堆里就错误呢?

而且segmentation fault又如何解释呢?

=================================

真搞不懂,指针有这么难学么?心血来潮,写点心得在下面。有兴趣的请指教。

不管是

char *p="Hello";

还是

char p[]="Hello";

都是错误的

 

这两种情况p都只向一块6字节大小的空间,使用这6字节之后的空间就会引起错误,因为也许它们是某个变量的空间。为了防止对内存地址非法操作,就有了段保护的机制。不可能让你修改内存中任意地址的内容。

 

比如说这段代码:

 

#include

 

int main()

{

char p[] = "Hello";

p[5] = '!';

p[6] = '\0';

printf("%s\n", p);

}

 

似乎不会出错,虽然p[6]好像超出了6个字符的限制。

但是如果把p[6]改成p[3000]又如何呢?你可以试一下,100%出错。p[]定义在栈里,运行时根据需要,栈会初始化一个大小,如果试图修改栈以外的地址,就出错。

经常看到有人报错说加一行printf程序就能正常运行,不加这一行就会segmentation falt,其实跟上面的程序一样,程序隐含了致命的问题,只不过因为 printf 改变了堆栈的布局,遮盖了你的程序的漏洞。再试一下在上面程序中char p[] = "Hello"前面加上一行char c[3000],那么p[3000]也不会造成错误,因为c[3000]这个变量的定义相当于让栈扩大了。

 

再看一个直观的例子:

#include

 

int main(int argc, char* argv[])

{

char p[] = "Hello";

char i = 1;

p[5] = '!';

for(i = 6; i < 100; i++)

p[i] = 0;

printf("%s, argc=%d\n", p, argc);

}

结果是造成core dump,并且argc的值被改成0

进一步看看

printf("%d, argc=%d\n", *(int*)(p+32), argc);

的输出结果,可以看到p[32]的值和argc是一样的,它们在栈里的地址是一样的。现在你应该相信非法指针操作可能带来的危害了吧?

 

顺便说一句,对于初学者的问题,不要什么都指到c99,那个东西我没看过,我想看过的人也不多。其实弄一本经典的书好好学一下,再多练习练习,我想就差不多了。

 

mikewang

(enthusiast)

03-05-26 16:34

  Re: 关于segmentation fault 

我的看法和你不一样

1, 什么堆呀,栈呀 都是编译器的问题, 不是你考虑的东西

2, C写程序,就要安装C的规范写, 不要考虑汇编

3, 入门的教材还是要的, 不过C99是比读的, 除非你不用C写程序

x86

(member)

03-05-26 16:52

   Re: 关于segmentation fault 

 

>1, 什么堆呀,栈呀 都是编译器的问题, 不是你考虑的东西

>2, C写程序,就要安装C的规范写, 不要考虑汇编

当然,这两点我同意。讲一下堆栈,指针的问题就更好理解一些。

 

>3, 入门的教材还是要的, 不过C99是比读的, 除非你不用C写程序

也许是我懒,每回看到c99都没法读下去,我觉得并非所有细节都需了解,就好像一个HTML高手也未必完全了解HTML规范,java想必也有标准,看的人就更少了。C/C++语言有很多经典教材,其中很多并非只用于入门。

 

teawater

(old hand)

03-05-26 17:48

   Re: 关于segmentation fault 

char p[]="Hello";有什么错?

我认为其是相当于

char p[6]="Hello";

本身是没问题的

只要你不访问超出其范围的地址就不会有问题

指针只是个概念问题,严格按照规范做就不会出问题。

过渡强调编译器相关的问题只能让问题复杂化

 

x86

(member)

03-05-27 09:35

   Re: 关于segmentation fault 

 

呵呵,老兄又误会我的意思了。

 

coolq说为什么char* pchar p[]的表现不一样,char p[]不会引起core dump,而char* p会,我的意思是不管定义成哪一个,代码都有问题。并非说char p[]="Hello"有问题。

 

有一点可能我没说清楚,char* pchar p[]并非与堆栈有关,而是因为char* p="Hello"const,而char p[]不是。所以char* p的错误是语法问题,而char p[]的错误是指针越界。

 

本来是回的coolq的帖子,写了一大段才发现你已经回的差不多了,所以另开一个帖子,只是舍不得写的一大段文字罢了。

 

teawater

(old hand)

03-05-27 10:43

   Re: 关于segmentation fault 

 

其实你写的挺好的 为原创鼓掌  

jfwan

(addict)

03-05-27 10:55

   Re: 关于segmentation fault 

 

hehe, I also think so!

x86

(member)

03-05-27 11:07

   Re: 关于segmentation fault 

Thanks.

f1122

(stranger)

05-01-07 15:10

  Re: 关于segmentation fault 

 char *p="hello";

"hello"不是const

请看规范

 

vrbear

(stranger)

05-01-07 15:24

  Re: 关于segmentation fault 

 char *p="hello";

把看成const属于设计概念错误。

char *p = “Hello”; // non-constant pointer,non-constant data

const char *p = “Hello”; // non-constant pointer,constant data

char * const p = “Hello”; // constant pointer, non-const data

const char * const p = Hello; // constant pointerconstant data

 

不过VC是把"hello"看成常量放在静态存储区的,这可能是出于优化的目的。

 

gooderfeng

(stranger)

05-05-27 12:37

  Re: 关于segmentation fault 

 

想想看

char [] 是在堆栈里面保存的

char*这个指针也是在静态区里面保存的。

而指针指的串还是在堆栈区的。

我是看不出来他们本质上有什么区别。

 

caty

(newbie)

05-05-27 14:01

  Re: 关于segmentation fault 

看一下汇编代码,

gcc "Hello" 放到只读数据区,

.section .rodata

只要改成 .section .data

程序就可以跑了。

当然用strcat你把别人的空间给覆盖了,这是另外一个问题。

阅读(4905) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~