网站建设关键词排名优化,上海人才网站官网入口,袜子技术支持深圳网站建设,福州seo代理计费一、什么是内存的动态分配
全局变量分配在内存中的静态存储区。局部变量#xff08;包括形参#xff09;分配在内存中的动态存储区#xff0c;这个存储区是一个称为栈的区域。除此之外#xff0c;C语言还允许建立内存动态分配区域#xff0c;以存放一些临时用的数据…一、什么是内存的动态分配
全局变量分配在内存中的静态存储区。局部变量包括形参分配在内存中的动态存储区这个存储区是一个称为栈的区域。除此之外C语言还允许建立内存动态分配区域以存放一些临时用的数据这些数据不必在程序的声明部分定义也不必等到函数结束时才释放而是需要时随时开辟不需要时随时释放。这些数据是存放在一个特别的自由存储区称为堆区。可以根据需要向系统申请所需大小的空间。由于未在声明部分定义它们为变量或数组因此不能通过变量名或数组名去引用这些数据只能通过指针来引用。 也就是说全局变量分配于静态存储区局部变量分配于栈动态内存分配在堆。
二、怎样建立内存的动态分配
对于内存的动态分配是通过系统提供的库函数来实现的主要有malloccallocreallocfree这四个函数。
1.用malloc函数开辟动态内存
malloc的函数原型为
void *malloc(unsigned int size);malloc函数的作用是 在内存的动态存储区中分配一个长度为size的连续空间。形参size的类型定为无符号整型不允许为负数。此函数的值即“返回值”是所分配区域的第一个字节的首地址或者说此函数是一个指针型函数返回的指针指向该分配域的第一个字节。如
malloc(100);
//开辟100字节的临时分配域函数值为其第一个字节的地址。注意指针的基类型为void即不指向任何类型的数据只提供一个地址。如果此函数未能成功执行例如内存空间不足则返回空指针NULL失败只有一种情况就是申请的内容太大超出堆能提供的最大连续空间。
2.用calloc函数开辟动态内存
calloc的函数原型为
void*calloc(unsigned n,unsigned size);calloc的函数的作用是 在内存的动态存储区中分配n个长度为size的连续空间这个空间一般比较大足以保存一个数组。 用calloc函数可以为一维数组开辟动态内存存储空间n为数组元素个数每个元素长度为size。这就是动态数组。函数的指针指向所分配域的第一个字节此函数的值即“返回值”是所分配区域的第一个字节的首地址如果不成功返回空指针NULL。如
pcalloc(50,4);
//开辟50个长度为4个字节的临时分配域把首地址赋给指针变量pcalloc和malloc最大的区别为申请完空间之后calloc会将每个元素的值直接置为0。
3.用realloc函数重新分配动态内存
realloc函数的原型
void *realloc(void*p,unsigned int size);参数的意义p:旧内存的地址size:新申请的内存大小以字节为单位 realloc函数的作用是 如果已经通过malloc函数或calloc函数获得了动态内存空间想改变其大小可以用realloc函数重新分配。用realloc函数将p所指向的动态内存空间的大小改变为size。p的值不变。函数值成功返回时返回新的动态内存的首地址如果重分配不成功返回空指针NULL。失败只有一种情况就是申请的内容太大超出堆能提供的最大连续空间。如
realloc(p,50);
//将p指向的动态内存空间的大小改变为50字节用malloc实现realloc扩容
#include stdio.h
#include stdlib.h
#include assert.h
int main()
{int n 10;int *p(int*)malloc(n * sizeof(int));assert(p ! NULL);int i;for (i 0; i n; i){p[i] i;}for (i 0; i n; i){printf(%d , p[i]);}printf(\n);//1发现p申请的太少于是重新申请int*q(int *)malloc(2* n * sizeof(int));//1申请新内存//2搬家for (i 0; i 2*n; i){q[i] i;}for (i 0; i 2*n; i){printf(%d , q[i]);}free(p);//3释放p的内存p q;//4接收新内存q NULL;//...后面可以继续使用preturn 0;
}realloc实现扩容
#include stdio.h
#include stdlib.h
#include assert.h
int main()
{int n 10;int* p (int*)malloc(n * sizeof(int));assert(p ! NULL);int i;for (i 0; i n; i){p[i] i;}for (i 0; i n; i){printf(%d , p[i]);}printf(\n);//1发现p申请的太少于是重新申请p (int*)realloc(p, 2 * n * sizeof(int));for (i 0; i 2 * n; i){p[i] i;}//2搬家for (i 0; i 2 * n; i){printf(%d , p[i]);}//...后面可以继续使用pfree(p);return 0;
}4.用free函数释放动态存储区
free函数的原型
void freeviod*p;free函数的作用是 释放指针变量p所指向的动态内存空间使这部分空间能重新被其他变量使用。p应是最近一次调用calloc或malloc函数时得到的函数返回值。free函数无返回值。如
free(p);
//释放指针变量p所指向的已分配的动态内存空间free崩溃的原因 1.p移动了p因为申请p的时候有一个n的大小如果p移动找不到头信息 2.找不到尾信息 3.重复释放了一段内存
以上4个函数malloccallocreallocfree的声明都在stdlib.h的头文件中在用到这些函数时应该用#includestdlib.h指令把stdlib.h头文件包含在程序文件中。
三、void指针类型
C99允许使用基类型为void的指针类型。可以定义一个基类型为void的指针变量即void*型变量它不指向任何类型的数据。 注意不要把“指向void类型”理解为能指向“任何类型”的数据而应理解为“指向空类型”或“不指向确定的类型”的数据。在将它的值赋给另一指针变量时由系统对它进行类型转换使之适合于被赋值的变量的类型。 例如
int main()
{int a 3; //定义a为整型变量int* p1 a;//p1指向int型变量char* p2;//p2指向char型变量void* p3;//p3为无类型指针变量基类型为void型p3 (void*)p1;//将p1的值转换为void*类型然后赋值给p3p2 (char*)p3;//将p3的值转换为char*类型然后赋值给p2printf(%d, *p1);//合法输出整型变量a的值void* p3 a; printf(%d, *p3);//错误p3是无指向的不能指向a
}说明 地址信息应该包含位置信息和基类型的信息。 一定要注意基类型的信息即存放存放在以此地址标志的存储单元中的数据类型否则无法实现对数据的存取。所以对于void*类型的指针这种指针无指向在这种无指向的地址所标志的存储单元中是不可以存储任何数据的也就是说无法通过这种地址对内存存取数据。 什么情况下会用到void*类型的指针 在调用动态存储分配函数如malloc、calloc、realloc函数时会用到void*类型的指针。用户用这些函数开辟动态存储区时希望获得此动态存储区的起始地址以便利用该动态存储区。 C99规定malloc、calloc、realloc函数返回void*指针使其“无指向”这种指针称为“空类型指针”它不指向任一种具体的数据类型只提供一个地址。这是C有关地址应用的一种特殊情况。 这种空类型指针在形式上和其他指针一样遵循C语言对指针的有关规定它也有基类型只是它的基类型是void可以这样定义
void*p; //定义p是void*型的指针变量void*型指针代表“无指向的地址”这种指针不指向任何类型的数据。不能企图通过它存取数据在程序中它只是过渡性的只有转换为有指向的地址才能存取数据。
四、建立动态内存分配区和使用void指针
【例题】建立动态数组输入5个学生的成绩另外用一个函数检查其中有无低于60分的输出不合格的成绩。 【思路】用malloc开辟一个动态自由区域用来存放5个学生的成绩会得到这个动态域的第一个字节的地址他的基类型是void型。用一个基类型是int的指针变量p来指向动态数组的各元素并输出它们的值。但必须先把malloc函数返回的void指针转换为整型指针然后赋给p1。
#include stdio.h
#include stdlib.h //程序中用了malloc函数应包含stdlib.h
void check(int* p)//定义check函数形参是int*指针
{printf(不合格的成绩为);for (int i 0; i 5; i){if (p[i] 60)printf(%d , p[i]);//输出不合格成绩}printf(\n);
}
int main()
{int* p1 (int*)malloc(5 * sizeof(int)); //p1是int型指针开辟动态内存将地址转换为int*型然后放在p1中for (int i 0; i 5; i){scanf(%d, p1[i]);//输入5个学生的成绩}check(p1);//调用check函数free(p1);return 0;
}五、断言assert
一种比较保守的编程方式每一次都要验证动态申请内存的返回值是否为空这里就需要用到断言assertassert函数的声明都在assert.h的头文件中在用到这个函数时应该用#includeassert.h指令把assert.h头文件包含在程序文件中。 【例题】输出n个连续自然数中的所有素数
void Getprimer(int n)
{int* p (int*)malloc(n * sizeof(int));//堆assert(p ! NULL);for (int i 0; i n; i){p[i] 1;}p[1] p[0] 0;//0和1不是素数for (int i 2; i n; i){for (int j i 1; j n; j){if (j % i 0)p[j] 0;}}for (int i 2; i n; i){if (p[i] 1){printf(%d是素数\n, i);}}free(p);
}
int main()
{int n;printf(请输入n的大小);scanf(%d, n);Getprimer(n);return 0;
}