国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

詳解C語言—動態(tài)內(nèi)存分配(二)

這篇具有很好參考價值的文章主要介紹了詳解C語言—動態(tài)內(nèi)存分配(二)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

目錄

前言:

幾個經(jīng)典的例題題

例一:

例二:

例三:

例四:

例五:?

?C/C++程序的內(nèi)存開辟

柔性數(shù)組

柔性數(shù)組的特點:

柔性數(shù)組的使用:?

柔性數(shù)組的代替:

柔性數(shù)組的優(yōu)勢:

小結(jié):


前言:

希望在復(fù)習(xí)完詳解C語言—動態(tài)內(nèi)存分配(一)???????,閱讀此篇文章會進一步提升你的能力!

幾個經(jīng)典的例題題

例一:

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

運行之后 沒有結(jié)果,異常退出:詳解C語言—動態(tài)內(nèi)存分配(二),詳解C語言,c語言,算法,開發(fā)語言?

我們在調(diào)試中可以看到程序發(fā)生異常。?

詳解C語言—動態(tài)內(nèi)存分配(二),詳解C語言,c語言,算法,開發(fā)語言

  • 首先主函數(shù)調(diào)用Test函數(shù),Test函數(shù)聲明一個char*類型變量str對其賦值為NULL,
  • 然后調(diào)用GetMemory函數(shù),將str作為參數(shù)傳入,形式參數(shù)p只是將實參str的值拷貝一份,兩者是獨立的,函數(shù)中對 p 動態(tài)分配空間100個字節(jié)空間,與str沒有關(guān)系,所以調(diào)用GetMemory函數(shù)函數(shù)之后 str 還是空指針,
  • strcpy的參數(shù)是指針類型,strcpy內(nèi)部需要對指針類型參數(shù)進行解引用,詳解C語言—動態(tài)內(nèi)存分配(二),詳解C語言,c語言,算法,開發(fā)語言? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? str作為參數(shù)造成對空指針進行解引用操作,形成對空指針的非法訪問。

該程序會造成兩個問題:

  1. 對NULL指針進行了解引用操作,程序會崩潰。
  2. 沒有釋放空間,造成內(nèi)存泄漏問題。

因此我們做出以下修改:?

想要修改指針變量需要將指針變量的地址傳入函數(shù)中,函數(shù)的參數(shù)用二級指針接收,這樣在函數(shù)內(nèi)部可以對其動態(tài)分配空間。

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

?輸出結(jié)果:詳解C語言—動態(tài)內(nèi)存分配(二),詳解C語言,c語言,算法,開發(fā)語言

例二:

char* GetMemory(void)
{
	char p[] = "hello world";
	return p;
}
void Test(void)
{
	char* str = NULL;
	str = GetMemory();
	printf(str);
}

int main()
{
	Test();
	return 0;
}

輸出結(jié)果:詳解C語言—動態(tài)內(nèi)存分配(二),詳解C語言,c語言,算法,開發(fā)語言?

GetMemory函數(shù)中,p 儲存了"hello world"首地址,返回為p,當GetMemory函數(shù)調(diào)用完后,雖然str獲取到p儲存的地址,但p的空間會被銷毀,p變成了野指針,str獲取到的就是野指針。相當于非法訪問。

?如果在給p加上static聲明 p 為靜態(tài)變量,延長生命周期,就可以輸出"hello world"。

詳解C語言—動態(tài)內(nèi)存分配(二),詳解C語言,c語言,算法,開發(fā)語言

例三:

int* test()
{
	int a = 10;
	return &a;
}

int main()
{
	int* p = test();
	printf("%d\n", *p);

	return 0;
}

輸出結(jié)果:詳解C語言—動態(tài)內(nèi)存分配(二),詳解C語言,c語言,算法,開發(fā)語言

調(diào)用test函數(shù)時 一旦test函數(shù)返回,變量a的空間不會立即被刪除,但是它的生命周期結(jié)束,該內(nèi)存空間可以被系統(tǒng)重用,也就是說,該內(nèi)存空間可能會被分配給后續(xù)的函數(shù)調(diào)用或變量,該內(nèi)存可能會被其他數(shù)據(jù)覆蓋。

這次可能只是僥幸a的空間沒有占用,如果在輸出語句前再加上這樣一條這樣的輸出語句,

printf("hehe");

a的空間就被占用了,輸出結(jié)果將不再是 10 。

?輸出結(jié)果:詳解C語言—動態(tài)內(nèi)存分配(二),詳解C語言,c語言,算法,開發(fā)語言

例四:

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

輸出結(jié)果:?詳解C語言—動態(tài)內(nèi)存分配(二),詳解C語言,c語言,算法,開發(fā)語言

