跳至主要內容

06-内存管理

AI悦创原创C教程C教程大约 10 分钟...约 3047 字

1. 内存管理

1.1 内存管理

了解内存是 C 语言编程的一个重要方面。当你使用基本数据类型声明一个变量时,C 语言会自动在一个叫做的内存区域为该变量分配空间。

例如,一个 int 变量,在声明时通常分配4个字节。我们通过使用 sizeof 运算符获取某个变量的字节大小:

Code1
int x;
printf("%d", sizeof(x)); /* output: 4 */

再比如,一个指定大小的数组分配在一个连续的内存块,每个块的大小为一个元素的大小:

Code1
int arr[10];
printf("%d", sizeof(arr)); /* output: 40 */

只要你的程序明确声明了基本数据类型或数组大小,内存就会自动管理。然而,你可能经希望实现一个数组大小在运行时才动态分配大小的程序。

动态内存分配是根据需要分配和释放内存的过程。现在你可以在运行时提示数组元素的数量,然后创建一个指定大小的数组。

动态内存是用指针管理的,指针指向一个叫做的区域中新分配的内存块。

除了使用堆栈的自动内存管理和使用堆的动态内存分配外,在主内存中还有静态管理的数据,用于在程序的生命周期内持续存在。

1.2 动态内存分配是?

A. 根据需要分配和释放内存的过程

B. 定义数组的过程

C. 声明函数指针的过程

A

1.3 内存管理函数

stdlib.h 库包括内存管理函数。 在你的程序顶部的语句#include <stdlib.h>能够访问以下函数:

  • malloc(bytes) 返回一个指向连续内存块的指针,该内存块的大小为bytes。
  • calloc(num_items, item_size) 返回一个指向具有 num_items项的连续内存块的指针,每个项的大小为item_size字节。通常用于数组,结构和其他派生数据类型。分配的内存被初始化为0。
  • realloc(ptr, bytes)ptr指向的内存大小调整为字节大小。新分配的内存未初始化。
  • free(ptr) 释放ptr指向的内存块。

当你不再需要一个分配的内存块时,使用函数 free() 释放,之后该内存块可再次分配使用。

填空,引入可访问内存管理函数的头文件:

___include <___.h>

#

stdlib

2. malloc 和 free 函数

2.1 malloc 函数

malloc() 函数在内存中分配指定数量的连续字节

例如:

Code1
#include <stdlib.h>

int *ptr;
/* a block of 10 ints */
ptr = malloc(10 * sizeof(*ptr));

if (ptr != NULL) {
  *(ptr + 2) = 50;  /* assign 50 to third int */
}

填空,分配 10 个字节的大小的内存:

int* ptr = ___(10);

malloc

2.2 malloc 函数

分配内存是连续的,可以作为一个数组对待。不使用括号[ ]来访问元素,而是使用指针运算来遍历数组。建议你使用+来迭代数组元素。使用 +++= 可以更改指针所存储的地址。

如果分配不成功,则返回 NULL。因此,你应该包含用于检查 NULL 指针的代码。

一个简单的二维数组需要 (rows*columns)*sizeof(datatype)字节的内存。

分配的内存为:

A. 随机分布的

B. 连续的

B

2.3 free 函数

free() 函数是一个内存管理函数,它用来释放内存。通过释放内存,可以腾出更多的内存供以后的程序使用。

例如:

Code1
int* ptr = malloc(10 * sizeof(*ptr));
if (ptr != NULL)
  *(ptr + 2) = 50;  /* assign 50 to third int */
printf("%d\n", *(ptr + 2));

free(ptr);

填空,分配内存,然后释放由 malloc() 分配的内存:

int ___ ptr = malloc(10);
___ (ptr);

*

free

3. calloc 和 realloc 函数

3.1 calloc 函数

calloc() 函数根据特定项(例如结构体)的大小分配内存。

下面的程序使用 calloc 为结构分配内存,并使用 malloc 为结构中的字符串分配内存:

Code1
typedef struct {
  int num;
  char *info;
} record;

record *recs;
int num_recs = 2;
int k;
char str[ ] = "This is information";

recs = calloc(num_recs, sizeof(record));
if (recs != NULL) {
  for (k = 0; k < num_recs; k++) {
    (recs+k)->num = k;
    (recs+k)->info = malloc(sizeof(str));
    strcpy((recs+k)->info, str);
  }
} 

calloc 在一个连续的内存块为结构体元素的数组分配内存块。你可以用指针运算从一个结构体指向到下一个结构体。

在为一个结构体分配空间后,必须为结构体内的字符串分配内存。

动态分配的结构是链表二叉树以及其他数据结构的基础。

填空,为 3 个 recssord 结构分配内存:

typedef struct {
  int num;
  char *info;
} record;
___ *recs;
recs = ___(3, ___(record))

record

calloc

sizeof

3.2 realloc 函数

realloc(void *__ptr, size_t __size):更改已经配置的内存空间,即更改由 malloc() 函数分配的内存空间的大小。

如果将分配的内存减少,realloc 仅仅是改变索引的信息。

如果是将分配的内存扩大,则有以下情况:

