想来说说内存管理已经好长时间了,但是不知如何较好的表达。整理了几天,来给大家分享这种底层问题。
学好C语言就要学好内存管理。那么内存分为那几个区呢?
先来说说内存中大致的这几个区:栈区,堆区,全局变量区,和代码区。
栈区:就是用来保存局部变量。栈上的内容只在函数的范围内存在,当函数运行完毕后,这些内容就被自动销毁。
优点:效率高
缺点:空间大小有限,比如内存是8G的话栈所拥有的空间仅仅在1M到几M之间,不同机器可能有所差别,但栈着实内存很小。
堆区:就是由malloc系列函数或new操作符分配的内存。其生命周期由free或delete决定,在没有释放之前一直存在,直到程序结束。
优点:使用灵活。空间相当大,一个8G内存,堆一般占据了7G多。
缺点:容易出错。比如没有及时free会导致内存泄漏,不要以为分配的那么一点点内存无所谓,这在几天或者长达几个月的不停息的服务器程序上跑,将会异常危险。
全局区:就是存放全局变量和静态变量的区域。当然常量字符串也保存在此。全局变量区的内容在整个程序的生命周期内都存在,它由编译器在编译的时候分配。
代码区:就是存放代码的区域。
接下来说说内存错误的几种问题
第一种:定义了指针变量,却没有为指针分配内存,就是指针没有指向一块合法的内存。
来看看这个例子:
#define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> #include<string.h> void Test1() { typedef struct stu { char* name; int score; }stu; stu student, *ptr; strcpy(student.name, "Jack"); student.score = 90; } int main() { Test1(); system("pause"); return 0; }
在定义结构体指针ptr时只为它分配了4个字节,指针name指向了一个非法的地址。指针内部存储着可能是一些乱码,拷贝这个字符串的话,就是把字符串往乱码所指向的内存上拷贝。这块内存name指针根本无权访问。办法就是为name分配一块内存。
那么改成这样呢?
#define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> #include<string.h> void Test1_1() { typedef struct stu { char* name; int score; }stu; stu student, *ptr; ptr = (stu*)malloc(sizeof(stu));//为结构体分配一块内存空间 strcpy(ptr->name, "Jack"); student.score = 90; printf(ptr->name); free(ptr); ptr = NULL; } int main() { Test1_1(); system("pause"); return 0; }
小可爱们是不是可以了呢?很抱歉它还是有问题,其关键在于它还是没有为name指针指向分配一块内存。不要被malloc蒙蔽了眼睛。她的确是为结构体分配一块空间,但并没有为结构体成员指针分配空间。那么应该怎么做呢?看看下面代码
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//解决上述问题
void Test1_2()
{
typedef struct stu
{
char* name;
int score;
}stu;
stu *ptr;
ptr = (stu*)malloc(sizeof(stu));//为结构体分配一块内存空间
ptr->name = (char*)malloc(sizeof(stu));//为结构体指针name分配一块内存空间
strcpy(ptr->name, "Jack");
printf(ptr->name);
free(ptr);
}
int main()
{
Test1_2();
system("pause");
return 0;
}
OK,为结构体成员name指针分配了一块内存终于可以,存放“Jack”了哈哈,细心地小可爱发现没有,我没有释放那块内存空间,这就存在问题,内存泄漏。好了再free前面再加一个并且置空,第二个free也要置空就OK了,粗心的小伙伴注意了。想要源码的伙伴们请搜索
https://github.com/AventadorSQ/zhen_yuanma/commit/b1a3b4caccbb71801cf4ed9022b6d4fce7c34d90
珍&源码