看似沒有問題,但還是存在唯一的問題——忘記釋放內(nèi)存。?

	free(str);
	str = NULL;

例五:?

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

?free處理完str,str變成野指針,所以判斷不為空,對其進行拷貝,但str指向的空間已被free回收了,再進行拷貝就造成非法訪問內(nèi)存。

其實用free在釋放完,要及時將str即使賦值為NULL。

?C/C++程序的內(nèi)存開辟

詳解C語言—動態(tài)內(nèi)存分配(二),詳解C語言,c語言,算法,開發(fā)語言

C/C++程序內(nèi)存分配的幾個區(qū)域:
1. 棧區(qū)(stack):在執(zhí)行函數(shù)時,函數(shù)內(nèi)局部變量的存儲單元都可以在棧上創(chuàng)建,函數(shù)執(zhí)行結(jié)束時這些存儲單元自動被釋放。棧內(nèi)存分配運算內(nèi)置于處理器的指令集中,效率很高,但是分配的內(nèi)存容量有限。 棧區(qū)主要存放運行函數(shù)而分配的局部變量、函數(shù)參數(shù)、返回數(shù)據(jù)、返回地址等。
2. 堆區(qū)(heap):一般由程序員分配釋放, 若程序員不釋放,程序結(jié)束時可能由OS回收 。分配方式類似于鏈表。
3. 數(shù)據(jù)段(靜態(tài)區(qū))(static)存放全局變量、靜態(tài)數(shù)據(jù)。程序結(jié)束后由系統(tǒng)釋放。
4. 代碼段:存放函數(shù)體(類成員函數(shù)和全局函數(shù))的二進制代碼。
現(xiàn)在我們就可以更好的理解在static關(guān)鍵字修飾局部變量的例子了:
實際上普通的局部變量是在棧區(qū)分配空間的,棧區(qū)的特點是在上面創(chuàng)建的變量出了作用域就銷毀。
但是被static修飾的變量存放在數(shù)據(jù)段(靜態(tài)區(qū)),數(shù)據(jù)段的特點是在上面創(chuàng)建的變量,直到程序結(jié)束才銷毀,所以生命周期變長。

柔性數(shù)組

也許你從來沒有聽說過柔性數(shù)組(flexible array)這個概念,但是它確實是存在的。
C99 中,結(jié)構(gòu)中的最后一個元素允許是未知大小的數(shù)組,這就叫做『柔性數(shù)組』成員。
第一種編譯器不支持那就用第二種。
struct s
{
	int n;
	int arr[];//柔性數(shù)組
};

struct s
{
	int n;
	int arr[0];//柔性數(shù)組
};

柔性數(shù)組的特點:

  • 結(jié)構(gòu)中的柔性數(shù)組成員前面必須至少一個其他成員。
  • sizeof 返回的這種結(jié)構(gòu)大小不包括柔性數(shù)組的內(nèi)存。
  • 包含柔性數(shù)組成員的結(jié)構(gòu)用malloc ()函數(shù)進行內(nèi)存的動態(tài)分配,并且分配的內(nèi)存應(yīng)該大于結(jié)構(gòu)的大小,以適應(yīng)柔性數(shù)組的預(yù)期大小。

柔性數(shù)組的使用:?

struct s
{
	int n;
	int arr[0];
};

int main()
{
	//printf("%d\n", sizeof(struct S));
	struct S* ps = (struct S*)malloc(sizeof(struct S) + 40);
	if (ps == NULL)
	{
		perror("malloc");
		return 1;
	}
	ps->n = 100;
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		ps->arr[i] = i + 1;
	}

	free(ps);
	ps = NULL;

	return 0;
}

?如需增容則加上realloc函數(shù)進行增容:

int main()
{
	//printf("%d\n", sizeof(struct S));
	struct S* ps = (struct S*)malloc(sizeof(struct S) + 40);
	if (ps == NULL)
	{
		perror("malloc");
		return 1;
	}
	ps->n = 100;
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		ps->arr[i] = i + 1;
	}

	//空間不夠,需要增容
	struct S* ptr = realloc(ps, sizeof(struct S) + 60);
	if (ptr == NULL)
	{
		perror("realloc");
		return 1;
	}
	ps = ptr;
	ps->n = 15;
	for (i = 0; i < 15; i++)
	{
		printf("%d\n", ps->arr[i]);
	}

	//釋放
	free(ps);
	ps = NULL;

	return 0;
}

柔性數(shù)組的代替:

我們可以用指針類型的結(jié)構(gòu)體成員代替柔性數(shù)組:?

struct S
{
	int n;
	int* arr;
};