1)如果当前内存段后面有需要的内存空间,则直接扩展这段内存空间,realloc() 将返回原指针。

2)如果当前内存段后面的空闲字节不够,那么就使用堆中的第一个能够满足这一要求的内存块,将目前的数据复制到新的位置,并将原来的数据块释放掉,返回新的内存块位置。

3)如果申请失败,将返回 NULL,此时,原来的指针仍然有效。

Code1
int *ptr;
ptr = malloc(10 * sizeof(*ptr));  
if (ptr != NULL) {
  *(ptr + 2) = 50;  /* assign 50 to third int */
}
ptr = realloc(ptr, 100 * sizeof(*ptr)); 
*(ptr + 30) = 75; 

realloc 将原始内容保留在内存中,并扩展该块以允许更多存储。

下面代码的输出是哪一项?

int *arr = malloc(sizeof(int));
*arr = 13;
arr = realloc(arr, 2*sizeof(int));
*(arr + 1) = *arr;
printf("%d", *(arr + 1));

A. 0

B. 13

C. 未知

D. 14

B

4. 动态字符串及数组

4.1 为字符串分配内存

在为字符串指针分配内存时,你可能需要使用字符串长度而不是 sizeof 运算符来计算字节。

例如:

Code1
char str20[20];
char *str = NULL;

strcpy(str20, "12345");
str = malloc(strlen(str20) + 1); 
strcpy(str, str20);
printf("%s", str); 

这种方法可以更好地管理内存,因为你分配的空间不会超出指针所需的空间。

当使用 strlen 确定字符串所需的字节数时,请确保为 NULL 字符 \0 添加一个额外的字节。

char 始终是一个字节,因此无需将内存需求乘以 sizeof(char)

填空,为 str 字符串分配 42 个字节:

___  *str = NULL;
str = ___ (42);

char

malloc

4.2 动态数组

许多算法实现了动态数组,因为这允许元素的数量根据需要增加。

由于不会一次分配所有元素,因此动态数组通常使用一种结构来跟踪当前数组的大小,当前容量以及指向元素的指针,如以下程序所示:

Code1
typedef struct {
  int *elements;
  int size;
  int cap;
} dyn_array;

dyn_array arr;

/* initialize array */
arr.size = 0;
arr.elements = calloc(1, sizeof(*arr.elements) );
arr.cap = 1;  /* room for 1 element */ 

要扩展更多元素:

Code1
arr.elements = realloc(arr.elements, (5 + arr.cap) * sizeof(*arr.elements));
if (arr.elements != NULL)
  arr.cap += 5; /* increase capacity */ 

向数组添加元素会增加其大小:

Code1
if (arr.size < arr.cap) {
  arr.elements[arr.size] = 50;
  arr.size++;
} else {
  printf("Need to expand the array.");
}

为了演示,整个程序写在 main() 中。为了正确实现动态数组,应该把子任务分解成 init_array()increase_array()add_element()display_array() 等函数。为了保持演示的简短,错误检查也被跳过了。

填空,为 int 数组分配内存,然后为更多元素扩展内存。

___* arr = malloc(4 * sizeof(int));
arr = ___(arr, 8 * sizeof(int));

int

realloc

5. 小测验

5.1 练习-1

填空,分配 10 字节内存:

int* mem = ___(___);

malloc

10

5.2 练习-2

为值 42 的整数分配内存,并打印:

int* ptr = ___(sizeof(int));
___= 42;
printf("%d", *ptr);

malloc

*ptr

5.3 练习-3

使用 calloc() 函数为 2 个 time 结构体分配内存:

typedef struct {
  int minutes;
  int hours;
} time;
time *tm = ___(2, sizeof___));

calloc

time

5.4 练习-4

填空,为一个 20 个字符的字符串分配内存,并为该字符串赋值:

char* str ____ malloc(20);
strcpy(___, "Hello, SoloLearn!");

=

str

5.5 练习-5

填空,创建并初始化一个动态数组:

int* arr = ___(10 * sizeof(int));
for (int i = 0; i < 10; ++i) {
  ___(arr + i) = i;
}

malloc

*

公众号:AI悦创【二维码】

AI悦创·编程一对一

AI悦创·推出辅导班啦,包括「Python 语言辅导班、C++ 辅导班、java 辅导班、算法/数据结构辅导班、少儿编程、pygame 游戏开发、Linux、Web、Sql」,全部都是一对一教学:一对一辅导 + 一对一答疑 + 布置作业 + 项目实践等。当然,还有线下线上摄影课程、Photoshop、Premiere 一对一教学、QQ、微信在线,随时响应!微信:Jiabcdefh

C++ 信息奥赛题解,长期更新!长期招收一对一中小学信息奥赛集训,莆田、厦门地区有机会线下上门,其他地区线上。微信:Jiabcdefh

方法一:QQopen in new window

方法二:微信:Jiabcdefh

上次编辑于:
贡献者: AndersonHJB
你认为这篇文章怎么样?
  • 0
  • 0
  • 0
  • 0
  • 0
  • 0
评论
  • 按正序
  • 按倒序
  • 按热度