在数组一章中,曾介绍过数组的长度是预先定义好的,在整个程序中固定不变。C语言中不允许动态数组类型。
例如:
int n;
scanf(“%d”,&n);
int a[n];
用变量表示长度,想对数组的大小作动态说明,这是错误的。
但是在实际的编程中,往往会发生这种情况,即所需的内存空间取决于实际输入的数据,而无法预先确定。
对于这种问题,用数组的办法很难解决。为了解决上述问题,C语言提供了一些内存管理函数,这些内存管理函数可以按需要动态地分配内存空间,也可把不再使用的空间回收待用,为有效地利用内存资源提供了手段。
常用的内存管理函数有以下三个:
1. 分配内存空间函数 malloc
调用形式:
ptr = (cast_type *) malloc (byte_size);
(类型说明符*) malloc (size)
功能:在内存的动态存储区中分配一块长度为”size”字节的连续区域。函数的返回值为该区域的首地址。“类型说明符”表示把该区域用于何种数据类型。(类型说明符*)表示把返回值强制转换为该类型指针。“size”是一个无符号数。
例如:
pc=(char *)malloc(100);
表示分配 100 个字节的内存空间,并强制转换为字符数组类型,函数的返回值为指向该字符数组的指针,把该指针赋予指针变量 pc。
2. 分配内存空间函数 calloc
calloc 也用于分配内存空间。
调用形式:
ptr = (cast_type *) calloc (n, size);
(类型说明符*)calloc(n,size)
功能:在内存动态存储区中分配 n 块长度为“size”字节的连续区域;函数的返回值为该区域的首地址;当内存空间分配后,所有字节初始化为零。
每当分配内存空间错误(例如内存不足)时,都会返回空指针。
calloc 函数与 malloc 函数的区别仅在于一次可以分配 n 块区域。
例如:
ps=(struet stu*)calloc(2,sizeof(struct stu));
其中的 sizeof(struct stu)是求 stu 的结构长度。因此该语句的意思是:按 stu 的长度分配 2 块连续区域,强制转换为 stu 类型,并把其首地址赋予指针变量 ps。
3. 释放内存空间函数 free
调用形式:
free(void*ptr);
功能:释放 ptr 所指向的一块内存空间,ptr 是一个任意类型的指针变量,它指向被释放区域的首地址。被释放区应是由 malloc 或 calloc 函数所分配的区域。
例1. – 分配一块区域,输入一个学生数据
main() { struct stu { int num; char *name; char sex; float score; } *ps; ps=(struct stu*)malloc(sizeof(struct stu)); ps->num=102; ps->name="Zhang ping"; ps->sex='M'; ps->score=62.5; printf("Number=%d\nName=%s\n",ps->num,ps->name); printf("Sex=%c\nScore=%f\n",ps->sex,ps->score); free(ps); }
本例中,定义了结构 stu,定义了 stu 类型指针变量 ps。然后分配一块 stu 结构体内存区,并把首地址赋予 ps,使 ps 指向该区域。再以 ps 为指向结构的指针变量对各成员赋值,并用printf 输出各成员值。最后用 free 函数释放 ps 指向的内存空间。
整个程序包含了申请内存空间、使用内存空间、释放内存空间三个步骤,实现存储空间的动态分配。
例2.动态分配内存空间
#include <stdlib.h> int main() { int *ptr; ptr = malloc(15 * sizeof(*ptr)); /* a block of 15 integers */ if (ptr != NULL) { *(ptr + 5) = 480; /* assign 480 to sixth integer */ printf("Value of the 6th integer is %d",*(ptr + 5)); } }
- 请注意,当以后将* ptr声明类型转换为其他数据类型时,使用sizeof(* ptr)代替sizeof(int)是为了使代码更有兼容性;
- 如果内存不足,分配可能会失败。 在这种情况下,它将返回NULL指针。 因此,您应该包括用于检查NULL指针的代码;
- 请记住,分配的内存是连续的,可以将其视为数组。 我们可以使用指针算法来访问数组元素,而不是使用方括号[]。 我们建议使用+来引用数组元素,因为使用增量++或+ =会更改指针存储的地址。
例3.用malloc分配一个整型数组指针,并赋值给第二个整数
#include <stdio.h> int main() { int* ptr = malloc(10 * sizeof(*ptr)); if (ptr != NULL) { *(ptr + 2) = 50; printf("Value of the 2nd integer is %d",*(ptr + 2)); } free(ptr); }
例4.动态分配内存实现自然数加法
#include <stdio.h> int main() { int i, * ptr, sum = 0; ptr = calloc(10, sizeof(int)); if (ptr == NULL) { printf("Error! memory not allocated."); exit(0); } printf("Building and calculating the sequence sum of the first 10 terms \ n "); for (i = 0; i < 10; ++i) { * (ptr + i) = i; sum += * (ptr + i); } printf("Sum = %d", sum); free(ptr); return 0; }
calloc与malloc:主要区别
calloc函数通常比malloc函数更合适,更高效。 虽然这两个函数都用于分配内存空间,但calloc可以一次分配多个块。 您不必每次都请求存储块。
calloc函数用于需要更大存储空间的复杂数据结构中。calloc函数分配的内存块始终初始化为零,而在malloc中,它始终包含垃圾值。
4. Realloc 函数
使用realloc()函数,可以将更多的内存大小添加到已分配的内存中。 它扩展当前块,同时保留原始内容。 realloc代表内存的重新分配。
realloc也可以用来减小先前分配的内存的大小。
语法:
ptr = realloc (ptr,newsize);
上面的语句在变量newsize中分配具有指定大小的新内存空间。 执行完函数后,指针将返回到存储块的第一个字节。 新的大小可以大于或小于以前的内存。
我们不能确定新分配的块是否将指向与先前存储块相同的位置。 此功能将在新区域中复制所有先前的数据。 它确保数据将保持安全。
例5.
#include <stdio.h> int main () { char *ptr; ptr = (char *) malloc(10); strcpy(ptr, "Programming"); printf(" %s, Address = %u\n", ptr, ptr); ptr = (char *) realloc(ptr, 20); //ptr is reallocated with new size strcat(ptr, " In 'C'"); printf(" %s, Address = %u\n", ptr, ptr); free(ptr); return 0; }
每当重新分配导致操作失败时,它都会返回空指针,并且先前的数据也将被释放。