C语言段错误的有用总结
例题:
有以下两个文件,输出结果是 ()
文件A:
int a[10] = {100};
文件B:
#include <stdio.h>
extern int *a;
void main()
{
printf("%d", a[0]);
}
A) 100 B) 0 C) 段错误 D) 编译错误
测试结果:
解释:
在extern int *a和printf("%d", a[0])这两条语句中,编译器觉得a是一个指针变量,所以它提取存储在那里的指针值,然后对这个结果运行间接訪问操作。但a实际上是整型数组的起始位置,所以作为"指针"获得的这个值实际上是数组的第一个整形元素。其结果解释为一个地址。然后对它进行间接訪问。作为结果,它或者将提取一些随意内存位置的内容。或者因为某种地址错误而导致程序失败。
段错误的常见原因总结:
一、段错误究根到底就是访问了非法内存
这个内存区要么是不存在的,要么 是受到系统保护的,还有可能是缺少文件或者文件损坏。可能的原因包括:
访问代码段(原因经常是指针未初始化指向了错误的位置或解引用空指针)、访问寄存器
例子1:解引用空指针 int *p=NULL; printf("%d\n",*p); //因为内存低地址为代码段,不可访问
例子2:访问含有非法值得内存 register int p =10; printf("%d\n",*p); //由于register关键字使变量存储到内核寄存器中,因此不能访问
野指针:即定义指针时并未对其初始化,其指向的的位置式未知的。对野指针解引用可能造成段错误或者导致程序崩溃
防止方案:1;定义时初始化为NULL 2;解引用前赋值 3;使用完后指向NULL 每次使用指针之前记得赋值就好了
二、数组越界
如:当使用malloc申请了一页内存,但使用却超出了。 越过数组边界写入数据,在动态分配的内存两端之外写入数据,或改写一些堆管 理数据结构(在动态分配的内存之前的区域写入数据)
堆中:p = malloc(256); p[-1] = 0; p[256] = 0; //访问了未知空间的内存
栈中:int *p=NULL; int a[6]; p=a; for(int i=0;i<10;i++){*p++=i;} //stack smashing detected 访问了未知空间的内存
三、scanf错误使用
int b;
scanf("%d",b);//应为scanf("%d",&b);
四、指针访问只读内存区
如:char *p=“abcddf”; *p=‘A’; //其实本质上错误原因和解引用空指针类似,“abcddf”在被定义时放在了代码段或常量区。
//解决方法是将字符串存到数组中,再将指针指向数组头
这里补充一下程序运行时内存分配:
1 栈区:存放函数运行时产生的临时变量,局部变量、函数的入口参数,返回值和const定义的局部变量,函数结束后由编译器释放。
2 堆区:用于存放程序运行时被动态分配的内存段,一般由程序员手动申请释放malloc申请,free释放。
3 全局区(静态区):全局区用来存储全局变量,主要分为两个段:1. .bss段:该段用于存放未初始化或者初始化为0的全局变量和静态变量(static)
2. .data段:又叫数据段,用于存储初始化不为0的全局变量和静态变量、const定义的全局变量(在.rodata段)
该段在程序结束后由系统释放。
4 常量区:常量字符串就是放在这里的。 程序结束后由系统释放
5 代码区:又叫.text段用于存放函数的代码,部分字符串常量也存在代码段
三个申请内存的函数:
1. void *malloc(unsigned int size); //单位为字节 如要申请200个字节的空间存储int型数据 int *p=(int *)malloc(50 *sizeof(int))
2. void *calloc(unsigned n,unsigned size); //long *buffer; buffer =(long *)calloc(20,sizeof(long)); 获得一块长整型数组空间
3. void *realloc(void *mem_address,unsigned int newsize);//重新分配内存
三种方式,申请成功返回(void *)类型的指针,失败返回NULL;使用完之后切记要free释放
总结
以上是生活随笔为你收集整理的C语言段错误的有用总结的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇: linux c 获取终端输出到文件,LI
- 下一篇: iptv错误代码2003什么意思_IPT