找回密码
 立即注册→加入我们

QQ登录

只需一步,快速开始

搜索
热搜: 下载 VB C 实现 编写
查看: 3638|回复: 3

realloc引发的惨案

[复制链接]
发表于 2014-12-29 22:49:57 | 显示全部楼层 |阅读模式

欢迎访问技术宅的结界,请注册或者登录吧。

您需要 登录 才可以下载或查看,没有账号?立即注册→加入我们

×
帮别人调试个程序,程序的功能主要涉及动态数组,实现动态数组元素的添加,删除,查找,显示功能。但是在执行添加功能的时候,连续执行三次添加的时候就会出现问题,让人感到非常的莫名其妙。
1.png
涉及到的函数如下所示:
  1. void adddata(int * arr, int * len)
  2. {
  3.         int n;
  4.         int * add;
  5.         int cnt =0, t1;
  6.         printf("please enter the amount of element you want to add;\n");
  7.         scanf("%d", &n);
  8.         add = (int *)malloc(sizeof(int) * n);
  9.         inputdata(add, n); //把用户要添加的数据加入一个新的数组。
  10.         t1 = *len; //下面循环有用,当用户输入的数都大于任何数的时候用的
  11.         *len = *len + n ; //重新定义下数组长度,根据用户要扩充的大小。
  12.         realloc(arr, sizeof(int)*(*len));
  13.        
  14.         for (i=0; i<n; ++i)                                                                // i 循环是 循环要添加的数
  15.         {
  16.                 for (j=0; j<t1+i; ++j)                                                        // j循环 是循环原数组
  17.                 {
  18.                         if ( add[i] < arr[j])
  19.                         {
  20.                                 for (k=j; k <= t1+i; ++k)
  21.                                 {
  22.                                                 t = arr[k];
  23.                                                 arr[k] = add[i];
  24.                                                 add[i] = t;
  25.                                 }
  26.                                 cnt = 1;
  27.                                 break;
  28.                         }
  29.                         cnt = 0;
  30.                 }
  31.                 if ( 0 == cnt)
  32.                         arr[t1+i]=add[i];

  33.         }
  34.         resultdata(arr, *len);
  35.         switch_choice (arr, * len);
  36. }
复制代码
从这里可以看到这段程序的缺点:
<1>全局变量的滥用,不过这里没有造成错误
<2>realloc函数不适用返回值,后面会知道这是罪魁祸首
<3>malloc的add没有在函数结束的时候释放
1 针对函数的缺点,我们一一侦破,先是在函数的结尾加上对add的释放
  1. if(add != NULL)
  2. {
  3.         free(add);
  4.         add = NULL;
  5. }
复制代码
但是第一次释放add就会出现下面的问题,执行调试,发现是在free的时候出现了问题,也就是free竟然失败了。
1.png
2 然后再加上对realloc函数的修改
  1. void *realloc(void *memblock, size_t size );
复制代码
Realloc函数会针对不同的情况执行不同的行为,如果realloc函数执行成功,那么函数会返回新的内存空间的首地址,并且free掉之前 的内存空间,并且之前的内存内容复制到新的内存中;如果开辟失败,那么之前的内存空间不会被释放,realloc函数返回NULL。所以在增加内存的时候,万万不可使用一直使用原来的全局指针,原因就是它可能已经被free掉,而新的指针指向发生了变化。
同时如果继续使用原来的全局指针,就可能发生数组的越界,越界就会破坏堆,最终连其它的跟操作内存的函数执行都会出现问题。
现在把void adddata(int *arr, int *len)中的realloc函数修改成如下:
  1. tmp = (int*)realloc(arr, sizeof(int)*(*len));

  2. if( tmp != NULL)
  3. {
  4.         arr = tmp;
  5.         tmp = NULL;
  6. }
  7. else
  8. {
  9.         printf("realloc memory failed\n");
  10.         exit(1);
  11. }
复制代码
然后测试,一切OK,这说明了罪魁祸首的确是realloc函数的错误使用,realloc不会保证新内存的首地址还是原来的,它很可能发生变化。

