软件内存问题的原理:(内存泄露、内存益出、指针操作)
一、变量在内存中的存储
# include<stdio.h> //引用头文件stdio.h,这样就可以在程序中调用Printf()函数
Int a=1; //全局变量a,并赋出值为1
Int b; //全局变量b
Void main() //主函数
{
Int c; //动态局部变量c,其关键字auto省略
Static int d; //静态局部变量d,其关键字static未省略
Printf(“%d\n”,c) //打印c的值
}
以上程序段内变量在内存中的存储过程如下:
|
(堆) |
静态局部变量;d (静 态存储区域) |
全局变量:a、b (静态存储区) |
|
在以上过程中:
栈:存储动态局部变量。
堆:动态分配的内存空间(手工分配)。
静态存储区:存储静态局部变量和全局变量,即在整个程序运行期间不变的量。
代码段:存储执行语句。
二、内存分配形式(C、C++、JAVA虽然具体语法不同,但内存分配形式都一样)
a) 从静态存储区域分配:内存在编译时就已经分配好,这块内存在程序的整个运行期间都存在,如全局变量,static变量。
b) 在栈上分配:在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时,这些存储单元自动被释放掉。栈内存分配运算内置与处理器的指令集。
c) 从堆上分配(动态内存分配):程序在运行时用关键字(malloc、new)申请任意大小的内存,程序员自己负责何时释放内存(free、delete)。动态内存的生存期由程序员决定。
三、程序举例(C语言)
C语言编程时,需要注意的地方
1、 申请内存后,检查内存是否为NULL,防止指针为NULL的内存。
2、 动态内存的申请与释放必须配对,防止内存泄露。
3、 释放内存后,立即将指针设置为NULL,防止产生“野指针”。
4、 不要忘记为数组或动态内存赋出值。
5、 避免数组或指针的下标越界,如多“1”或者少“1”。
# include<malloc.h> //引用头文件malloc.h,以调用free()函数
#include<stdio.h> //引用头文件stdio.h,以调用printf()函数
Main()
{
Char *p; //定义p为char指针
P=(char*)malloc(100); //申请100字节内存空间,并将内存首地址赋值为p
If(p==null) //判断P是否为空
Printf(“内存未申请成功!!\n”);//如果为空,则内存为空,即内存申请不成功
Else
Printf(“内存首地址为:%X”,p); //将内存首地址已16进制形式输出首地址
Free(p); //释放内存,如果没有这一句,将可能导致内存泄露。
P=null; //指针置为NULL,
Return 0;
}
以上程序段讲述的是:1-3。
#include<stdio.h> //调用头文件stdio.h
Void main(void)
{
Int i=0; //定义变量i,并赋出值为0
Int a[10]; //定义数组a[],有10个元素,注意这一行有没有问题
for (i=0;i<10;++i) //循环
a[i]=i; //给数组元素赋值
for(i=9;i>=0;--i)//循环
printf(“%d”,a[i]); //输出数组元素的值
printf(“\n”);
}
如果将第一个循环的i<10错误写成i<=10,或i<12,此时运行程序将会出现“内存溢出错误”,而且是“写内存溢出”。
如果将第二个循环的i=9错误写成i=10,此时运行程序将会出现一些莫名其妙的数据,这就是“读内存溢出”。
以上程序讲述的是:4-5