int main()
{
	struct S* ps = (struct S*)malloc(sizeof(struct S));
	if (ps == NULL)
	{
		perror("malloc->ps");
		return 1;
	}
	ps->n = 100;
	ps->arr = (int*)malloc(40);//1 2 3 4 5 6 7 8 9 10
	if (ps->arr == NULL)
	{
		perror("malloc->arr");
		return 1;
	}
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		ps->arr[i] = i + 1;
	}

	//調(diào)整
	int* ptr = (int*)realloc(ps->arr, 60);
	if (ptr != NULL)
	{
		ps->arr = ptr;
	}
	else
	{
		perror("realloc");
		return 1;
	}
	//打印
	for (i = 0; i < 15; i++)
	{
		printf("%d\n", ps->arr[i]);
	}

	//釋放
	free(ps->arr);
	ps->arr = NULL;

	free(ps);
	ps = NULL;

	return 0;
}

柔性數(shù)組的優(yōu)勢:

上述 第一種 ? 和 第二種 ? 可以完成同樣的功能,但是 第一種 ? 的實現(xiàn)有兩個好處:
第一個好處是: 方便內(nèi)存釋放
如果我們的代碼是在一個給別人用的函數(shù)中,你在里面做了二次內(nèi)存分配,并把整個結(jié)構(gòu)體返回給用戶。用戶調(diào)用free可以釋放結(jié)構(gòu)體,但是用戶并不知道這個結(jié)構(gòu)體內(nèi)的成員也需要free,所以你不能指望用戶來發(fā)現(xiàn)這個事。所以,如果我們把結(jié)構(gòu)體的內(nèi)存以及其成員要的內(nèi)存一次性分配好了,并返回給用戶一個結(jié)構(gòu)體指針,用戶做一次free就可以把所有的內(nèi)存也給釋放掉。
第二個好處是: 這樣有利于訪問速度.
連續(xù)的內(nèi)存有益于提高訪問速度,也有益于減少內(nèi)存碎片。(其實,我個人覺得也沒多高了,反正你跑不了要用做偏移量的加法來尋址)

小結(jié):

?學(xué)習(xí)之路道阻且長,希望大家堅持復(fù)習(xí),堅持敲代碼,未來的你們一定會收到心儀的offer?。?!文章來源地址http://www.zghlxwxcb.cn/news/detail-721282.html

