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;
	}
}
时间: 2024-10-21 09:11:46

realloc函数引发的惨案的相关文章

转:安全起见,小心使用C语言realloc()函数

安全起见,小心使用C语言realloc()函数 http://www.360doc.com/content/16/0712/09/19227797_574892368.shtml 在C语言中,良好的编程习惯要求一个函数只做一件事,如果一个函数实现了若干功能,可以说基本是一个糟糕的设计. C语言 realloc() 函数位于 stdlib.h 头文件中,其原型为: void *realloc(void *ptr, size_t size); realloc() 会将 ptr 所指向的内存块的大小修

一道题引发的惨案

昨天在一个cocos2d-x的群里,有群友发了一个问题求答案,当时自已也一下子没想到什么好的写法,这时候有个群友写了一个比较少见的代码方法,当时一看到这代码,我有一种如糊灌顶的感受,因为自已平时基本没用这种写法,今日在别的群,我就发了这道题让大家讨论一下,结果没想到,引发了各种争吵和讨论,有写得不好却自以为是的,有写得好却看不起别人的写法,有写得很好却十分低调的,十分精彩,也算是为群里热闹了一下气氛,QQ群也变成了社会市井的一个浓缩了,呵呵. 以下贴上问题和昨天那位群友写的代码,我觉得精彩的地方

C语言中的realloc函数的使用注意事项

最近在学C语言,在用到realloc函数时除了一些问题,始终找不到问题所在,后来便一步一步调试,终于找到了问题,由于前面calloc函数使用时将字符串的长度设置错了,导致在使用realloc时原字符串末尾'\0'被清除了,导致了一系列的问题,好在终于解决了,现在来总结一下 realloc使用注意事项(这是总结网友们的经验) 1. realloc失败的时候,返回NULL 2. realloc失败的时候,原来的内存不改变,也就是不free或不move,(这个地方很容易出错) 3. 假如原来的内存后面

【C/C++】Linux下system()函数引发的错误

http://my.oschina.net/renhc/blog/54582 [C/C++]Linux下system()函数引发的错误 恋恋美食  恋恋美食 发布时间: 2012/04/21 11:33 阅读: 11393 收藏: 21 点赞: 8 评论: 4 今天,一个运行了近一年的程序突然挂掉了,问题定位到是system()函数出的问题,关于该函数的简单使用在我上篇文章做过介绍: http://my.oschina.net/renhc/blog/53580 先看一下问题 简单封装了一下sys

一个截取字符串函数引发的思考

背景 前些天,遇到这样一个问题,问题的内容如下: 要求编写一个截取字符串的函数,输入为一个字符串和字节数,输出为按字节截取的字符串.但是要保证汉字不被截半个,如"我ABC", 4,截取后的效果应该为"我AB",输入"我ABC汉DEF", 6,应该输出为"我ABC",而不是"我ABC+汉的半个". 问题 刚看到这个问题的时候,以为还是很简单的,但写出来之后,发现并不是想要的效果.回想一下当时的思路,就发现刚开

c realloc函数和malloc函数

realloc 原型:extern void *realloc(void *mem_address, unsigned int newsize); 用法:#include <stdlib.h> 有些编译器需要#include <alloc.h> 在C++环境中,使用#include<iostream> using namespace std;功能:改变mem_address所指内存区域的大小为newsize长度. 说明:如果重新分配成功则返回指向被分配内存的指针,否则返

CSDN日报20170301——《一次dns缓存引发的惨案》

[程序人生] 一次dns缓存引发的惨案 作者:纯洁的虫子 时间2015年的某个周六凌晨5点,公司官方的QQ群有用户反馈官网打不开了,但有的用户反馈可以打开,客服爬起来自己用电脑试了一下没有问题,就给客户反馈说,可能是自己网络的问题,请过会在试试.早点8点,越来越多的用户反馈官网无法打开,并且有部分用户开发反馈app也打不开了,客服打电话叫起了还在梦乡中的我. -- 点此阅读全文 [Android 开发] Android UI性能优化 检测应用中的UI卡顿 作者:鸿洋 在做app性能优化的时候,大

一个Sqrt函数引发的血案

我们平时经常会有一些数据运算的操作,需要调用sqrt,exp,abs等函数,那么时候你有没有想过:这个些函数系统是如何实现的?就拿最常用的sqrt函数来说吧,系统怎么来实现这个经常调用的函数呢? 虽然有可能你平时没有想过这个问题,不过正所谓是"临阵磨枪,不快也光",你"眉头一皱,计上心来",这个不是太简单了嘛,用二分的方法,在一个区间中,每次拿中间数的平方来试验,如果大了,就再试左区间的中间数:如果小了,就再拿右区间的中间数来试.比如求sqrt(16)的结果,你先试

realloc函数实现数组动态增长

body { font-family: 微软雅黑,"Microsoft YaHei", Georgia,Helvetica,Arial,sans-serif,宋体, PMingLiU,serif; font-size: 10.5pt; line-height: 1.5; } html, body { } h1 { font-size:1.5em; font-weight:bold; } h2 { font-size:1.4em; font-weight:bold; } h3 { fon