欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C語言 動態(tài)內(nèi)存開辟常見問題解決與分析流程

 更新時間:2022年03月16日 10:26:00   作者:K穩(wěn)重  
動態(tài)內(nèi)存是相對靜態(tài)內(nèi)存而言的。所謂動態(tài)和靜態(tài)就是指內(nèi)存的分配方式。動態(tài)內(nèi)存是指在堆上分配的內(nèi)存,而靜態(tài)內(nèi)存是指在棧上分配的內(nèi)存

前言

當我們用動態(tài)內(nèi)存分配函數(shù)來編寫程序時,在編寫的過程中常常會產(chǎn)生一些不易被察覺,被發(fā)現(xiàn)的錯誤,例如對NULL指針的解引用操作,對動態(tài)開辟空間的越界訪問,使用free釋放非動態(tài)開辟的空間,使用free釋放動態(tài)內(nèi)存中的一部分,對同一塊動態(tài)開辟的空間,多次釋放,動態(tài)開辟空間忘記釋放。下面我們挨個來分析,刨析一下這些個常見的動態(tài)內(nèi)存開辟的問題。

一、動態(tài)內(nèi)存錯誤

1.對NULL指針的解引用操作

代碼如下(示例):

錯誤示例:
//動態(tài)內(nèi)存開辟
int main()
{
 
	int* p = malloc(100000000000);
	//沒有對mollac函數(shù)的返回值做判空處理
		int i = 0;
	for (i = 0; i < 10; i++)
	{
		*(p + i) = 5;
	}
	
	return 0;
}
 
正確示例:
//動態(tài)內(nèi)存開辟
int main()
{
 
	int* p = malloc(100000000000);
	if (p == NULL)
	{
		return 1;
	}
		int i = 0;
	for (i = 0; i < 10; i++)
	{
		*(p + i) = 5;
	}
	for (i = 0; i < 10; i++)
	{
		printf("%d ", p[i]);
	}
	free(p);
	p = NULL;
	return 0;
}

2.對動態(tài)開辟空間的越界訪問

代碼如下(示例):

錯誤示例:
//動態(tài)內(nèi)存開辟
int main()
{
 
	int* p = (int*)malloc(10*sizeof(int));
	if (p == NULL)
	{
		return 1;
	}
		int i = 0;
		//越界訪問
	for (i = 0; i < 40; i++)//malloc函數(shù)只是開辟了十個整型的空間,這里卻要訪問四十個元素。
	{
		*(p + i) = 5;
	}
	for (i = 0; i < 40; i++)
	{
		printf("%d ", p[i]);
	}
	free(p);
	p = NULL;
	return 0;
}
 
正確示例:
//動態(tài)內(nèi)存開辟
int main()
{
 
	int* p = (int*)malloc(10*sizeof(int));
	if (p == NULL)
	{
		return 1;
	}
		int i = 0;
		
	for (i = 0; i < 10; i++)
		*(p + i) = 5;
	}
	for (i = 0; i < 10; i++)
	{
		printf("%d ", p[i]);
	}
	free(p);
	p = NULL;
	return 0;
}

3.使用free釋放非動態(tài)開辟的空間

代碼如下(示例):

//動態(tài)內(nèi)存開辟
int main()
{
	int arr[10] = { 0 };//棧區(qū)
	int* p = arr;
	free(p);//使用free釋放非動態(tài)開辟的空間
	p = NULL;
	return 0;
}

4.使用free釋放動態(tài)內(nèi)存中的一部分

代碼如下(示例):

 
//動態(tài)內(nèi)存開辟
int main()
{
	int* p = malloc(10 * sizeof(int));
	if (p == NULL)
	{
		return 1;
	}
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		*p++ = i;//1:p一直往后走之后沒人知道起始空間的位置在哪,2:p釋放的只是后面空間的一部分,前面的空間并沒有得到釋放。
	}
	free(p);
	p = NULL;
	return 0;
}

5.對同一塊動態(tài)內(nèi)存動態(tài)開辟的空間多次釋放

代碼如下(示例):

//動態(tài)內(nèi)存開辟
int main()
{
	int* p = malloc(10 * sizeof(int));
	//使用
	//釋放
	free(p);
	//再次釋放
	free(p);//free要是傳的是空指針什么事都不會發(fā)生。
	p = NULL;
	return 0;
}

6.動態(tài)開辟的空間忘記釋放(容易造成內(nèi)存泄露,比較嚴重)

代碼如下(示例):

void test()
{
	int* p = malloc(10 * sizeof(int));
	if (p == NULL)
	{
		return 1;
	}
	//使用
	//忘記釋放
}
 
//動態(tài)內(nèi)存開辟
int main()
{
	test();
	return 0;
}

二、動態(tài)內(nèi)存錯誤面試題分析

1.NULL指針傳參不取地址傳的也是一份臨時拷貝

例題分析:
 
void 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;
}

程序運行結果:

拷貝不成功,程序直接掛掉。

原因分析:

str傳給GetMemory函數(shù)的時候是值傳遞,所以GetMemory函數(shù)的形參p是str的一份臨時拷貝。
在GetMemory函數(shù)內(nèi)部動態(tài)申請空間的地址,存放在P中,不會影響外面str,所以當GetMemory函數(shù)返回
之后,str任然是NULL指針,所以strcpy會失敗。
當GetMemory函數(shù)返回之后,形參p銷毀,使得動態(tài)開辟的100個字節(jié)存在內(nèi)存泄漏。

?正確代碼:

//第一種改法:
 
char* GetMemory(char* p)
{
	p = (char*)malloc(100);
	return p;
}
void test(void)
{
	char* str = NULL;
	str = GetMemory(str);
	strcpy(str, "hello world");
	printf(str);
	free(str);
	str = NULL;
}
 
int main()
{
	test();
	return 0;
}
 
 
//第二種改法:
 
char* 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.局部變量和形式參數(shù)存在于棧上

代碼如下(示例):

//例題分析:
 
char* GetMemory(void)
{
	char p[] = "hello world";
	return p;
}
void Test(void)
{
	char* str = NULL;
	str = GetMemory();
	printf(str);
}
 
int main()
{
	test();
	return 0;
}

程序運行結果:

打印不成功,打印的都是隨機值

原因分析:

GetMemory函數(shù)內(nèi)部創(chuàng)建的數(shù)組是在棧區(qū)上創(chuàng)建的
出了函數(shù),p的數(shù)組的空間就還給了操作系統(tǒng)
返回的地址是沒有實際意義的,如果通過返回的地址,去訪問內(nèi)存就是非法訪問內(nèi)存。

?正確代碼:

char* 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.動態(tài)內(nèi)存開的空間記得free釋放掉

代碼如下(示例)

void 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;
}

錯誤分析:

申請的動態(tài)內(nèi)存空間使用完之后沒有及時free釋放掉。

正確代碼:

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;
}
int main()
{
	test();
	return 0;
}

4.非法訪問內(nèi)存

代碼如下(示例)

void 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;
}

錯誤分析:

申請的空間已經(jīng)free釋放還給操作系統(tǒng)了,及時str還記得這塊空間的起始地址,但是也不能訪問,屬于非法訪問內(nèi)存空間。
free完之后要及時把str置成NULL指針。

正確代碼:

void 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;
}

總結:

上述給大家簡單介紹了動態(tài)內(nèi)存開辟常見的幾種問題,也分析了往年的幾道面試題里面的錯誤,讓我們加深了對這一章的理解,后續(xù)自己使用的時候可以有效的規(guī)避掉這些問題。相信大家都學會了。如果上述文章有任何問題?,歡迎大佬們提出質(zhì)疑,我會虛心學習和改正,最重要的是能共同進步,共同成長,學習好編程。

到此這篇關于C語言 動態(tài)內(nèi)存開辟常見問題解決與分析流程的文章就介紹到這了,更多相關C語言 動態(tài)內(nèi)存開辟內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • QT設置widget背景圖片不影響widget內(nèi)其他控件背景的方法

    QT設置widget背景圖片不影響widget內(nèi)其他控件背景的方法

    這篇文章主要給大家介紹了關于QT設置widget背景圖片不影響widget內(nèi)其他控件背景的方法,軟件的界面為了更直觀或美觀,常常需要通過圖片來表達,需要的朋友可以參考下
    2023-06-06
  • 使用MySQL編程實現(xiàn)C語言功能強大化步驟示例

    使用MySQL編程實現(xiàn)C語言功能強大化步驟示例

    這篇文章主要為大家介紹了使用MySQL編程實現(xiàn)C語言功能強大化步驟示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-05-05
  • C++語言基礎 this和static關鍵字

    C++語言基礎 this和static關鍵字

    這篇文章主要介紹了C++語言基礎 this和static關鍵字,需要的朋友可以參考下
    2020-01-01
  • C++工廠方法之對象創(chuàng)建型模式詳解

    C++工廠方法之對象創(chuàng)建型模式詳解

    這篇文章主要為大家詳細介紹了C++對象創(chuàng)建型模式,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-03-03
  • C/C++實現(xiàn)投骰子游戲

    C/C++實現(xiàn)投骰子游戲

    這篇文章主要為大家詳細介紹了C/C++實現(xiàn)投骰子游戲,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-11-11
  • 深入了解C語言中的const和指針

    深入了解C語言中的const和指針

    這篇文章將具體為大家介紹一下C語言中const和指針的使用,文中的示例代碼講解詳細,對我們學習const和指針有一定幫助,需要的可以參考一下
    2022-02-02
  • QT實現(xiàn)提示右下角冒泡效果

    QT實現(xiàn)提示右下角冒泡效果

    這篇文章主要為大家詳細介紹了QT實現(xiàn)提示右下角冒泡效果,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-08-08
  • C語言結構及隊列實現(xiàn)示例詳解

    C語言結構及隊列實現(xiàn)示例詳解

    這篇文章主要為大家介紹了C語言實現(xiàn)隊列示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-12-12
  • C++實現(xiàn)靜態(tài)鏈表

    C++實現(xiàn)靜態(tài)鏈表

    這篇文章主要為大家詳細介紹了C++實現(xiàn)靜態(tài)鏈表,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-04-04
  • C語言形參與實參使用的差別講解

    C語言形參與實參使用的差別講解

    形參出現(xiàn)在函數(shù)定義中,在整個函數(shù)體內(nèi)都可以使用, 離開該函數(shù)則不能使用。實參出現(xiàn)在主調(diào)函數(shù)中,進入被調(diào)函數(shù)后,實參變量也不能使用,形參和實參的功能是作數(shù)據(jù)傳送。發(fā)生函數(shù)調(diào)用時, 主調(diào)函數(shù)把實參的值傳送給被調(diào)函數(shù)的形參從而實現(xiàn)主調(diào)函數(shù)向被調(diào)函數(shù)的數(shù)據(jù)傳送
    2023-02-02

最新評論