realloc函数引发的慘案
帮别人调试个程序,程序的功能主要涉及动态数组。实现动态数组元素的加入,删除,查找。显示功能。可是在运行加入功能的时候,连续运行三次加入的时候就会出现故障,让人感到很的莫名其妙。
涉及到的函数例如以下所看到的:
void adddata(int * arr, int * len) { int n; int *add; int cnt=0, t1; printf("pleaseenter the amount of element you want to add;\n"); scanf("%d",&n); add = (int*)malloc(sizeof(int)* n); inputdata(add, n); //把用户要加入的数据加入一个新的数组。 t1 = *len; //以下循环实用,当用户输入的数都大于不论什么数的时候用的 *len = *len + n ; //又一次定义下数组长度,依据用户要扩充的大小。 realloc(arr, sizeof(int)*(*len)); for (i=0;i<n; ++i) // i 循环是循环要加入的数 { for(j=0; j<t1+i; ++j) // j循环是循环原数组 { if( add[i] < arr[j]) { for (k=j; k <= t1+i; ++k) { t =arr[k]; arr[k]= add[i]; add[i]= t; } cnt = 1; break; } cnt = 0; } if( 0 == cnt) arr[t1+i]=add[i]; } resultdata(arr, *len); switch_choice (arr, * len); }
从这里能够看到这段程序的缺点:
<1>全局变量的滥用。只是这里没有造成错误
<2>realloc函数不适用返回值。后面会知道这是罪魁祸首
<3>malloc的add没有在函数结束的时候释放
1 针对函数的缺点。我们一一侦破,先是在函数的结尾加上对add的释放
if(add != NULL) { free(add); add = NULL; }
可是第一次释放add就会出现以下的问题。运行调试,发现是在free的时候出现了问题。也就是free居然失败了。
2 然后再加上对realloc函数的改动
void *realloc(void *memblock, size_t size );
Realloc函数会针对不同的情况运行不同的行为,假设realloc函数运行成功,那么函数会返回新的内存空间的首地址。而且free掉之前 的内存空间。而且之前的内存内容拷贝到新的内存中。假设开辟失败,那么之前的内存空间不会被释放,realloc函数返回NULL。所以在添加内存的时候。万万不可使用一直使用原来的全局指针,原因就是它可能已经被free掉,而新的指针指向发生了变化。
同一时候假设继续使用原来的全局指针,就可能发生数组的越界,越界就会破坏堆,终于连其他的跟操作内存的函数运行都会出现故障。
如今把void adddata(int * arr,int * len)
中的realloc函数改动成例如以下:
tmp = (int*)realloc(arr, sizeof(int)*(*len)); if( tmp!= NULL) { arr = tmp; tmp = NULL; } else { printf("reallocmemory failed\n"); exit(1); }
然后測试。一切OK,这说明了罪魁祸首的确是realloc函数的错误使用,realloc不会保证新内存的首地址还是原来的。它非常可能发生变化。
3 针对realloc函数错误调用后,发生数组越界会造成free失败的验证
測试代码例如以下所看到的:
#include <stdio.h> #include <stdlib.h> void main() { int n = 3; int na; int i; int *p2; int *p = (int*)malloc(sizeof(int)*n); int *p3 = ( int*)malloc(sizeof(int)*3 ); p3[0] = 11; p3[1] = 22; p3[2] = 33; for(i=0;i<n;i++) { p[i] = i; } for(i=0;i<n;i++) printf("%d\n",p[i]); printf("input mount of number to add:"); scanf("%d",&na); p2 = (int*)realloc( p,sizeof(int)*(n+na) ); for(i=n;i<n+na;i++) { p2[i] = i; } p[n+na+ 10] = 0; // out range of p for(i=0;i<n+na;i++) printf("%d\n",p2[i]); printf("now can see\n"); for(i=0;i<n;i++) printf("%d\n",p[i]); if( p3 != NULL) //failed because of p's outof range { free(p3); p3 = NULL; } }运行结果:
这个就说明了一切问题。p的越界造成了无辜的p3跟着遭殃,p3到最后都不能进行释放。
附录(改动后的完整的功能程序):
#include <stdio.h> #include <stdlib.h> void inputdata( int * arr, int len); void arrangeinorder( int * arr, int len); void resultdata(int*, int); void switch_choice(int * , int ); void finddata( int * arr, int len); void deletedata(int * arr, int * len); void adddata(int * arr, int * len); int main (void) { int *arr; int len; printf ("enter the amount of data that you will input: "); scanf("%d", &len); arr = (int *) malloc( sizeof(int) * len); inputdata(arr, len); //单独測试可用(用来输入数组) arrangeinorder(arr, len); // 单独測试可用(把数组进行排序。从小到大) switch_choice (arr, len); free(arr); return 0; } void inputdata( int * arr, int len) { int i; printf("please enter your data ;\n"); for (i=0; i<len; ++i) { printf("%d--> ", i+1); scanf("%d", &arr[i]); } } void arrangeinorder( int * arr, int len) { int i,j,t; for (i=0; i<len; ++i) { for (j=i+1; j<len; ++j) { if (arr[i] > arr[j]) { t = arr[i]; arr[i] = arr[j]; arr[j] = t; } } } resultdata(arr, len); } void finddata( int * arr, int len) { int n,i; int t = 0; printf("please enter the number you want to find\n"); scanf("%d", &n); for (i=0; i<len; ++i) { if (n == arr[i]) { printf ("the number %d, is located in the %d th\n", n,i+1); t=1; } } if (t != 1 ) printf("number %d is not in this array.\n", n); } void deletedata(int * arr, int * len) { int n,i,j; int cnt =0; printf("please enter the number you want to delete from this array;\n"); scanf ("%d", &n); for (i=0; i<*len; ++i) { while(n == arr[i]) { for (j=i; j<*len; ++j) arr[j] = arr[j+1]; cnt++; //to count amount of number had been delete from array. } } *len = *len - cnt; arr = (int*)realloc(arr, sizeof(int)*(*len)); if( arr == NULL ) { printf("realloc memory failed\n"); exit(1); } resultdata(arr, *len); switch_choice (arr, * len); } void adddata(int * arr, int * len) { int n,i,j,k,t1; int *add,*tmp; int cnt =0; int t = 0; printf("please enter the amount of element you want to add;\n"); scanf("%d", &n); add = (int *)malloc(sizeof(int) * n); inputdata(add, n); //把用户要加入的数据加入一个新的数组。 t1 = *len; //以下循环实用,当用户输入的数都大于不论什么数的时候用的 *len = *len + n ; //又一次定义下数组长度。依据用户要扩充的大小。//realloc(arr, sizeof(int)*(*len)); tmp = (int*)realloc(arr, sizeof(int)*(*len)); if( tmp != NULL) { arr = tmp; tmp = NULL; } else { printf("realloc memory failed\n"); exit(1); } for (i=0; i<n; ++i) // i 循环是 循环要加入的数 { for (j=0; j<t1+i; ++j) // j循环 是循环原数组 { if ( add[i] < arr[j]) { for (k=j; k <= t1+i; ++k) { t = arr[k]; arr[k] = add[i]; add[i] = t; } cnt = 1; break; } cnt = 0; } if ( 0 == cnt) arr[t1+i]=add[i]; } if (add != NULL) { free(add); add = NULL; } resultdata(arr, *len); switch_choice (arr, * len); } void resultdata( int * arr, int len) { int i; printf("new array has been show below\n"); for ( i=0 ; i <len ; ++i) { printf("%d--> ", i+1); printf("%2d \n", arr[i]); } } void switch_choice(int * arr, int len) { int n; printf("type number to choose the function you are going to use:\n"); printf("1. activate number search.\n"); printf("2. delete number from this array. \n"); printf("3. add new numbers to this array. \n"); printf("4. exit this program. \n"); scanf("%d", &n); switch (n) { case 1: finddata (arr, len); break; case 2: deletedata (arr, &len); break; case 3: adddata ( arr, &len); break; case 4: return; break; } }