1.为什么使用动态内存分配
答:为解决未知长度数组的相关问题
2.malloc 和 free
void *malloc(size_t size); //分配动态内存
void free(void *pointer); //释放动态内存
malloc:参数 size:需要分配的内存字节数
若成功,返回一个指向被分配的内存块(分配的是一个连续的内存,且未初始化)起始位置的指针
若失败,返回 NULL 指针
free: 参数要么是 NULL(无任何效果),要么是 malloc,calloc 或 realloc 返回的值。
3.calloc 和 realloc
void *calloc(size_t num_elements, size_t element_size);
void *realloc(void *ptr, size_t new_size);
calloc:也用于分配内存,与 malloc 的区别是其在返回指向内存的指针之前它初始化为0
参数: num_elements:元素数量, element_size:每个元素的字节数
realloc:用于修改一个原先已经分配的内存块的大小
扩大:原内容保留,新增内容放到原内存后面,并且未初始化
缩小:内存块尾去除,剩余 部分保留
若无法改变内存块大小,分配另一块正确大小的新内存,复制原内存到此内存块上。因此,在使用 realloc
之后,不能再使用旧内存指针,而应改用返回的新指针。
如果重新分配成功则返回指向被分配内存的指针,否则返回空指针NULL。
若第一个参数为 NULL,则与 malloc等效
4.使用动态内存分配
int *pi;
...
pi = malloc(100);
if (pi == NULL)
{
printf("Out of memory!\n");
exit(1);
}
如果分配成功,这块内存被当作25个整型元素的数组(设整形为4个字节),因为 pi 是一个指向整型的指针
如果目标就是获得足够存储25个整数的内存,有更好的可移植的技巧:
pi = malloc(25 * sizeof(int));
如何使用这块内存:可以使用间接访问和指针运算来访问数组的不同整数位置,和一般指针使用相同。
5.常见动态内存错误
错误包括对 NULL 指针进行解引用操作,对分配的内存进行操作时越过边界,释放并非动态分配的内存,试图释放一块动态分配的内存的一部分
以及一块动态内存被释放之后被继续使用。
内存泄漏:分配内存但在使用完毕后不释放将引起内存泄漏
6.内存分配实例
a. 读取一列数据,并按升序排列他们并打印
#include<stdlib.h>
#include<stdio.h>
int compare_integers(void const *a, void const *b)//指定排序的顺序函数
{
register int const *pa = a;
register int const *pb = b;
return *pa > *pb ? 1 : *pa < *pb ? -1 : 0;
}
int main()
{
int *array;
int n_values;
int i;
printf("How many value are there?");
if (scanf("%d", &n_values) != 1 || n_values <= 0)
{
printf("Illegal number of values.\n");
exit(EXIT_FAILURE);
}
array = malloc(n_values * sizeof(int));//分配内存
if (array == NULL)
{
printf("Can't get memory for that many values.\n");
exit(EXIT_FAILURE);
}
for (i = 0; i < n_values; i++)//读取数值
{
printf("?");
if (scanf("%d", array + i) != 1)
{
printf("Error reading value #%d\n", i);
free(array);
exit(EXIT_FAILURE);
}
}
qsort(array, n_values, sizeof(int), compare_integers);//排序(库函数)
for (i = 0; i < n_values; i++)
printf("%d\n", array[i]);
free(array);
return EXIT_SUCCESS;
}
运行:
用于保存这个列表的内存是动态分配的,这样就不必担心不知道用户希望对多少个值进行排序。他实际分配的内存就是实际需要的内存,不会造成浪费。
b. 复制字符串
#include<stdlib.h>
#include<stdio.h>
char * strdup(char const *string)
{
char *new_string;
new_string = malloc(strlen(string) + 1);
if (new_string != NULL)
strcpy(new_string, string);
return new_string;
}
strlen 不包含结束符,而 strcpy 是连同结束符 一起复制,所以这里要分配 比字符串长度多一个字节的内存,以便存储字符串结尾的NUL字节。