零基础学网站建设网络服务商分为哪几类
web/
2025/10/5 0:43:51/
文章来源:
零基础学网站建设,网络服务商分为哪几类,网站适配手机怎么做,吉林省吉林市地图相关代码gitee自取#xff1a;C语言学习日记: 加油努力 (gitee.com)
接上期#xff1a;
学C的第三十一天【通讯录的实现】_高高的胖子的博客-CSDN博客 1 . 为什么存在动态内存分配 学到现在认识的内存开辟方式有两种#xff1a; 创建变量#xff1a; int val …
相关代码gitee自取C语言学习日记: 加油努力 (gitee.com) 接上期
学C的第三十一天【通讯录的实现】_高高的胖子的博客-CSDN博客 1 . 为什么存在动态内存分配 学到现在认识的内存开辟方式有两种 创建变量 int val 20; —— 在栈空间上开辟4个字节 创建数组 char arr[10] {10}; —— 在栈空间上开辟10个字节的连续空间 上述的开辟空间的方式有两个特点 空间开辟大小是固定的。 数组在声明的时候必须指定数组的长度它所需要的内存在编译时分配。 但是对于空间的需求不仅仅是上述的情况。 有时候我们需要的空间大小在程序运行的时候才能知道 那数组的编译时开辟空间的方式就不能满足了。 这时候就只能试试动态内存开辟了。 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 2 . 动态内存函数的介绍 1. malloc 和 free malloc : 该函数是一个动态内存开辟的函数 这个函数可以向内存申请一块连续可用的空间 并返回指向这块空间的指针。 书写格式如下 void* malloc (size_t size); 如果开辟成功则返回一个指向开辟好空间的指针。 如果开辟失败则返回一个NULL指针因此malloc的返回值一定要做检查。 返回值的类型是 void* 所以malloc函数并不知道开辟空间的类型具体在使用的时候使用者自己决定。 如果参数 size 为0malloc的行为是标准是未定义的取决于编译器。 malloc声明在 stdlib.h 头文件中。 示例 free : malloc函数申请的内存空间在程序退出时才会还给操作系统 如果程序不退出动态申请的内存是不会主动释放的。 所以需要 free函数 来释放动态内存。 书写格式如下 void free (void* ptr); 如果参数 ptr 指向的空间不是动态开辟的那free函数的行为是未定义的。 如果参数 ptr 是NULL指针则函数什么事都不做。 free声明在 stdlib.h 头文件中。 示例 2. calloc 书写格式如下 void* calloc (size_t num, size_t size); 函数的功能是以 num 个大小为 size 的元素开辟一块空间并且把空间的每个字节初始化为0。 如果我们对申请的内存空间的内容要求初始化那么可以很方便的使用calloc函数来完成任务。 与函数 malloc 的区别只在于 calloc 会在返回地址之前把申请的空间的每个字节初始化为全0。 calloc 声明在 stdlib.h 头文件中。 示例 3. realloc realloc函数的出现让动态内存管理更加灵活。 有时会我们发现过去申请的空间太小了有时候我们又会觉得申请的空间过大了 那为了合理地使用内存我们一定会对内存的大小做灵活的调整。 那 realloc 函数就可以做到对动态开辟内存大小的调整。 书写格式如下 void* realloc (void* ptr, size_t size); ptr 是要调整的内存地址如果填的是NULL空指针那会开辟一块新的空间跟malloc函数一样。 size 是调整之后新大小 返回值 为调整之后的内存起始位置。 这个函数在调整原内存空间大小的基础上还会将原来内存中的数据移动到新的空间。 realloc在调整内存空间的是存在两种情况 情况1 -- 原有空间之后有足够大的空间 在这种情况下要扩展内存就直接在原有内存之后直接追加空间 原来空间的数据不发生变化。 情况2 -- 原有空间之后没有足够大的空间 在这种情况下扩展的方法是在堆空间上另找一个合适大小的连续空间来使用 将旧的空间中的数据拷贝到新的空间中再释放旧的空间最后返回新空间的起始地址。 这样函数返回的就是一个新的内存地址。 realloc 声明在 stdlib.h 头文件中。 示例 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 3 . 常见的动态内存错误 1. 对NULL指针的解引用操作 malloc、calloc、realloc函数 都可能开辟空间 开辟空间就有可能会失败返回 NULL空指针 这时解引用该空指针就可能会出问题。 示例 2. 对动态开辟空间的越界访问 示例 3. 对非动态开辟内存使用free函数释放 示例 4. 使用free函数释放一块动态开辟内存的一部分 使用动态空间过程中 改变了指向动态空间的指针 这时要使用free函数释放空间就会出问题。 示例 5. 对同一块动态内存多次释放 可以在释放动态空间后 将该空间指针设置为空指针 防止多次释放。 示例 6. 动态开辟内存忘记释放 -- 内存泄漏 只有两种方式可以对动态内存进行释放 free函数 和 程序运行结束 所以如果 忘记释放 或 没释放且程序无法结束 就会造成内存泄漏。 示例 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 4 . 相关经典笔试题 题一 进行修改 对应代码 //1:改前
#include stdio.h
#include stdlib.h
#include string.hvoid GetMemory(char* p)
{//开辟动态空间p (char*)malloc(100);
}void Test(void)
{//创建空指针char* str NULL;//使用该指针进行动态内存开辟GetMemory(str);//对动态空间赋值并使用strcpy(str, hello world);printf(str);}int main()
{Test();return 0;
}//1:改后
#include stdio.h
#include stdlib.h
#include string.hvoid GetMemory(char** p)
{//开辟动态空间*p (char*)malloc(100);
}void Test(void)
{//创建空指针char* str NULL;//使用该指针进行动态内存开辟GetMemory(str);//对动态空间赋值并使用strcpy(str, hello world);printf(str);//使用后进行释放free(str);str NULL;
}int main()
{Test();return 0;
} 题二 进行修改 对应代码 //2:改前
#include stdio.h
#include stdlib.hchar* GetMemory(void)
{char p[] hello world;return p;
}void Test(void)
{//创建空指针char* str NULL;//调用上面的函数str GetMemory();printf(str);
}int main()
{Test();return 0;
}//2:改后
#include stdio.h
#include stdlib.hchar* GetMemory(void)
{static char p[] hello world;return p;
}void Test(void)
{//创建空指针char* str NULL;str GetMemory();printf(str);
}int main()
{Test();return 0;
}题三 进行修改 对应代码 //3改前
#include stdio.h
#include stdlib.hvoid GetMemory(char** p, int num)
{//根据需求创建动态空间*p (char*)malloc(num);
}void Test(void)
{//创建空指针变量char* str NULL;//调用函数GetMemory(str, 100);//使用动态空间strcpy(str, hello);printf(str);
}int main()
{Test();return 0;
}//3改后
#include stdio.h
#include stdlib.hvoid 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;
}int main()
{Test();return 0;
} 题四 进行修改 对应代码 //4改前
#include stdio.h
#include stdlib.hvoid Test(void)
{//创建动态空间并接收char* str (char*)malloc(100);//使用动态空间strcpy(str, hello);//释放free(str);if (str ! NULL){strcpy(str, world);printf(str);}
}int main()
{Test();return 0;
}//4改后
#include stdio.h
#include stdlib.hvoid Test(void)
{//创建动态空间并接收char* str (char*)malloc(100);//使用动态空间strcpy(str, hello);//释放free(str);str NULL;if (str ! NULL){strcpy(str, world);printf(str);}
}int main()
{Test();return 0;
} ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 . C/C程序的内存开辟 1. C/C程序内存区域划分 C/C程序内存分配的几个区域 1. 栈区stack 在执行函数时函数内局部变量的存储单元都可以在栈上创建 函数执行结束时这些存储单元自动被释放。 栈内存分配运算内置于处理器的指令集中效率很高但是分配的内存容量有限。 栈区主要存放运行函数而分配的局部变量、函数参数、返回数据、返回地址等。 2. 堆区heap 一般由程序员分配释放 若程序员不释放 程序结束时可能由OS操作系统回收 。 分配方式类似于链表。 3. 数据段静态区static 存放全局变量、静态数据。程序结束后由系统释放。 4. 代码段 存放函数体类成员函数和全局函数的二进制代码。 图示 有了这幅图 我们就可以更好的理解static关键字修饰局部变量的例子了。 实际上普通的局部变量是在栈区分配空间的 栈区的特点是在上面创建的变量出了作用域就销毁。 但是被static修饰的变量存放在数据段静态区 数据段的特点是在上面创建的变量直到程序结束才销毁 所以生命周期变长。 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 6 . 柔性数组 C99中结构体中最后一个元素允许是未知大小的数组这就叫做柔性数组成员。 实例 1. 柔性数组的特点 结构体中的柔性数组成员前面必须至少有一个其他成员。 sizeof 返回的这种结构体大小不包括柔性数组的内存。 包含柔性数组成员的结构体用malloc ()函数进行内存的动态分配 并且分配的内存应该大于结构的大小以适应柔性数组的预期大小。 实例 2. 柔性数组的使用 实例 3. 柔性数组的优势 方便内存释放 如果我们的代码是在一个给别人用的函数中 你在里面做了二次内存分配使用两次malloc函数可以实现类似柔性数组的效果 并把整个结构体返回给用户 用户调用free可以释放结构体但是用户并不知道这个结构体内的成员也需要free 所以你不能指望用户来发现这个事。 所以如果我们把结构体的内存以及其成员要的内存一次性分配好了 并返回给用户一个结构体指针 用户做一次free就可以把所有的内存也给释放掉。 有利于访问速度 连续的内存有益于提高访问速度 也有益于减少内存碎片两个开辟的空间中间空余的内存。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/87066.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!