- UID
- 580
- 精华
- 积分
- 561
- 威望
- 点
- 宅币
- 个
- 贡献
- 次
- 宅之契约
- 份
- 最后登录
- 1970-1-1
- 在线时间
- 小时
|
帮别人调试个程序,程序的功能主要涉及动态数组,实现动态数组元素的添加,删除,查找,显示功能。但是在执行添加功能的时候,连续执行三次添加的时候就会出现问题,让人感到非常的莫名其妙。
涉及到的函数如下所示:- void adddata(int * arr, int * len)
- {
- int n;
- int * add;
- int cnt =0, t1;
- 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));
-
- 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("realloc memory 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;
- }
- }
复制代码 |
|