7.1 存储管理函数
Last updated
Was this helpful?
Last updated
Was this helpful?
Dynamic memory management
学习步骤:
2023-11-23 周四
2024-03-24 Upload
malloc()
函数是 C 语言中用于动态分配内存的函数之一,它允许在程序运行时按需请求指定大小的内存空间。这个函数位于 <stdlib.h>
头文件中。
malloc()
函数的基本用法:参数: size
参数表示要分配的内存大小,以字节为单位。返回类型是 void*
,即指向分配内存起始位置的指针。
返回值: 如果内存分配成功,返回指向分配内存的指针;如果分配失败,则返回 NULL
。
检查分配是否成功: 始终检查 malloc()
返回的指针是否为 NULL
,以确保内存分配成功。
释放动态分配的内存: 使用 free()
函数释放通过 malloc()
分配的内存,避免内存泄漏。
类型转换: 在 C++ 中,不需要显式类型转换 malloc()
返回的指针,而在 C 中需要进行显式类型转换。
malloc()
是动态内存分配中最基本和常用的函数之一,但在使用时需要小心管理内存,避免内存泄漏和指针操作错误。随后的 C 标准引入了更多安全和方便的内存管理函数,如 calloc()
和 realloc()
,它们可以更好地满足不同的需求。
当你使用 malloc()
分配了内存后,你可以将这块内存用于存储数据或进行其他操作。以下是一个示例,演示了如何正确分配内存并使用指针进行操作:
int *ptr = (int *)malloc(10 * sizeof(int));: 使用 malloc() 函数分配了足够存储 10 个整数的内存空间,并将分配得到的地址赋值给了 ptr 指针。这行代码中的 (int *) 是一种类型转换,将 malloc() 返回的 void* 类型指针强制转换为 int* 类型指针。
在这个示例中,我使用 malloc()
分配了足够存储 10 个整数的内存空间,并用 memcpy()
将数组 arr
的内容复制到了动态分配的内存中。然后通过循环打印了动态分配内存中的内容,最后使用 free()
释放了分配的内存。
这个例子展示了如何正确分配和使用动态内存。记得在不再需要动态分配的内存时使用 free()
函数来释放它,以免出现内存泄漏问题。
分配给一块空间,用,用完没有还,。 用去图书馆借书的例子理解, 借了,看完了,没还,别人也借不了。 然后我一直不还, 对图书馆来说,相当于书丢了,这就是“内存泄漏”。
开辟过程:
这段代码的作用是演示了动态内存的使用过程:
内存复制: 使用 memcpy()
函数将数组 arr
中的内容复制到了动态分配的内存空间中,这样就把静态数组 arr
中的数据复制到了动态分配的内存中的位置 ptr
。
打印动态分配内存中的内容: 通过循环遍历动态分配内存中的内容,并使用 printf()
函数输出每个元素的值。
释放动态分配的内存: 最后使用 free()
函数释放了动态分配的内存。这一步非常重要,因为在不再需要动态分配内存时,应该及时释放它,以免造成内存泄漏。
将指针置为 NULL: 将指针 ptr
置为 NULL
是一种良好的习惯,可以避免出现悬空指针。悬空指针是指已经释放的内存却没有将指针设置为 NULL
,这样的指针可能会导致程序错误的操作。
这段代码是一个简单的示例,展示了动态内存分配、使用和释放的基本流程。在实际编程中,使用动态内存时需要确保适当地分配和释放内存,避免内存泄漏和悬空指针的问题。
生成随机字符串: 这个例子对malloc的运用就很到位
https://cplusplus.com/reference/cstdlib/malloc/
rand()%26+'a'
是一个生成随机小写字母的表达式。让我解释一下:
rand()
函数返回一个介于 0 和 RAND_MAX
之间的随机整数值。RAND_MAX
是 <stdlib.h>
头文件中定义的一个常量,表示 rand()
函数能够生成的最大随机数值。
rand()%26
使用取余操作符 %
将 rand()
生成的随机整数限制在 0 到 25 之间。因为 % 26
可以得到 0 到 25 的余数。
'a'
是字符 'a' 的 ASCII 值。在 ASCII 表中,小写字母 'a' 对应的 ASCII 值为 97。
所以,rand()%26+'a'
的含义是:生成一个 0 到 25 的随机整数,然后加上 ASCII 值 97(即小写字母 'a' 的 ASCII 值),得到的结果是一个随机小写字母的 ASCII 值。这个值会被存储在 buffer[n]
中,实现了生成随机小写字母的目的。
这段代码是一个简单的示例,用于生成随机字符串。
printf ("How long do you want the string? ");
: 打印提示消息,询问用户希望生成的随机字符串的长度。
scanf ("%d", &i);
: 从用户输入中读取一个整数,存储到变量 i
中,表示用户期望生成的字符串长度。
buffer = (char*) malloc (i+1);
: 使用 malloc()
函数分配了 i+1
大小的内存空间,存储字符的缓冲区。为了存储字符串结束符 \0
,分配的大小比用户输入的长度多了一个字符位置。buffer
指针指向这块分配的内存空间。
if (buffer==NULL) exit (1);
: 检查 malloc()
是否成功分配了内存。如果 buffer
是 NULL
,意味着分配失败,程序将以错误码 1 退出。
for (n=0; n<i; n++) buffer[n]=rand()%26+'a';
: 使用循环生成随机字符并存储在 buffer
指向的内存中。这里利用 rand()
函数生成一个 0 到 25 的随机数,加上字符 'a',以便生成小写字母(ASCII 值从 97 到 122)。
buffer[i]='\0';
: 在生成随机字符后,手动添加字符串结束符 \0
,确保生成的内容构成一个以 \0
结尾的字符串。
printf ("Random string: %s\n",buffer);
: 使用 %s
格式化符号将生成的随机字符串打印到控制台上。
free (buffer);
: 使用 free()
函数释放了动态分配的内存,以免造成内存泄漏。
这个程序演示了如何动态分配内存,并在内存中生成随机字符串。在实际使用时,为了确保安全,应该考虑更多边界情况和错误处理,比如输入检查、内存分配失败时的应对等。
sizeof(int)
就是表示整型 4
p==NULL
表示 是否是悬空指针, 有没有申请成功,失败就结束 。return 1
。
这个示例演示了使用 calloc() 函数分配了 n 个整数大小的内存空间,然后打印了分配的内存中的内容。由于 calloc() 分配的内存会初始化为零,所以在打印内容之前,所有的元素都应该是零。
这段代码是一个基本的示例,展示了 calloc() 函数的用法。在实际使用时,可以根据需求修改分配的内存空间的类型和大小,并根据需要进行更复杂的操作。记得在不再需要动态分配的内存时,使用 free() 函数释放它,避免内存泄漏问题。
让我解释下每行代码的作用:
printf("Content of allocated memory:\n");: 打印消息,说明即将输出分配的内存空间的内容。
for (int i = 0; i < n; ++i) { printf("%d ", ptr[i]); }: 这个 for 循环遍历了动态分配的内存空间,依次输出每个元素的值。ptr[i] 表示指针 ptr 指向的动态分配内存空间中第 i 个元素的值。
printf("\n");: 在 for 循环结束后,打印一个换行符,将输出的内容放在新的一行。
整个代码块的目的是,利用循环遍历打印了动态分配的内存空间中的内容,展示了 calloc() 函数初始化分配内存为零的特性。
calloc 函数的典型用法, 就这样记住就行。
memset() 常用于将数组或其他内存块的一部分或全部内容设置为特定的值,比如清空数组、初始化某些数据结构等。
由于 value 参数是以整数形式给出的,因此将会被转换为 unsigned char 类型,所以可以用任何 unsigned char 类型表示的值来填充内存块,如 0、'A'、'*' 等。
尽管 memset() 函数返回 void* 类型的指针,但它实际上没有返回值。
ptr:指向之前由 malloc()、calloc() 或 realloc() 返回的内存块的指针。如果 ptr 是 NULL,则 realloc() 的行为类似于 malloc(size)。
size:需要重新分配的内存块的新大小(以字节为单位)。
当在代码中加入数组时,我们可以利用 realloc()
函数动态调整数组的大小。以下是一个示例,展示了如何动态增加数组的长度:
这个示例展示了如何在初始分配了一定大小的内存后,使用 realloc()
函数动态地调整数组的大小。在实际使用中,你可以根据需求动态改变数组的大小,使其适应不同的场景和需求。值得注意的是,realloc()
可能会涉及内存的重新分配和数据的拷贝,所以在使用时需要注意内存分配失败的情况,并确保操作前后正确管理内存。
realloc
在申请空间的时候,
情况一,覆盖到别人的空间: 情况一比较复杂
怎么办?
找一块新的满足要求的空间, 第一步讲原来的值复制到新的空间去。 多的扩容的空间留着不用,返回的时候,直接返回新的地址。
可以看到这里,realloc 没有使用 p来进行接收,这就是因为,如果内存申请失败,p指向申请的这块地址的时候,申请失败,指不过来, 那天之前的地址,可能会“失忆”,有风险。
这就ok了,做一个中间转换,
情况二,后面没人用,直接增加。情况二是简单的。