整型的不定输入之静态数组与动态内存管理

前言:

本篇文章讨论的不定输入,是旨在研究“任意个数的字符或整型都可以被成功读取,并存放在数组中”。也就是想输入多少就输入多少,且成功读取的 “输入方式”。

在前文中我们,探讨了字符了字符字符的不定输入,以下为链接:

字符的不定输入之正则输入和gets( )函数-CSDN博客文章浏览阅读75次,点赞3次,收藏2次。本篇文章讨论的不定输入,是旨在研究“任意个数的字符或整型都可以被成功读取,并存放在数组中”。也就是想输入多少就输入多少,且成功读取的 “输入方式”。https://blog.csdn.net/Isaiah_Cohen/article/details/136415024?spm=1001.2014.3001.5501那么该怎么完成整型的不定输入呢?今天,我们就关于这个做一个简单的分析。

闲言少叙,书归正传,我们来看一看代码。

一、静态数组

代码
int main()
{
	int a[70];
	int size=0;
	char ch;
	do{
		scanf("%d",&a[size++]);
	}while((ch=getchar())!='\n');
	for(int i=0;i<size;i++)
	{
		printf("%d ",a[i]);
	}
	return 0;
}
基本思路:

首先,我们预估一个大致的容量,比如上述代码中的“70”,就是预估出来的大小。有了预估的容量之后,我们需要定义一个size,来表示数组中元素的多少。当每读取一个整型字符,变量size++,时刻保证size与数组元素个数的一致相等。

此外,由于scanf("%d",&a[size++])只能读取整型,输入的空格和换行符'\n',被保留在缓存区中,所以基于此我们可以定义一个字符变量 ch=getchar( ),读取缓存区中的空格和换行符。

若是空格则继续读取,若为换行符则结束循环。

不过,要值得注意的是,因为getchar( )和scanf( )读取字符都是按照顺序一次读取,所以必须利用do…while循环,后置判断。如果是先前置判断,那么数字就会提前被getchar( )读取,造成数据丢失。

可是,提前预估一个数组大小不可避免地会造成误差。可能会造成空间的浪费或者空间不足的情况发生,那么我们该如何防止这样的惨剧发生呢?哎!要是数组能动起来就好了,于是我们想到了动态内存管理。

二、动态内存管理

代码
int main(){
	int count=1;
	int size=0;
	char ch;
	int* arr=(int*)malloc(sizeof(int)*count);
	do{
		if(size==count){
			int newCount=count*2;
			int* tmp=(int*)realloc(arr,newCount*sizeof(int));
			if(tmp==NULL){
				printf("%s\n",strerror(errno));
				exit(-1);
			}
			else{
				arr=tmp;
				count=newCount;
			}
		}
		scanf("%d",&arr[size++]);
	}while((ch=getchar())!='\n');
	printf("%d",count);
	free(arr);
	arr=NULL;
	return 0;
}

首先我们先了解一下里面提到动态内存相关的库函数。

malloc( ) 

头文件:#include<stdlib.h> 或者 #include<malloc.h>

原型

extern void * malloc(unsigned int num_byte)
  • 功能:分配长度为num_byte字节的内存块
  • 参数:需要分配的内存字节数,如果内存池中的可用内存可以满足这个需求,malloc就返回一个指向被分配的内存块起始位置的指针
  • 返回值:如果分配成功则返回指向被分配内存的指针,否则返回空指针NULL 

知道了这个,我们来拆分相关的上述代码吧 !

int count=1;
int* arr=(int*)malloc(sizeof(int)*count);

malloc向系统申请分配指定 sizeof(int)*count 个字节的内存空间,也就是可以存放一个元素的连续空间。此外,malloc返回的指针类型是void *类型。void *类型表示未确定类型的指针。因此,C、C++规定,void *类型可以强制转换为任何其他类型的指针。所以,在这里相当于创建了一个数组名为arr,大小为1 的整型数组只不过,这个数组大小被改变。

