1. 程式人生 > >初夏小談:記憶體管理之常見記憶體錯誤(重點乾貨)

初夏小談:記憶體管理之常見記憶體錯誤(重點乾貨)

想來說說記憶體管理已經好長時間了,但是不知如何較好的表達。整理了幾天,來給大家分享這種底層問題。

學好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

                                                                                                                                                          珍&原始碼