❤️C语言动态内存管理库函数介绍❤️(下)

简介: 大家好!在实现动态通讯录的时候,我用到了malloc 和realloc动态申请内存,所以今天我想来和大家分享有关动态内存管理函数与柔性数组的相关知识。

💐2.C语言动态内存管理库函数应用



🌿🌿2.1常见相关笔试题


💐题目一:请问运行Test 函数会有什么样的结果?

char *GetMemory(void) 
{
 char p[] = "hello world";
 return p; 
 }
void Test(void) 
{
 char *str = NULL;
 str = GetMemory();
 printf(str);
}

💐分析:程序运行极大可能打印随机值


由于p是一个局部变量,因此当其出了函数GetMemory之后就会销毁,虽然在销毁之前将地址返回给str,但str维护的是一块野指针,因此str就会非法访问内存.

这类问题属于返回栈空间地址的问题。栈空间的地址不能轻易返回,因为一旦出了作用域之后就被销毁了。


💐题目二:请问运行Test 函数会有什么样的结果?

void GetMemory(char *p)
{
 p = (char *)malloc(100);
}
void Test(void) {
 char *str = NULL;
 GetMemory(str);
 strcpy(str, "hello world");
 printf(str);
}

💐分析:程序运行打印随机值


函数GetMemory的形参为char* p,p为该函数的局部变量,作用域在函数内部,出了函数该变量就被销毁了,并且没有对申请好的内存进行释放。所以参数str传入函数GetMemory后,其值不会改变,仍为NULL,空地址是不能被用户访问修改的,因此程序崩溃。


💐题目三:请问运行Test 函数会有什么样的结果?

void GetMemory(char **p, int num) 
{
 *p = (char *)malloc(num);
}
void Test(void) 
{
 char *str = NULL;
 GetMemory(&str, 100);
 strcpy(str, "hello");
 printf(str);
}

💐分析:该程序虽然会输出hello,但是是存在内存泄漏的,因为最后并没有释放申请的内存。

正确写法应该是:

void GetMemory(char **p, int num) 
{
 *p = (char *)malloc(num);
}
void Test(void) 
{
 char *str = NULL;
 GetMemory(&str, 100);
 strcpy(str, "hello");
 printf(str);
 free(str);
 str=NULL;
}

💐题目四:请问运行Test 函数会有什么样的结果?

void Test(void) 
{
 char *str = (char *) malloc(100);
 strcpy(str, "hello");
 free(str);
 if(str != NULL)
 {
 strcpy(str, "world");
 printf(str);
 }
}

💐分析:由于free完没有置为NULL空指针,因此错误。

正确写法:

void Test(void) 
{
 char *str = (char *) malloc(100);
 strcpy(str, "hello");
 free(str);
 str=NULL;
}


🌿🌿2.2C/C++语言中的内存开辟


2f37a9c5d03949b5ba9a79bab5561453.png

栈区(stack):在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行 结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但 是分配的内存容量有限。 栈区主要存放运行函数而分配的局部变量、函数参数、返回数据、 返回地址等。


堆区(heap):一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。分

配方式类似于链表。


数据段(静态区)(static)存放全局变量、静态数据。程序结束后由系统释放。


代码段:存放函数体(类成员函数和全局函数)的二进制代码。


🌿🌿2.3柔性数组


也许你从来没有听说过柔性数组(flexible array)这个概念,但是它确实是存在的。

在C99 中,结构中的最后一个元素允许是未知大小的数组,这就叫做『柔性数组』成员。


🌺🌺🌺2.3.1柔性数组特点与使用


typedef struct st_type
{
 int i;
 int a[];  //柔性数组成员
}type_a;

💐注意事项:

  1. 结构中的柔性数组成员前面必须至少一个其他成员。
  2. sizeof 返回的这种结构大小不包括柔性数组的内存。
  3. 包含柔性数组成员的结构用malloc ()函数进行内存的动态分配,并且分配的内存应该大于结构的大
    小,以适应柔性数组的预期大小。

💐举个栗子:

typedef struct st_type
{
 int i;
 int a[0];//柔性数组成员
}type_a;
printf("%d\n", sizeof(type_a));//输出的是4

这里输出的是4,不包括柔性数组的大小。


💐为柔性数组开辟空间

int i = 0;
type_a *p = (type_a*)malloc(sizeof(type_a)+100*sizeof(int));
//业务处理
p->i = 100;
for(i=0; i<100; i++) {
 p->a[i] = i; }
free(p);