到了這里,關(guān)于詳解C語言—動態(tài)內(nèi)存分配(二)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • C語言 malloc動態(tài)內(nèi)存分配函數(shù)

    malloc函數(shù):malloc時動態(tài)內(nèi)存分配函數(shù),用于申請一塊連續(xù)的指定大小的內(nèi)存塊區(qū)域以void*類型返回分配的內(nèi)存區(qū)域地址,就是當數(shù)組創(chuàng)建長度不一定 害怕數(shù)據(jù)存儲不夠或者不能浪費時間 在使用malloc開辟空間時,使用完成一定要釋放空間,如果不釋放會造內(nèi)存泄漏。n在使用ma

    2024年02月07日
    瀏覽(17)
  • C語言系列9——動態(tài)內(nèi)存分配與釋放

    在計算機編程中,動態(tài)內(nèi)存分配與釋放是一項重要的操作。本文將介紹malloc與free這兩個基本操作,探討內(nèi)存泄漏的原因及避免策略,并通過實際案例討論動態(tài)數(shù)組的創(chuàng)建與管理技巧。 動態(tài)內(nèi)存分配是現(xiàn)代編程中的一個關(guān)鍵概念。與靜態(tài)內(nèi)存分配不同,動態(tài)內(nèi)存分配允許程序

    2024年02月19日
    瀏覽(22)
  • C語言【自定義數(shù)據(jù)類型、typedef、動態(tài)內(nèi)存分配】

    一、自定義數(shù)據(jù)類型。 ? 關(guān)于下面講到的所有自定義數(shù)據(jù)類型(enum、struct、union),有一點要說的是:定義類型不是聲明變量,做這步操作時不分配內(nèi)存,也不能在定義類型時賦值(枚舉那個不是賦值,是做一個限定,賦值時賦限定之外的值也不報錯。)。 1、typedef (給類

    2024年02月05日
    瀏覽(19)
  • 操作系統(tǒng)原理 —— 內(nèi)存動態(tài)分區(qū)分配算法(二十一)

    操作系統(tǒng)原理 —— 內(nèi)存動態(tài)分區(qū)分配算法(二十一)

    在上一個章節(jié)我們講了 內(nèi)存連續(xù)分配 的幾種方式,有單一、固定、動態(tài)這三種,在固定、動態(tài)這種里面,操作系統(tǒng)會記錄空閑分區(qū)表,這個表是用來記錄當前空閑的內(nèi)存。 那么在之后有新的進程裝入內(nèi)存,需要從空閑分區(qū)表中找到一塊比較合適的空閑內(nèi)存,該怎么找呢?

    2024年02月08日
    瀏覽(21)
  • c語言:通訊錄管理系統(tǒng)(動態(tài)分配內(nèi)存版)

    c語言:通訊錄管理系統(tǒng)(動態(tài)分配內(nèi)存版)

    前言: 本通訊錄管理系統(tǒng)一共三個版本,除此文章以外還有如下倆個版本,大家可以根據(jù)需求自?。?基礎(chǔ)增刪查改功能版本 :c語言:通訊錄管理系統(tǒng)(增刪查改)_luming.02的博客-CSDN博客 文件保存版本 :c語言:通訊錄管理系統(tǒng)(文件版本)-CSDN博客 ????????本文是在基

    2024年02月08日
    瀏覽(104)
  • 8.8 【C語言】動態(tài)內(nèi)存分配與指向它的指針變量

    棧:全局變量和局部變量,全局變量是分配在內(nèi)存中的靜態(tài)存儲區(qū)的,非靜態(tài)的局部變量是分配在內(nèi)存中的動態(tài)存儲區(qū)的。 堆:數(shù)據(jù)臨時存放在一個特別的自由存儲區(qū)。 對內(nèi)存的動態(tài)分配是通過系統(tǒng)提供的庫函數(shù)來實現(xiàn)的,主要有malloc,calloc,free,realloc這四個函數(shù)。 1.用mallo

    2024年02月11日
    瀏覽(22)
  • 動態(tài)異長分區(qū)內(nèi)存分配與去配算法的設(shè)計-最佳適應(yīng)算法

    動態(tài)異長分區(qū)內(nèi)存分配與去配算法的設(shè)計-最佳適應(yīng)算法

    理解存儲管理的功能,掌握動態(tài)異長分區(qū)內(nèi)存管理中的最佳適應(yīng)算法。 本設(shè)計要求模擬最佳適應(yīng)算法的分配算法和回收算法。 空閑區(qū)域首址 空閑區(qū)域長度 … … addr size … … 圖1-1 空閑區(qū)域表 為了實現(xiàn)存儲資源的分配和回收,操作系統(tǒng)需要記錄內(nèi)存資源使用情況,即哪些區(qū)

    2024年02月19日
    瀏覽(19)
  • 【C語言高階篇】成為編程高手必學(xué)內(nèi)容,動態(tài)內(nèi)存分配我不允許還有人不會!

    【C語言高階篇】成為編程高手必學(xué)內(nèi)容,動態(tài)內(nèi)存分配我不允許還有人不會!

    ?? 鴿芷咕 :個人主頁 ??? 個人專欄 :《C語言初階篇》 《C語言進階篇》 ??生活的理想,就是為了理想的生活! ?? ?? hello! 各位寶子們大家好啊,又是新的一天開始了,今天給大家?guī)淼氖莿討B(tài)內(nèi)存規(guī)劃這一章節(jié)! ?? ?? 我們在創(chuàng)建變量的時候大家都知道大小是固

    2024年02月16日
    瀏覽(22)
  • 【C語言高階篇】成為編程高手必學(xué)內(nèi)容,程序中的動態(tài)內(nèi)存分配我不允許還有人不會!

    【C語言高階篇】成為編程高手必學(xué)內(nèi)容,程序中的動態(tài)內(nèi)存分配我不允許還有人不會!

    ?? 鴿芷咕 :個人主頁 ??? 個人專欄 :《C語言初階篇》 《C語言進階篇》 ??生活的理想,就是為了理想的生活! ?? ?? hello! 各位寶子們大家好啊,又是新的一天開始了,今天給大家?guī)淼氖莿討B(tài)內(nèi)存規(guī)劃這一章節(jié)! ?? ?? 我們在創(chuàng)建變量的時候大家都知道大小是固

    2024年02月16日
    瀏覽(23)
  • 【C/C++】靜態(tài)內(nèi)存分配與動態(tài)內(nèi)存分配

    1.1 - 定義概述 內(nèi)存分配 (Memory Allocation) 是指為計算機程序或服務(wù)分配物理內(nèi)存空間或虛擬內(nèi)存空間的一個過程。通常在程序執(zhí)行前或執(zhí)行時完成內(nèi)存分配。 1.2 - 分類概述 存在兩種類型的內(nèi)存分配: 編譯時內(nèi)存分配或靜態(tài)內(nèi)存分配 (Compile-time or Static Memory Allocation) 運行時內(nèi)存

    2024年02月11日
    瀏覽(24)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包