C语言动态数组建立方法
动态数组是指在声明时没有确定数组大小的数组,即忽略圆括号中的下标;当要用它时,可随时用ReDim语句(C语言中用malloc语句)重新指出数组的大小。使用动态数组的优点是可以根据用户需要,有效利用存储空间。
为什么要使用动态数组?
在实际的编程中,往往会发生这种情况,即所需的内存空间取决于实际输入的数据,而无法预先确定。对于这种问题,用静态数组的办法很难解决。为了解决上述问题,C语言提供了一些内存管理函数,这些内存管理函数结合指针可以按需要动态地分配内存空间,来构建动态数组,也可把不再使用的空间回收待用,为有效地利用内存资源提供了手段。
动态数组与静态数组的对比
对于静态数组,其创建非常方便,使用完也无需释放,要引用也简单,但是创建后无法改变其大小是其致命弱点! 对于动态数组,其创建麻烦,使用完必须由程序员自己释放,否则严重会引起内存泄露。但其使用非常灵活,能根据程序需要动态分配大小。 如何构建动态数组
遵循原则
申请的时候从外层往里层,逐层申请; 释放的时候从里层往外层,逐层释放。
构建所需指针
对于构建一维动态数组,需要一维指针; 对于二维,则需要一维,二维指针; 三维需要一,二,三维指针; 依此类推。
构建所需函数
函数原型 | 返 回 | 功能说明 |
void *malloc(unsigned int size); |
成功:返回所开辟 空间首地址 失败:返回空指针 |
向系统申请 size字节的 堆空间 |
void *calloc(unsigned int num, unsigned int size); |
成功:返回所开辟 空间首地址 失败:返回空指针 |
按类型申请 num个size字 节的堆空间 |
void free(void *p); | 无返回值 |
释放p指向 的堆空间 |
void *realloc(void *p,unsigned int size); |
成功:返回新开辟 空间首地址 失败:返回空指针 |
将p指向的 堆空间变为 size |
说明:
(1)规定为void *类型,这并不是说该函数调用后无返回值,而是返回一个结点的地址,该 地址的类型为void(无类型或类型不确定),即一段存储区的首址,其具体类型无法确定,只有使 用时根据各个域值数据再确定。可以用强制转换的方法将其转换为别的类型。例如:double *pd=NULL; pd=(double *)calloc(10,sizeof(double)); 表示将向系统申请10个连续的 double类型的存储空间,并用指针pd指向这个连续的空间的首地址。并且用(double)对calloc( ) 的返回类型进行转换,以便把double类型数据的地址赋值给指针pd。 (2)使用sizeof的目的是用来计算一种类型的占有的字节数,以便适合不同的编译器。 (3)由于动态分配不一定成功,为此要附加一段异常处理程序,不致程序运行停止,使用户 不知所措。通常采用这样的异常处理程序段: if(p==NULL) { printf("动态申请内存失败!\n"); exit(1); //异 常退出 } (4)这四个函数头文件均包含在<stdlib.h>中。 (5)分配的堆空间是没有名字的 只能通过返回的指针找到它。 (6)绝不能对非动态分配存储块使用free。也不能对同一块内存区同时用free释放两次。 如:free(p);free(p); (7)调用 free() 时, 传入指针指向的内存被释放, 但调用函数的指针值可能保持不变, 因 为p是作为形参而传递给了函数。严格的讲, 被释放的指针值是无效的, 因为它已不再指向所申请 的内存区。这时对它的任何使用便可能会可带来问题。 malloc与calloc的区别 对于用malloc分配的内存区间,如果原来没有被使用过,则其中的每一位可能都是0;反之, 如果这部分内存空间曾经被分配、释放和重新分配,则其中可能遗留各种各样的数据。也就是说, 使用malloc()函数的程序开始时(内存空间还没有被重新分配)能正常运行,但经过一段时间后(内 存空间已被重新分配)可能会出现问题,因此在使用它之前必须先进行初始化(可用memset函数 对其初始化为0),但调用calloc()函数分配到的空间在分配时就已经被初始化为0了。 当你在calloc()函数和malloc()函数之间作选择时,你需考虑是否要初始化所分配的内存空 间,从而来选择相应的函数。
具体构建方法
以三维整型数组array[n1][n2][n3]为例。 先遵循从外层到里层,逐层申请的原则: 最外层指针是array,它是个三维指针,所指向的是array[],其为二维指针。所以给array 申请内存应: array=(int***)calloc(n1,sizeof(int**)); 次层指针是array[],它是个二维指针,所指向的是array[][],其为一维指针。所以给array[] 申请内存应: for(i=0;i<n1;i++) { array[i]=(int**)calloc(n2,sizeof(int*)); } 最内层指针是array[][],它是个一维指针,所指向的是array[][][],其是个整型常量。所 以给array[][]申请内存应: for(i=0;i<n1;i++) { for(j=0;j<n2;j++) { array[i][j]=(int*)calloc(n3,sizeof(int)); } } 当然,你可以把它们整合在一起为: int i,j,k; int n1,n2,n3; int ***array; scanf("%d%d%d",&n1,&n2,&n3); array=(int***)calloc(n1,sizeof(int**)); for(i=0;i<n1;i++) { array[i]=(int**)calloc(n2,sizeof(int*)); for(j=0;j<n2;j++) { array[i][j]=(int*)calloc(n3,sizeof(int)); for(k=0;k<n3;k++) { array[i][j][k]=i+j+k+1; } } } 最后不要忘了释放这些内存,这要遵循释放的时候从里层往外层,逐层释放的原则。 分析过程可参考上面的解答,这里不再赘述。只给出代码吧: for(i=0;i<n1;i++) { for(j=0;j<n2;j++) { free(array[i][j]);//释放第三维指针 } } for(i=0;i<n1;i++) { free(array[i]);//释放第二维指针 } free(array);//释放第一维指针 其余维的如四维创建过程大同小异,这里不再赘述。
基础概念
C#集合、C#动态数组的概念之集合,什么是集合呢?集合就如同数组,用来存储和管理一组特定类型的数据对象,除了基本的数据处理功能,集合直接提供了各种数据结构及算法的实现,如队列、链表、排序等,可以让你轻易地完成复杂的数据操作。在使用数组和集合时要先加入system.collections命名空间,它提供了支持各种类型集合的接口及类。集合本身上也是一种类型,基本上可以将其作为用来存储一组数据对象的容器,由于c#面向对象的特性,管理数据对象的集合同样被实现成为对象,而存储在集合中的数据对象则被称为集合元素。这里提到了接口这个概念,它也是面向对象编程进化的重要标准,我们在这里不做过多的讲解,先注重学习集合中的对象及其使用就可以了,下面我们来学习第一种集合: C#集合、C#动态数组的概念之C#动态数组ArrayList.ArrayList 类提供了继承了IList接口。什么是继承呢?这也是面向对象语言的重要特点之一,现在你们先把它理解为,如果一个对象继承了类或接口,那么它也具有了这个类和接口中的方法、属性,可以用这些继承的方法和属性来做相应的操作,比如:数组增加元素没有Add()方法,但是动态数组ArrayList继承了一个增加元素有Add()方法的接口,那么当它要增加元素的时候,不仅可以用索引,也可以用继承下来的Add()方法了。随着学习的深入,我会给大家再具体讲解继承的概念和使用继承的好处。那么下面让我们来看看动态数组所继承的这个接口IList它有什么特性呢? C#动态数组之 Ilist接口:定义了利用索引访问集合对象的方法,还继承了ICollection和IEnumerable接口,除实现了接口原有的方法成员外,其本身也定义多个专门的方法成员,例如新增、移除、在指定位置插入元素或是返回特定元素在集合中所在的位置索引,这些方法主要为集合对象提供类似数组的元素访问功能。 C#动态数组之ILsit接口成员:add、insert、RemoveAt、Remove、contains、Clear、indexof方法,它最大的特色在于提供类似数组索引的访问机制。 C#集合、C#动态数组的概念的基本情况就向你介绍到这里,希望对你了解和学习C#集合、C#动态数组的概念有所帮助。
构建实例
一维
#include <stdio.h> #include <stdlib.h> int main() { int n1,i; int *array; puts("输入一维长度:"); scanf("%d",&n1); array=(int*)malloc(n1*sizeof(int));//第一维 for(i=0;i<n1;i++) { array[i]=i+1; printf("%d\t",array[i]); } free(array);//释放第一维指针 return 0; }
二维
#include <stdlib.h> #include <stdio.h> int main() { int n1,n2; int **array,i,j; puts("输入一维长度:"); scanf("%d",&n1); puts("输入二维长度:"); scanf("%d",&n2); array=(int**)malloc(n1*sizeof(int*)); //第一维 for(i=0;i<n1; i++) { array[i]=(int*)malloc(n2* sizeof(int));//第二维 for(j=0;j<n2;j++) { array[i][j]=i+j+1; printf("%d\t",array[i][j]); } puts(""); } for(i=0;i<n1;i++) { free(array[i]);//释放第二维指针 } free(array);//释放第一维指针 return 0; }
三维
#include <stdlib.h> #include <stdio.h> int main() { int n1,n2,n3; int ***array; int i,j,k; puts("输入一维长度:"); scanf("%d",&n1); puts("输入二维长度:"); scanf("%d",&n2); puts("输入三维长度:"); scanf("%d",&n3); array=(int***)malloc(n1*sizeof(int**));//第一维 for(i=0; i<n1; i++) { array[i]=(int**)malloc(n2*sizeof(int*)); //第二维 for(j=0;j<n2;j++) { array[i][j]=(int*)malloc(n3*sizeof(int)); //第三维 for(k=0;k<n3;k++) { array[i][j][k]=i+j+k+1; printf("%d\t",array[i][j][k]); } puts(""); } puts(""); } for(i=0;i<n1;i++) { for(j=0;j<n2;j++) { free(array[i][j]);//释放第三维指针 } } for(i=0;i<n1;i++) { free(array[i]);//释放第二维指针 } free(array);//释放第一维指针 return 0; }
四维
#include <stdlib.h> #include <stdio.h> int main() { int n1,n2,n3,n4; int ****array; int i,j,k,m; puts("输入一维长度:"); scanf("%d",&n1); puts("输入二维长度:"); scanf("%d",&n2); puts("输入三维长度:"); scanf("%d",&n3); puts("输入四维长度:"); scanf("%d",&n4); array=(int****)malloc(n1*sizeof(int***));//第一维 for(i=0; i<n1; i++) { array[i]=(int***)malloc(n2*sizeof(int**)); //第二维 for(j=0;j<n2;j++) { array[i][j]=(int**)malloc(n3*sizeof(int*)); //第三维 for(k=0;k<n3;k++) { array[i][j][k]=(int*)malloc(n4*sizeof(int));//第四维 for(m=0;m<n4;m++) { array[i][j][k][m]=i+j+k+m+1; printf("%d\t",array[i][j][k][m]); } puts(""); } puts(""); } puts(""); } for(i=0;i<n1;i++) { for(j=0;j<n2;j++) { for(k=0;k<n3;k++) free(array[i][j][k]);//释放第四维指针 } } for(i=0;i<n1;i++) { for(j=0;j<n2;j++) { free(array[i][j]);//释放第三维指针 } } for(i=0;i<n1;i++) { free(array[i]);//释放第二维指针 } free(array);//释放第一维指针 return 0; }
数组案例
#include <stdio.h> #include <stdlib.h> int main() { int*n,*p; int i; n=(int*)calloc(1,sizeof(int)); for(i=0;i<5000;i++) { n[i]=i+1; printf("%d\t",n[i]); p=(int*)realloc(n,(i+2)*sizeof(int));//动态扩充数组 if(p!=NULL) n=p; else { puts("error!"); return 0; } } free(n); return 0; }
游戏应用
预备知识
(1)getch() 函数原型: int getch(void); 函数功能: 从控制台读取一个字符,但不显示在屏幕上。 函数返回: 读取的字符。 (2)rand() 函数原型: int rand(void); 函数功能: 随机函数, 产生0到32767间的随机整数(0到0x7fff之间)。 函数返回: 随机整数 所属文件: <stdlib.h> (3)srand() 函数原型: void srand(unsigned seed); 函数功能: 该函数和rand随机函数配合使用,产生随机数的起始发生数据。 参数说明: seed为无符号整数。 所属文件: <stdlib.h> (4)time() 函数原型: time_t time(time_t *timer) 函数功能: 得到机器的日历时间或者设置日历时间。 函数返回: 机器日历时间。 参数说明: timer=NULL时得到机器日历时间,timer=时间数值时,用于设置日历时间, time_t是一个long类型。 所属文件: <time.h> (5)'\b'实现退格,即当前光标后退一格。 (6)'\a'实现响铃,即执行时计算机会嘟一声。 (7)得到随机数值范围在a~b(包含b)的方法:rand()%(b-a+1)+a;
代码
#include <stdio.h> #include <conio.h>//getch()函数所需头文件 #include <stdlib.h>//随机函数所需头文件 #include <time.h>//time()函数所需头文件 void clear(void)//此函数用以清除当前行 { printf("\r \r"); } void start(void) { puts("这是消单词游戏的精简版,还不会图像编程的人可以看一看"); puts(" 由于没有引人数据库,所以此单词是模拟的。"); puts("按任意键开始,按Esc键结束,按tab键重新开始:"); puts(" 一旦输错,将发出声音警告,你必须重新输入。"); puts(" 按任意键开始,按Esc键结束:"); if( '\x1b' == getch() ) //按Esc键结束 { exit( 1 ); } } int main() { char*c_rand,*c_input; int i,j,N,n,space,N_rand; start(); printf("\r你想消最多由多少个字母组成的单词?(输入数字(1-9)"); n=getch(); N=n-'0';//将输入的字符转换为整型数字 clear();//清除当前行 if(!((N>=1&&N<=9)||n==27))//27是键Esc的ASII值 { printf("\r范围错误,请重新开始:"); getch(); exit(1);//异常退出 } if(n==27) return 0; srand(time(NULL));//用来对随机函数初始化 c_rand=(char*)malloc(N+1); c_input=(char*)malloc(N+1); while(1) { N_rand=rand()%N+1;//实现单词长度随机定义 for(i=0;i<N_rand;i++) { c_rand[i]=(rand() ==0)?(rand()&+'A'):(rand()&+'a');//随机取个字母 } c_rand[N_rand]='\0'; //下面四行代码实现单词位置随机出现 space=rand()P; putchar('\r'); for(i=0;i<space;i++) putchar(' '); printf("%s",c_rand); for(i=0;i<N_rand;i++) { c_input[i]=getch();//用户输入 if(c_input[i]=='\x1b')//"\x1b"代表的是Esc键 break; //下面五行代码实现字母消失效果 putchar('\r'); for(j=0;j<space;j++) putchar(' '); for(j=0;j<=i;j++) putchar(' '); if(c_input[i]!=c_rand[i]) { i=-1; putchar('\a'); //下面四行代码代码字母重现效果 putchar('\r'); for(j=0;j<space;j++) putchar(' '); printf("%s",c_rand); } } if(c_input[i]=='\x1b')//"\x1b"代表的是Esc键 break; } free(c_rand); free(c_input); return 0;
}
转:http://blog.sina.com.cn/s/blog_7414b2930100v20t.html
C语言动态数组建立方法相关推荐
- c语言 头文件定义数组,C语言动态数组
动态数组是指在声明时没有确定数组大小的数组,即忽略方括号中的下标:当要用它时,可随时用ReDim语句(C语言中用malloc语句)重新指出数组的大小. 中文名 C语言动态数组 释 义 相对于静态 ...
- java封装数组_Java封装数组之动态数组实现方法详解
本文实例讲述了Java封装数组之动态数组实现方法.分享给大家供大家参考,具体如下: 前言:在此之前,我们封装的数组属于静态数组,也即数组空间固定长度,对于固定长度的数组当元素超过容量时会报数组空间不足 ...
- c语言动态数组的创建
用变量n如何创建a[n]呢? 首先,对于动态数组,大多数人初学时可能是这种情况: scanf("%d",&n); int a[n]; 当然,这种方法是不对的. 因为在程序运 ...
- C语言——动态数组的创建和使用
C语言文章更新目录 C语言学习资源汇总,史上最全面总结,没有之一 C/C++学习资源(百度云盘链接) 计算机二级资料(过级专用) C语言学习路线(从入门到实战) 编写C语言程序的7个步骤和编程机制 C ...
- c语言 动态数组_C语言的学习笔记!助你一路成长!
1.C语言中函数参数传递是按照"值传递"进行的,即单向传递. 2.函数原型:函数类型 函数名(参数类型,参数类型--),可以不必加参数名,因为操作系统不检查参数名. 3.数组作为实 ...
- C语言动态数组的两种定义方式
动态内存分配具有非常多的好处,可以最大化的节约内存空间的大小.本文将通过两种方式来实现C语言中内存的动态分配,希望你看完本文后能有所收获. 一.直接对数组大小进行输入 在C99标准中C语言数组已支 ...
- C语言动态数组(malloc()函数动态分配内存)
malloc()函数简介 头文件:<stdlib.h> 或者 <malloc.h>. 函数声明: void *malloc( int size ); 用法: (分配类型 * ) ...
- 基于动态数组建立二叉堆、批量建堆-JAVA
文章目录 1.堆的数据结构 2.添加 3.删除 4.代码实现 1.首先定义接口 2.写实现类 5.如何批量建堆 1.堆的数据结构 如果任意节点的值总是≥子节点的值,称为:最大堆.大根堆.大顶堆 如果任 ...
- c语言如何生成字符型动态数组,C语言构建动态数组完整实例
C语言构建动态数组完整实例 本文以一个完整的实例代码简述了C语言构建动态数组的方法,供大家参考,完整实例如下: #include #include int main(void) { int len; ...
最新文章
- 【微服务】Spring-Boot整合Consul (自定义服务配置及健康检查)
- 做砸数据中台项目的9种方法
- C#测试数据库连接是否成功
- C++ 大话数据结构 09: 中缀表达式 转后缀表达式 计算器
- 测试使用wiz来发布blog
- Oracle查询表结果添加到另一张表中
- C++--第1课 - C到C++的升级
- network secruity studay day3
- 显卡更新后重启计算机就没了,在windows10系统更新显卡后黑屏的解决方法
- 数据库原理-并发控制(2-封锁)
- 论剑大数据技术,效率为王!天善智能掘金数据技术沙龙【上海站 12.09】
- MySQL InnoDB 存储引擎写入磁盘(落盘)的原理\MySQL怎么保证持久性、原子性?(MySQL中是如何实现事务提交和回滚的)\隔离性
- PGSQL创建管理员账号
- RetinaNet模型在DDSM数据集的应用问题(2)
- ABP理论学习之数据过滤器
- 「BZOJ4763」雪辉
- 瘫痪患者借助脑机接口可进行数字绘画
- Python机器学习入门笔记(1)—— Scikit-learn与特征工程
- 打开5555调试端口
- 一文读懂堡垒机对企业信息安全起到的重要作用
热门文章
- 如何从使用环境上区别光纤收发器?
- 【渝粤教育】电大中专Office办公软件 (4)作业 题库
- 低功耗远距离lora模块:SX1262与SX1278、SX1276射频无线收发器芯片对比分析以及选型指南
- AC-DC电源模块设计原理及10个常见疑问
- mysql autoenlist默认_mysql连接参数详解
- 01_2_数字基带传输及其频谱特性
- 一建机电实务教材电子版_必背!一建《机电实务》高频考点,每日一背
- 基于wincc的虚拟电梯设计_一文带你了解西门子整个虚拟调试与仿真软硬件体系...
- hiti打印机android驱动,HiTi 打印机 驱动程序下载——更新 HiTi 软件
- android webview javascript不执行,WebView中的JavaScript为什么不执行?