realloc( )

头文件:#include<stdlib.h>

原型 

void* realloc(void* memblock, size_t size)
  • 功能:将原先memblock处的空间扩展到 size大小。
  • 参数:memblock是先前开辟的内存块的指针(也就是malloc或calloc之前申请的那块内存空间,即需要调整大小的内存空间)size_t size指的是New size in bytes,新的字节数,注意不是增加的字节数,而是新开辟的那块内存空间的字节数。
  • 返回值:为调整之后的内存的起始地址,如果后续的内存能够满足开辟那么就返回原地址,如果不满足开辟,则将原来的数据复制到新地址中,并将新地址返回,如果开辟失败就返回空指针NULL。
if(size==count)
{
	int newCount=count*2;
	int* tmp=(int*)realloc(arr,newCount*sizeof(int));
	if(tmp==NULL)
	{
		printf("%s\n",strerror(errno));
		exit(-1);
	}
	else
	{
		arr=tmp;
		count=newCount;
	}
}

当数组的元素数量size与我们所开辟的内存相等时,我们就需要开辟新空间进行扩容。

我们定义了一个newCount = count*2,表示新开辟空间的大小。

然后, realloc(arr,newCount*sizeof(int))表示将原来的空间扩增到原来的两倍,由于realloc函数返回的指针类型为viod*,所以我们要将他强制转化成 int*,存放到整型指针tmp中。

那么问题来了,既然realloc有可能返回原地址,那我们为什么不直接用原指针存储呢?

arr=(int*)realloc(arr,newCount*sizeof(int))

其实,使用tmp接收是有一定道理的。因为,如果开辟失败,用arr接收返回NULL就将原本的指针内容清零,arr就再也找不回原来的数据。也就是说原来开辟的空间没有被释放就与arr断开连接这样无疑对计算机会造成不可逆转的伤害。放在tmp中就可以检验tmp是否为空指针,不会对原来的数据造成威胁。

 接下来我们来认识一下如果是空指针该怎么办。

代码

if(tmp==NULL)
{
	printf("%s\n",strerror(errno));
	exit(-1);
}
else
{
	arr=tmp;
	count=newCount;
}

strerror( )

头文件:#include<string.h>和#include<errno.h>

 原型

char * strerror ( int errnum );
  • 功能:我们可以使用strerror函数来获取与指定错误码相对应的错误消息字符串,当程序出现错误时,对了解错误的具体信息、调试和修复问题至关重要。
  • 参数:errnum参数是一个表示错误码的整数值。
  • 返回值:strerror函数会返回一个指向错误消息字符串的指针。这个指针指向的字符串通常是一个静态的字符串常量,因此不应该尝试修改它。 
errno 

Linux中系统调用的错误都存储于errno中,errno由操作系统维护,存储就近发生的错误,即下一次的错误码会覆盖掉上一次的错误。

头文件:#include<errno.h>

用于表示最近一个函数调用是否产生了错误。若为0,则无错误,其它值均表示一类错误。

exit( ) 

头文件:#include<stdlib.h>

原型 

void exit(int status)
  • 功能:用于退出程序的函数 
  • 参数:exit(0),即status=0,表示正常退出,相当于return 0;其余,status为其他值时,均表示异常退出,此外,值得注意的是,括号内的参数都将返回给作系统。

接下来,我们再回到代码中吧! 

if(tmp==NULL)
{
	printf("%s\n",strerror(errno));
	exit(-1);
}
else
{
	arr=tmp;
	count=newCount;
}

当扩容失败,tmp指针为空指针时,strerror(errno)返回错误的原因,并将其打印再操作台上,并exit(-1),退出程序。 当扩容成功检查不为空指针后,将扩容后的数组大小,赋给arr,并将新扩充的容量,赋给count,这样以方便后续读取和判断元素个数与数组容量是否相等。

  • 35
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值