0x55AA 发表于 2014-12-29 22:49:57

realloc引发的惨案

帮别人调试个程序,程序的功能主要涉及动态数组,实现动态数组元素的添加,删除,查找,显示功能。但是在执行添加功能的时候,连续执行三次添加的时候就会出现问题,让人感到非常的莫名其妙。

涉及到的函数如下所示: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 < arr)
                        {
                                for (k=j; k <= t1+i; ++k)
                                {
                                                t = arr;
                                                arr = add;
                                                add = t;
                                }
                                cnt = 1;
                                break;
                        }
                        cnt = 0;
                }
                if ( 0 == cnt)
                        arr=add;

        }
        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 = 11;
        p3 = 22;
        p3 = 33;
        for(i=0;i<n;i++)
        {
                p = i;
        }
        for(i=0;i<n;i++)
                printf("%d\n",p);
        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;
        }
        p = 0;        // out range of p
        for(i=0;i<n+na;i++)
                printf("%d\n",p2);
        printf("now can see\n");
        for(i=0;i<n;i++)
                printf("%d\n",p);

        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);
        }
}

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 > arr)
                        {
                                t = arr;
                                arr = arr;
                                arr = 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)
                {
                        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)
                {
                        for (j=i; j<*len; ++j)
                                arr = arr;
                        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 < arr)
                        {
                                for (k=j; k <= t1+i; ++k)
                                {
                                                t = arr;
                                                arr = add;
                                                add = t;
                                }
                                cnt = 1;
                                break;
                               
                        }
                        cnt = 0;
                }
                if ( 0 == cnt)
                        arr=add;

        }
        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);
        }
}



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;
        }
}

元始天尊 发表于 2014-12-30 09:06:47

这篇文章写的挺有意义,核心是realloc如何被误用的
另外对于动态数组,还是用stl或类stl实现为好,否则每次进行realloc效率也不高

0xAA55 发表于 2015-9-30 11:44:18

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

realloc和stl本来就是不同语言的东西

FFFFFFFE 发表于 2015-10-2 18:45:10

这个要支持一下啊{:soso__4607844064215092132_3:}
页: [1]
查看完整版本: realloc引发的惨案