这里使用malloc为柔性数组开辟空间,100*sizeof(int)就是开辟了柔性数组的空间。

这样柔性数组成员a,相当于获得了100个整型元素的连续空间。


🌺🌺🌺2.3.2柔性数组的优点


💐第一个好处是:方便内存释放


如果我们的代码是在一个给别人用的函数中,你在里面做了二次内存分配,并把整个结构体返回 给用户。

用户调用free可以释放结构体,但是用户并不知道这个结构体内的成员也需要free,所以你不能指望用户来发现这事。如果我们把结构体的内存以及其成员要的内存一次性分配好了,并返回给用户一个结构体指针,用户做一次free就可以把所有的内存也给释放掉。


💐 第二个好处是:这样有利于访问速度.


连续的内存有益于提高访问速度,也有益于减少内存碎片。


相关文章
|
17天前
|
存储 C语言 开发者
【C语言】字符串操作函数详解
这些字符串操作函数在C语言中提供了强大的功能,帮助开发者有效地处理字符串数据。通过对每个函数的详细讲解、示例代码和表格说明,可以更好地理解如何使用这些函数进行各种字符串操作。如果在实际编程中遇到特定的字符串处理需求,可以参考这些函数和示例,灵活运用。
39 10
|
17天前
|
存储 程序员 C语言
【C语言】文件操作函数详解
C语言提供了一组标准库函数来处理文件操作,这些函数定义在 `<stdio.h>` 头文件中。文件操作包括文件的打开、读写、关闭以及文件属性的查询等。以下是常用文件操作函数的详细讲解,包括函数原型、参数说明、返回值说明、示例代码和表格汇总。
41 9
|
17天前
|
存储 Unix Serverless
【C语言】常用函数汇总表
本文总结了C语言中常用的函数,涵盖输入/输出、字符串操作、内存管理、数学运算、时间处理、文件操作及布尔类型等多个方面。每类函数均以表格形式列出其功能和使用示例,便于快速查阅和学习。通过综合示例代码,展示了这些函数的实际应用,帮助读者更好地理解和掌握C语言的基本功能和标准库函数的使用方法。感谢阅读,希望对你有所帮助!
31 8
|
17天前
|
C语言 开发者
【C语言】数学函数详解
在C语言中,数学函数是由标准库 `math.h` 提供的。使用这些函数时,需要包含 `#include <math.h>` 头文件。以下是一些常用的数学函数的详细讲解,包括函数原型、参数说明、返回值说明以及示例代码和表格汇总。
40 6
|
17天前
|
存储 C语言
【C语言】输入/输出函数详解
在C语言中,输入/输出操作是通过标准库函数来实现的。这些函数分为两类:标准输入输出函数和文件输入输出函数。
101 6
|
17天前
|
存储 缓存 算法
【C语言】内存管理函数详细讲解
在C语言编程中,内存管理是至关重要的。动态内存分配函数允许程序在运行时请求和释放内存,这对于处理不确定大小的数据结构至关重要。以下是C语言内存管理函数的详细讲解,包括每个函数的功能、标准格式、示例代码、代码解释及其输出。
47 6
|
17天前
|
C语言 开发者
【C语言】断言函数 -《深入解析C语言调试利器 !》
断言(assert)是一种调试工具,用于在程序运行时检查某些条件是否成立。如果条件不成立,断言会触发错误,并通常会终止程序的执行。断言有助于在开发和测试阶段捕捉逻辑错误。
27 5
|
25天前
|
缓存 Prometheus 监控
Elasticsearch集群JVM调优设置合适的堆内存大小
Elasticsearch集群JVM调优设置合适的堆内存大小
204 1
|
14天前
|
存储 监控 算法
深入探索Java虚拟机(JVM)的内存管理机制
本文旨在为读者提供对Java虚拟机(JVM)内存管理机制的深入理解。通过详细解析JVM的内存结构、垃圾回收算法以及性能优化策略,本文不仅揭示了Java程序高效运行背后的原理,还为开发者提供了优化应用程序性能的实用技巧。不同于常规摘要仅概述文章大意,本文摘要将简要介绍JVM内存管理的关键点,为读者提供一个清晰的学习路线图。
|
23天前
|
Java
JVM内存参数
-Xmx[]:堆空间最大内存 -Xms[]:堆空间最小内存,一般设置成跟堆空间最大内存一样的 -Xmn[]:新生代的最大内存 -xx[use 垃圾回收器名称]:指定垃圾回收器 -xss:设置单个线程栈大小 一般设堆空间为最大可用物理地址的百分之80