3 针对realloc函数错误调用后,发生数组越界会造成free失败的验证
测试代码如下所示:
  1. #include <stdio.h>
  2. #include <stdlib.h>

  3. void main()
  4. {       
  5.         int n = 3;
  6.         int na;
  7.         int i;
  8.         int *p2;
  9.         int *p = (int*)malloc(sizeof(int)*n);
  10.         int *p3 = ( int*)malloc(sizeof(int)*3 );
  11.         p3[0] = 11;
  12.         p3[1] = 22;
  13.         p3[2] = 33;
  14.         for(i=0;i<n;i++)
  15.         {
  16.                 p[i] = i;
  17.         }
  18.         for(i=0;i<n;i++)
  19.                 printf("%d\n",p[i]);
  20.         printf("input mount of number to add:");
  21.         scanf("%d",&na);
  22.         p2 = (int*)realloc( p,sizeof(int)*(n+na) );
  23.         for(i=n;i<n+na;i++)
  24.         {
  25.                 p2[i] = i;
  26.         }
  27.         p[n+na+ 10] = 0;        // out range of p
  28.         for(i=0;i<n+na;i++)
  29.                 printf("%d\n",p2[i]);
  30.         printf("now can see\n");
  31.         for(i=0;i<n;i++)
  32.                 printf("%d\n",p[i]);

  33.         if( p3 != NULL)        //failed because of p's outof range
  34.         {
  35.                 free(p3);
  36.                 p3 = NULL;
  37.         }
  38. }
复制代码
执行结果:
1.png
这个就说明了一切问题,p的越界造成了无辜的p3跟着遭殃,p3到最后都不能进行释放。

附录(修改后的完整的功能程序):
  1. # include <stdio.h>
  2. #include <stdlib.h>

  3. void inputdata( int * arr, int len);
  4. void arrangeinorder( int * arr, int len);
  5. void resultdata(int*, int);
  6. void switch_choice(int * , int );
  7. void finddata( int * arr, int len);
  8. void deletedata(int * arr, int * len);
  9. void adddata(int * arr, int * len);

  10. int main (void)
  11. {       
  12.         int *arr;
  13.         int len;
  14.        
  15.         printf ("enter the amount of data that you will input: ");
  16.         scanf("%d", &len);

  17.         arr = (int *) malloc( sizeof(int) * len);
  18.         inputdata(arr, len);                         //单独测试可用(用来输入数组)
  19.         arrangeinorder(arr, len);                 // 单独测试可用(把数组进行排序,从小到大)
  20.         switch_choice (arr, len);
  21.         free(arr);

  22.         return 0;
  23. }

  24. void inputdata( int * arr, int len)
  25. {
  26.         int i;
  27.         printf("please enter your data ;\n");
  28.         for (i=0; i<len; ++i)
  29.         {
  30.                 printf("%d-->  ", i+1);
  31.                 scanf("%d", &arr[i]);
  32.         }
  33. }

  34. void arrangeinorder( int * arr, int len)
  35. {
  36.         int i,j,t;
  37.         for (i=0; i<len; ++i)
  38.         {
  39.                 for (j=i+1; j<len; ++j)
  40.                 {
  41.                         if (arr[i] > arr[j])
  42.                         {
  43.                                 t = arr[i];
  44.                                 arr[i] = arr[j];
  45.                                 arr[j] = t;
  46.                         }
  47.                 }

  48.         }
  49.         resultdata(arr, len);
  50. }

  51. void finddata( int * arr, int len)
  52. {
  53.         int n,i;
  54.         int t = 0;
  55.         printf("please enter the number you want to find\n");
  56.         scanf("%d", &n);

  57.         for (i=0; i<len; ++i)
  58.         {
  59.                 if (n == arr[i])
  60.                 {
  61.                         printf ("the number %d, is located in the %d th\n", n,i+1);
  62.                         t=1;
  63.                 }
  64.         }

  65.         if (t != 1 )
  66.                 printf("number %d is not in this array.\n", n);

  67. }

  68. void deletedata(int * arr, int * len)
  69. {
  70.         int n,i,j;
  71.         int cnt =0;
  72.         printf("please enter the number you want to delete from this array;\n");
  73.         scanf ("%d", &n);

  74.         for (i=0; i<*len; ++i)
  75.         {
  76.                 while(n == arr[i])
  77.                 {
  78.                         for (j=i; j<*len; ++j)
  79.                                 arr[j] = arr[j+1];
  80.                         cnt++;   //to count amount of number had been delete from array.
  81.                 }
  82.         }
  83.         *len = *len - cnt;
  84.         arr = (int*)realloc(arr, sizeof(int)*(*len));
  85.         if( arr == NULL )
  86.         {
  87.                 printf("realloc memory failed\n");
  88.                 exit(1);
  89.         }

  90.         resultdata(arr, *len);
  91.         switch_choice (arr, * len);
  92. }

  93. void adddata(int * arr, int * len)
  94. {
  95.         int n,i,j,k,t1;
  96.         int *add,*tmp;
  97.         int cnt =0;
  98.         int t = 0;

  99.         printf("please enter the amount of element you want to add;\n");
  100.         scanf("%d", &n);

  101.         add = (int *)malloc(sizeof(int) * n);

  102.         inputdata(add, n); //把用户要添加的数据加入一个新的数组。
  103.         t1 = *len; //下面循环有用,当用户输入的数都大于任何数的时候用的

  104.         *len = *len + n ; //重新定义下数组长度,根据用户要扩充的大小。
  105.         //realloc(arr, sizeof(int)*(*len));
  106.         tmp = (int*)realloc(arr, sizeof(int)*(*len));

  107.         if( tmp != NULL)
  108.         {
  109.                 arr = tmp;
  110.                 tmp = NULL;
  111.         }
  112.         else
  113.         {
  114.                 printf("realloc memory failed\n");
  115.                 exit(1);
  116.         }

  117.         for (i=0; i<n; ++i)                                                                // i 循环是 循环要添加的数
  118.         {
  119.                 for (j=0; j<t1+i; ++j)                                                        // j循环 是循环原数组
  120.                 {
  121.                         if ( add[i] < arr[j])
  122.                         {
  123.                                 for (k=j; k <= t1+i; ++k)
  124.                                 {
  125.                                                 t = arr[k];
  126.                                                 arr[k] = add[i];
  127.                                                 add[i] = t;
  128.                                 }
  129.                                 cnt = 1;
  130.                                 break;
  131.                                
  132.                         }
  133.                         cnt = 0;
  134.                 }
  135.                 if ( 0 == cnt)
  136.                         arr[t1+i]=add[i];

  137.         }
  138.         if (add != NULL)
  139.         {
  140.                 free(add);
  141.                 add = NULL;
  142.         }

  143.         resultdata(arr, *len);
  144.         switch_choice (arr, * len);
  145. }

  146. void resultdata( int * arr, int len)
  147. {
  148.         int i;
  149.         printf("new array has been show below\n");
  150.         for ( i=0 ; i <len ; ++i)
  151.         {
  152.                 printf("%d-->  ", i+1);
  153.                 printf("%2d \n", arr[i]);
  154.         }
  155. }



  156. void switch_choice(int * arr, int len)
  157. {
  158.         int n;

  159.         printf("type number to choose the function you are going to use:\n");
  160.         printf("1. activate number search.\n");
  161.         printf("2. delete number from this array. \n");
  162.         printf("3. add new numbers to this array. \n");
  163.         printf("4. exit this program. \n");

  164.         scanf("%d", &n);

  165.         switch (n)
  166.         {
  167.         case 1:
  168.                 finddata (arr, len);
  169.                 break;
  170.         case 2:
  171.                 deletedata (arr, &len);
  172.                 break;
  173.         case 3:
  174.                 adddata ( arr, &len);
  175.                 break;
  176.         case 4:
  177.                 return;
  178.                 break;
  179.         }
  180. }
复制代码
回复

使用道具 举报

发表于 2014-12-30 09:06:47 | 显示全部楼层
这篇文章写的挺有意义,核心是realloc如何被误用的
另外对于动态数组,还是用stl或类stl实现为好,否则每次进行realloc效率也不高
回复 赞! 靠!

使用道具 举报

发表于 2015-9-30 11:44:18 | 显示全部楼层
元始天尊 发表于 2014-12-30 09:06
这篇文章写的挺有意义,核心是realloc如何被误用的
另外对于动态数组,还是用stl或类stl实现为好,否则每次 ...

realloc和stl本来就是不同语言的东西
回复 赞! 靠!

使用道具 举报

发表于 2015-10-2 18:45:10 | 显示全部楼层
这个要支持一下啊{:soso__4607844064215092132_3:}
回复 赞! 靠!

使用道具 举报

本版积分规则

QQ|Archiver|小黑屋|技术宅的结界 ( 滇ICP备16008837号 )|网站地图

GMT+8, 2024-12-22 15:08 , Processed in 0.044631 second(s), 28 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表