初夏小談:記憶體管理之常見記憶體錯誤(重點乾貨)
想來說說記憶體管理已經好長時間了,但是不知如何較好的表達。整理了幾天,來給大家分享這種底層問題。
學好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
珍&原始碼