By: 潘云登
Date: 2009-7-18
Email: intrepyd@gmail.com
Homepage: http://blog.csdn.net/intrepyd
Copyright: 该文章版权由潘云登所有。可在非商业目的下任意传播和复制。
对于商业目的下对本文的任何行为需经作者同意。
写在前面
本文记录了一个在实现散列表的过程中出现的错误。原本希望对malloc函数进行封装,结果由于对指针参数的理解不透彻,导致了意想不到的错误。
先来看一下下面的程序。
#include <stdio.h>
#define ARRAY_LENGTH 10
void new_array(int *array, int length) { int i;
array = malloc(sizeof(int)*length); printf("array inside:/n"); for(i=0; i<length; i++) { array[i] = 66; printf("%d ", array[i]); } printf("/n"); }
int main() { int *array, i;
new_array(array, ARRAY_LENGTH); printf("array outside:/n"); for(i=0; i<ARRAY_LENGTH; i++) printf("%d ", array[i]); printf("/n"); } |
运行结果如下:
array inside: 66 66 66 66 66 66 66 66 66 66 array outside: 1474660693 -1595387050 -2130706297 15169987 1290568448 13649351 -956301312 54341 1170669568 216 |
在函数中初始化为66的数组变成了这些奇怪的数字。为了查看数组的地址,添加新的打印。
#include <stdio.h>
#define ARRAY_LENGTH 10
void new_array(int *array, int length) { int i;
printf("inside,before malloc(),array=0x%0xd/n", (int)array); array = malloc(sizeof(int)*length); printf("array inside:/n"); for(i=0; i<length; i++) { array[i] = 66; printf("%d ", array[i]); } printf("/n"); printf("inside,after malloc(),array=0x%0xd/n", (int)array); }
int main() { int *array, i;
printf("outside,before new_array(),array=0x%0xd/n", (int)array); new_array(array, ARRAY_LENGTH); printf("outside,after new_array(),array=0x%0xd/n", (int)array); printf("array outside:/n"); for(i=0; i<ARRAY_LENGTH; i++) printf("%d ", array[i]); printf("/n"); } |
运行结果如下:
outside,before new_array(),array=0xb8054870d inside,before malloc(),array=0xb8054870d array inside: 66 66 66 66 66 66 66 66 66 66 inside,after malloc(),array=0x90ef008d outside,after new_array(),array=0xb8054870d array outside: 1474660693 -1595387050 -2130706297 15169987 1290568448 13649351 -956301312 54341 1170669568 216 |
终于真相大白,new_array()函数返回后,array的值仍然是0xb8054870d,而不是malloc所申请空间的地址。原来,array本身是一个指针,将其作为参数传递,在调用函数内,可以修改并保存指针所指向内存空间的内容。然而,指针本身的值仍是按值传递,函数返回后,其值保持不变。这种错误,不仅导致读写错误的内存地址,造成段错误,而且,malloc申请的空间再也无法释放,产生内存泄漏。
为了纠正上述错误,有两种修改方案,具体实现如下:
#include <stdio.h>
#define ARRAY_LENGTH 10
/*方案1*/ int *correct_new_array(int length) { int i, *temp_array;
temp_array = malloc(sizeof(int)*length); for(i=0; i<length; i++) temp_array[i] = 77;
return temp_array; }
/*方案2*/ void correct_new_array_again(int **array, int length) { int i;
*array = malloc(sizeof(int)*length); for(i=0; i<length; i++) (*array)[i] = 88; } |
个人比较喜欢方案1,不需要传递指针的指针,发生错误的概率较小。需要注意的是,不要忘了free先前malloc的内存空间,虽然上面的代码并没有列出。