您的位置:首页 > 其它

c程序中常见的与存储器有关的错误

2011-05-15 23:41 204 查看
------------- c程序中常见的与存储器有关的错误-----------
*整理:Zsm。
*时间:2011-5-2。
*出处:http://blog.csdn.net/Zsm0107。
------------------------------------------------------------
与存储器有关的错误属于那些最令人惊恐放入错误,(-:)),因为它们在时间和空间上,经常是错误源一段
距离之后才表现出来的。
一、两个概念
内存泄漏----未释放不再使用的内存。
内存损坏----释放或改写仍在使用的内存。
===============================================================================================
二、常见错误的归纳
----------------------------------------------------------------------------------------------
1.间接引用坏指针
例子:scanf("%d",val); 正确的是:scanf("%d",&val);
分析:scanf将把val的内容解释为一个地址,并试图将一个字写到这个位置。在最好的情况下,程序立即
停止。而在最糟糕的情况下,val的内容对应于虚拟存储器的某个合法的读/写区域,于是覆盖了存储器,这种
情况是隐藏的,所以会造成令人困惑的后果。
----------------------------------------------------------------------------------------------
2.读未初始化的存储器
i)原因:
虽然bss存储器位置总是被加载器初始化为零,但是对于堆存储器却并不是这样的。
ii)例子:
/*return y = a * x */
int *matvec(int **A, int *x, int n)
{
int i,j;

int *y = (int *)malloc(n*sizeof(int)); //注意此时的y[0....n-1]未初始化哦

for(i = 0; i != n; ++i)
{
for(j = 0; j != n; ++j)
{
y[i] += A[i][j] * x[j];
}
}
return y;
}
正确的是:
1.显示地将y[i]设为0.
int *y = (int *)malloc(n*sizeof(int));
for(i = 0; i != n; ++n)
{
y[i] = 0;
}
2.使用calloc
int *y = (int *)calloc(n, sizeof(int));
---------------------------------------------------------------------------------------------
3.允许栈缓冲区溢出
原因:
如果一个程序不检查输入串的大小就写入栈中的目标缓冲区,那么这个程序就会有栈缓冲区溢出错误。
例子:
#define BUFSIZE 64
void buf()
{
char buf[64];

gets(buf);
/*正确的是使用fgets:
*fgets(buf,BUFSIZE,stdin);
*/
return;
}
-----------------------------------------------------------------------------------------------
4.假设指针和它们指向的对象是相同大小
一种常见的错误是假设指向对象的指针和它们所指现的对象是相同大小的。
/*创建一个A
[m]的二维数组*/
int **makeArray(int n, int m)
{
int i;
int **A = (int **)malloc(n*sizeof(int)); //正确的是:int **A = (int **)malloc(n*sizeof(int*));

for(i = 0; i != n; ++i)
{
A[i] = (int *)malloc(m*sizeof(int));
}

return A;
}
---------------------------------------------------------------------------------------------------
5.造成错位错误(覆盖错误的来源之一哦)
同样是上面的那段代码:
/*创建一个A
[m]的二维数组*/
int **makeArray(int n, int m)
{
int i;
int **A = (int **)malloc(n*sizeof(int*));

for(i = 0; i != n+1; ++i) //注意这里的不同哦,将覆盖A数组后面的某个存储器
{
A[i] = (int *)malloc(m*sizeof(int));
}

return A;
}
---------------------------------------------------------------------------------------------------------
6.引用指针,而不是它所指向的对象
/*删除一个有*size项的二叉堆里的第一项,然后对剩下的 *size - 1 项重新建堆 */
int *binheapDelete(int **binheap, int *size)
{
int *p = binheap[0];

binheap[0] = binheap[*size -1];
*size--; //错误:因为 --和* 的优先级相同,从右向左结合。也就是*(size--),而本意是:(*size)--
heapify(binheap,*size,0);
return p;
}
个人认为:自己写代码时,最好加括号来表达自己的意思。
-------------------------------------------------------------------------------------------------------------
7.误解指针运算
忘记指针的算术操作是以它们指向的对象的大小为单位来进行的,而这种大小单位并一定是字节
/*search函数:在数组p中查找val第一个出现的位置*/
int *search(int *p, int val)
{
while(*p && *p != val)
{
p += sizeof(int); //正确的是:++p
}
return p;
}
--------------------------------------------------------------------------------------------------------------------
8.引用不存在的变量(主要是注意局部变量的作用(生存)周期)
int *stackp()
{
int val;

return &val;
}
---------------------------------------------------------------------------------------------------------------------
9.引用空闲堆块中的数据
int *heapref(int n)
{
int i;
int *x,*y;

x = (int *)malloc(n*sizeof(int));
free(x);

y = (int *)malloc(n*sizeof(int));
for(i = 0; i != m; ++i)
{
y[i] = x[i]++; //糟糕咯,x[i]已是一个空闲块咯
}

return y;
}
---------------------------------------------------------------------------------------------------------------------
10.引起存储器泄漏
void leak(int m)
{
int *x = (int *)malloc(n*sizeof(int));

return ; /*注意x未释放哈,当自己调用malloc函数时就需要与free函数相对应哈*/
}
-----------------------------------------------------------------------------------------------------------------------
如何检测内存泄漏(参见《c专家编程》的Page154)
这里就写两个步骤(-:D):
1.使用swap命令观察还有多少可用的交换空间。
2.确定可疑的进程,看看它是不是该为内存泄漏负责。
只写这两个步骤呢,原因是:这些东西我不是很熟悉,所以不能写得太多,会误导他人,也是对自己的学习负责。
说明:这只是自己写代码时常犯的一些错误,而后在书中看到了,就将其整理出,与大家
分享一下。请大家多多指教。
可以参考这篇文:http://blog.csdn.net/absurd/archive/2006/07/12/908601.aspx
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: