您的位置:首页 > 理论基础

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

2017-08-14 17:31 309 查看
  csapp的第九章“虚拟存储器”往往被认为是全书最精华的部分之一。书里前言也写道:“这一章比其他任何一章都更能展现将计算机系统中的硬件和软件结合起来阐述的优点”。在这一章,作者以malloc的实现为例,讲解了动态存储器分配、碎片合并、垃圾回收这些概念。最后列举了十种C程序中容易犯的内存引用错误,很实用:)总结如下。

间接引用坏指针

读未初始化的存储器

允许栈缓冲区溢出

错误地假设指针和它们指向的对象是相同大小的

造成错位错误

引用指针,而不是它所指向的对象

误解指针运算

引用不存在的变量

引用空闲堆块中的数据

引起存储器泄漏

间接引用坏指针

scanf("%d",&val);//正确,应当传递给scanf变量地址

scanf("%d",val);//错误,scanf会将val值解释为地址,假设不幸的是val的值确实对应于虚存的合法读写区域,就覆盖了存储器


读未初始化的存储器

int *matvec(int **A, int *x, int n)
{
int i, j;
int *y = (int *) malloc(n *sizeof(int));
for (i = 0; i < n; i++)
{
for (j = 0; j < n; j++)
{
y[i] += A[i][j] * x[j];/* 程序不正确地假设向量y被初始化为零(堆存储器不会初始化为零)*/
}
}
}


允许栈缓冲区溢出

void bufoverflow()
{
char buf[64];

gets(buf); /* 不检查输入串的大小就写入栈中的目标缓冲区会导致缓冲区溢出。应使用限制输入串大小的fgets函数 */
return;
}


错误地假设指针和它们指向的对象是相同大小的

int **makeArray1(int n, int m)
{
int i;
int **A = (int **) malloc(n * sizeof(int)); /*应是sizeof(int *),否则创建的是int数组而不是指针数组*/

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

return A;
}
/*这段代码将创建一个由n个指针组成的数组,每个指针指向一个包含m个int的数组*/

/*这段代码只有在int和指向int的指针大小相同的机器上运行良好,在指针大于int的机器上会引发for循环写越界*/


造成错位错误

int **makeArray2(int n, int m)
{
int i;
int **A = (int **) malloc(n *sizeof(int *));

for (i = 0; i <= n; i++)  /*低级的越界错误,i < n 而不是i <= n */
A[i] = (int *) malloc(m * sizeof(int));

return A;
}


引用指针,而不是它所指向的对象

int *binheapDelete(int **binheap, int *size)
{
int *packet = binheap[0];

binheap[0] = binheap[*size - 1];
*size--;          /*注意运算符优先级--和*相同,导致指针自减。应是 (*size)-- */
heapipfy(binheap, *size, 0);
return (packet);
}


误解指针运算

int *search(int *p, int val)
{
while (*p && *p != val)
p += sizeof(int); /* 指针是以指向的对象大小为单位来进行算术操作的。遍历数组应是p++。*/

return p;
}


引用不存在的变量

int *stackref()
{
int val;

return &val; /* 注意局部变量的生存周期 */
}


引用空闲堆块中的数据

int *heapref(int n, int m)
{
int i;
int *x, *y;

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

free(x);

y = (int *) malloc m * sizeof(int));

for (i = 0; i < m, i++)
y[i] = x[i]++; /* x已经被释放 */

return y;
}


引起存储器泄漏

void leak(int n)
{
int *x = (int *)malloc(n *sizeof(int));

return; /* 未释放就返回导致x成为堆中的垃圾 */
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息