C/C++语言如此的强大,让人爱不释手,但晦涩的语法和诸多的编程陷阱让人头皮发麻。
我们通常遇到的最多的错误莫过于段错误,下面是一个经典的段错误,你没遇到过?亲,那不可能~
好吧,一般这样的错误大都由指针引起,看看我们的代码都写了些什么:
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
void func1(char ** dest,char * src,int n) {
(*dest) = (char*)malloc(sizeof(char)*n);
strcpy(*dest,src);
}
int main(int argc,char** args) {
char ** p = NULL;
char str[] = "foreach_break";
int len = sizeof(str);
printf("%d\n",len);
func1(p,str,len);
printf("%s\n",*p);
free(p);
p = NULL;
}
这是一段有陷阱的代码,本篇将集中精力讨论段错误的问题。
我不打算告诉你如何快速定位段错误,因为那将让你远离事实的真相,如果你打算征服段错误, 从而更好的理解C/C++语言,那么你需要看下面的内容。
这里贴出我们的一个可以运行的版本
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
void func1(char ** dest,char * src,int n) {
(*dest) = (char*)malloc(sizeof(char)*n);
strcpy(*dest,src);
}
int main(int argc,char** args) {
char * p = NULL;
char str[] = "foreach_break";
int len = sizeof(str);
printf("%d\n",len);
func1(&p,str,len);
printf("%s\n",p);
free(p);
p = NULL;
}
它的运行结果如下:
它为什么可以运行?
注意和错误的代码的对比,有什么不同:
char ** p = NULL;
func1(p,str,len);
char * p = NULL;
func1(&p,str,len);
这里如果你有了一定的C语言基础,你肯定会觉得
对一个
char * p
的指针进行&p
操作会得到一个char ** p
,这似乎和正确的代码没有区别!
那么为什么会一个段错误,一个是正常运行呢?
我们将开始对两份代码进行反汇编,并找出段错误的原因:
我们从main
函数的第1行看起:
所谓野指针,就是存放这个指针的地址是有的,但这个指针指向的地址不明确。
所谓零指针,就是这个指针指向了虚拟地址0x0。
你已经知道两份代码中的指针p
都已经成了零指针。
我们关注一下func1
函数的开头:
错误代码
正确代码
也许你已经猜到了,在错误的代码中,我们调用
func1
函数,对dest
参数传入了一个零指针指向的地址0x0
。
就像这样:func1(p,str,len);
这种错误跟栈没有一点关系。
完全是因为错误代码中的指针的指针char ** p = NULL
指向了0x0
,所以*p
的值就是0x0
,那么你传递*p
就会传递0x0
。
这就是段错误的原因,0x0
这个地址在一个称作用户进程空间的保留或未使用的空间中,而这一段空间是被保护的,你无法访问。
我们在这里也可以尝试访问0x0
地址,会得到一个无法访问的提示:
每个应用程序被启动,都会引发操作系统实例一个进程(process).
进程拥有自己的虚拟地址空间(VMA).
你的C/C++程序为什么无法运行?揭秘Segmentation fault (core dumped)(1)
原文地址:http://blog.csdn.net/gsky1986/article/details/45371051