溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

C語(yǔ)言柔性數(shù)組怎么使用

發(fā)布時(shí)間:2023-04-19 11:17:27 來(lái)源:億速云 閱讀:80 作者:iii 欄目:開(kāi)發(fā)技術(shù)

今天小編給大家分享一下C語(yǔ)言柔性數(shù)組怎么使用的相關(guān)知識(shí)點(diǎn),內(nèi)容詳細(xì),邏輯清晰,相信大部分人都還太了解這方面的知識(shí),所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來(lái)了解一下吧。

一、前言

仔細(xì)觀察下面的代碼,有沒(méi)有看出哪里不對(duì)勁?

struct S
{
    int i;
    double d;
    char c;
    int arr[];
};

還有另外一種寫(xiě)法:

struct S
{
    int i;
    double d;
    char c;
    int arr[0];
};

你應(yīng)該一眼就看到了,結(jié)構(gòu)體的最后一個(gè)成員數(shù)組的寫(xiě)法是int arr[];或者是int arr[0],這兩種寫(xiě)法是等價(jià)的,意思是這個(gè)數(shù)組的大小是不確定的、未知的、可以變化的。

C99允許這種特殊的結(jié)構(gòu)體存在。這樣的結(jié)構(gòu)體滿足下面兩個(gè)條件:

1.最后一個(gè)成員變量是一個(gè)大小可以變化的數(shù)組。

2.這個(gè)成員數(shù)組前面至少有另外一個(gè)成員變量。

我們稱這個(gè)大小可以變化的成員數(shù)組為柔性數(shù)組。

注意,柔性數(shù)組不能是結(jié)構(gòu)體里唯一一個(gè)成員,下面的代碼是不允許的:

struct S
{
    int arr[0];
};

這篇文章里,我將重點(diǎn)探討柔性數(shù)組的用法、內(nèi)存分布以及和優(yōu)勢(shì)。

二、柔性數(shù)組的用法

我不建議在棧上直接定義有柔性數(shù)組的結(jié)構(gòu)體,也就是這么寫(xiě):

struct S s;

因?yàn)槿嵝詳?shù)組的大小是可以變化的,我建議在堆上申請(qǐng)空間,采取動(dòng)態(tài)內(nèi)存管理的方法,這樣就能發(fā)揮出柔性數(shù)組大小可以改變的優(yōu)勢(shì)。

假設(shè)我們使用malloc()函數(shù)來(lái)開(kāi)辟空間,一開(kāi)始應(yīng)該malloc出多大的空間呢?要回答這個(gè)問(wèn)題,首先我們要知道sizeof(struct S)是多少。

事實(shí)上,sizeof(struct S)計(jì)算出來(lái)的結(jié)果是該結(jié)構(gòu)體不考慮柔性數(shù)組的大小。如果我們想要給柔性數(shù)組開(kāi)辟空間,malloc出來(lái)的大小應(yīng)該是sizeof(struct S)加上柔性數(shù)組的大小。

假設(shè)這個(gè)柔性數(shù)組在結(jié)構(gòu)體中的聲明是int arr[0];,我想給這個(gè)數(shù)組的大小是40個(gè)字節(jié),這樣這個(gè)數(shù)組就能存儲(chǔ)10個(gè)int,那么一開(kāi)始malloc的大小就應(yīng)該是sizeof(struct S)+10*sizeof(int),具體的例子如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

int main()
{
	struct S* ps = (struct S*)malloc(sizeof(struct S) + 10 * sizeof(int));
	if (ps == NULL)
	{
		printf("malloc()->%s\n", strerror(errno));
		return 1;
	}

	return 0;
}

該結(jié)構(gòu)體中的i,d,c等變量可以正常使用。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

int main()
{
	struct S* ps = (struct S*)malloc(sizeof(struct S) + 10 * sizeof(int));
	if (ps == NULL)
	{
		printf("malloc()->%s\n", strerror(errno));
		return 1;
	}

	ps->i = 10;
	ps->d = 3.14;
	ps->c = 'F';

	return 0;
}

柔性數(shù)組也可以像正常的數(shù)組一樣訪問(wèn),比如把1~10放進(jìn)去。注意此時(shí)這個(gè)數(shù)組的容量是10個(gè)int,不能越界訪問(wèn)。使用的例子如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

int main()
{
	struct S* ps = (struct S*)malloc(sizeof(struct S) + 10 * sizeof(int));
	if (ps == NULL)
	{
		printf("malloc()->%s\n", strerror(errno));
		return 1;
	}

	ps->i = 10;
	ps->d = 3.14;
	ps->c = 'F';

	for (int i = 0; i < 10; i++)
	{
		ps->arr[i] = i + 1;
	}

	for (int i = 0; i < 10; i++)
	{
		printf("%d ", ps->arr[i]);
	}
	printf("\n");

	return 0;
}

我們還可以對(duì)柔性數(shù)組擴(kuò)容,如果我們想讓這個(gè)柔性數(shù)組的容量是20個(gè)int,整個(gè)結(jié)構(gòu)體的新的大小就是sizeof(struct S)+20*sizeof(int),因?yàn)閟izeof(struct S)是不考慮柔性數(shù)組的大小時(shí)計(jì)算的結(jié)構(gòu)體大小。只需要對(duì)ps進(jìn)行realloc就行了。實(shí)現(xiàn)代碼如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

int main()
{
	struct S* ps = (struct S*)malloc(sizeof(struct S) + 10 * sizeof(int));
	if (ps == NULL)
	{
		printf("malloc()->%s\n", strerror(errno));
		return 1;
	}

	ps->i = 10;
	ps->d = 3.14;
	ps->c = 'F';

	for (int i = 0; i < 10; i++)
	{
		ps->arr[i] = i + 1;
	}

	for (int i = 0; i < 10; i++)
	{
		printf("%d ", ps->arr[i]);
	}
	printf("\n");

	struct S* tmp = (struct S*)realloc(ps, sizeof(struct S) + 20 * sizeof(int));
	if (tmp == NULL)
	{
		printf("realloc()->%s\n", strerror(errno));
		return 1;
	}
	else
	{
		ps = tmp;
	}

	return 0;
}

擴(kuò)容后的柔性數(shù)組的空間更大了,我們可以把11~20都放進(jìn)去。實(shí)現(xiàn)代碼如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

int main()
{
	struct S* ps = (struct S*)malloc(sizeof(struct S) + 10 * sizeof(int));
	if (ps == NULL)
	{
		printf("malloc()->%s\n", strerror(errno));
		return 1;
	}

	ps->i = 10;
	ps->d = 3.14;
	ps->c = 'F';

	for (int i = 0; i < 10; i++)
	{
		ps->arr[i] = i + 1;
	}

	for (int i = 0; i < 10; i++)
	{
		printf("%d ", ps->arr[i]);
	}
	printf("\n");

	struct S* tmp = (struct S*)realloc(ps, sizeof(struct S) + 20 * sizeof(int));
	if (tmp == NULL)
	{
		printf("realloc()->%s\n", strerror(errno));
		return 1;
	}
	else
	{
		ps = tmp;
	}

	for (int i = 10; i < 20; i++)
	{
		ps->arr[i] = i + 1;
	}
	
	for (int i = 0; i < 20; i++)
	{
		printf("%d ", ps->arr[i]);
	}

	return 0;
}

當(dāng)然最后別忘了free掉ps,否則會(huì)導(dǎo)致內(nèi)存泄漏。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

int main()
{
	struct S* ps = (struct S*)malloc(sizeof(struct S) + 10 * sizeof(int));
	if (ps == NULL)
	{
		printf("malloc()->%s\n", strerror(errno));
		return 1;
	}

	ps->i = 10;
	ps->d = 3.14;
	ps->c = 'F';

	for (int i = 0; i < 10; i++)
	{
		ps->arr[i] = i + 1;
	}

	for (int i = 0; i < 10; i++)
	{
		printf("%d ", ps->arr[i]);
	}
	printf("\n");

	struct S* tmp = (struct S*)realloc(ps, sizeof(struct S) + 20 * sizeof(int));
	if (tmp == NULL)
	{
		printf("realloc()->%s\n", strerror(errno));
		return 1;
	}
	else
	{
		ps = tmp;
	}

	for (int i = 10; i < 20; i++)
	{
		ps->arr[i] = i + 1;
	}
	
	for (int i = 0; i < 20; i++)
	{
		printf("%d ", ps->arr[i]);
	}

	free(ps);
	ps = NULL;

	return 0;
}

對(duì)于柔性數(shù)組的使用,在上面的例子中,可以總結(jié)出幾個(gè)要點(diǎn):

1.malloc出來(lái)的大小是sizeof(struct S)加上柔性數(shù)組的大小,calloc同理。

2.擴(kuò)容時(shí)realloc出來(lái)的新大小也是sizeof(struct S)加上柔性數(shù)組的新大小。

3.每次使用malloc和realloc等函數(shù)時(shí),需要檢查返回值,否則可能導(dǎo)致對(duì)NULL指針的解引用(這點(diǎn)是動(dòng)態(tài)內(nèi)存管理的常識(shí)了)。

4.一定要記得柔性數(shù)組的容量是多少,不要越界訪問(wèn)了,空間不夠記得擴(kuò)容。

5.記得free,防止內(nèi)存泄漏。

三、柔性數(shù)組的內(nèi)存分布

柔性數(shù)組是結(jié)構(gòu)體的一個(gè)成員數(shù)組,在前面的例子中,整個(gè)結(jié)構(gòu)體都是在堆上malloc出來(lái)的。此時(shí),整個(gè)結(jié)構(gòu)體都存儲(chǔ)在堆上的一塊連續(xù)的空間里,包括前面幾個(gè)成員變量i,d,c和柔性數(shù)組arr。也就是這樣:

C語(yǔ)言柔性數(shù)組怎么使用

只不過(guò)數(shù)組arr的大小是可以改變的,所以叫“柔性數(shù)組”。

有些朋友可能會(huì)說(shuō)了,我不需要柔性數(shù)組也能實(shí)現(xiàn)類似這樣的效果呀!我在結(jié)構(gòu)體里存一個(gè)指針,指向一塊malloc出來(lái)的空間,這塊空間也是堆上的,可以動(dòng)態(tài)管理。也就是說(shuō),像下面這樣定義結(jié)構(gòu)體:

struct S
{
    int i;
    double d;
    char c;
    int* arr;
};

這樣似乎還簡(jiǎn)單一點(diǎn),先malloc出一個(gè)struct S出來(lái),malloc的大小就是sizeof(struct S),像這樣:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

int main()
{
	struct S* ps = (struct S*)malloc(sizeof(struct S));
	if (ps == NULL)
	{
		printf("malloc()->%s\n", strerror(errno));
		return 1;
	}

	return 0;
}

然后再malloc出10個(gè)int的大小出來(lái),用結(jié)構(gòu)體中的arr指針來(lái)管理這塊空間,像這樣:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

int main()
{
	struct S* ps = (struct S*)malloc(sizeof(struct S));
	if (ps == NULL)
	{
		printf("malloc()->%s\n", strerror(errno));
		return 1;
	}

	ps->arr = (int*)malloc(10 * sizeof(int));
	if (ps->arr == NULL)
	{
		printf("2: malloc()->%s\n", strerror(errno));
		return 1;
	}

	return 0;
}

此時(shí)arr就可以當(dāng)成一個(gè)數(shù)組來(lái)使用了,比如把1~10放進(jìn)去。同樣還是要注意不要越界訪問(wèn)。示例代碼如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

int main()
{
	struct S* ps = (struct S*)malloc(sizeof(struct S));
	if (ps == NULL)
	{
		printf("malloc()->%s\n", strerror(errno));
		return 1;
	}

	ps->arr = (int*)malloc(10 * sizeof(int));
	if (ps->arr == NULL)
	{
		printf("2: malloc()->%s\n", strerror(errno));
		return 1;
	}

	for (int i = 0; i < 10; i++)
	{
		ps->arr[i] = i + 1;
	}
	
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", ps->arr[i]);
	}
	printf("\n");

	return 0;
}

你如果覺(jué)得空間不夠,還可以擴(kuò)容。比如,你可以把結(jié)構(gòu)體中的arr進(jìn)行realloc,新的大小能存放20個(gè)int。示例代碼如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

int main()
{
	struct S* ps = (struct S*)malloc(sizeof(struct S));
	if (ps == NULL)
	{
		printf("malloc()->%s\n", strerror(errno));
		return 1;
	}

	ps->arr = (int*)malloc(10 * sizeof(int));
	if (ps->arr == NULL)
	{
		printf("2: malloc()->%s\n", strerror(errno));
		return 1;
	}

	for (int i = 0; i < 10; i++)
	{
		ps->arr[i] = i + 1;
	}
	
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", ps->arr[i]);
	}
	printf("\n");

	int* tmp = (int*)realloc(ps->arr, 20 * sizeof(int));
	if (tmp == NULL)
	{
		printf("realloc()->%s\n", strerror(errno));
		return 1;
	}
	else
	{
		ps->arr = tmp;
	}

	return 0;
}

此時(shí),你就可以把11~20也放進(jìn)去。實(shí)現(xiàn)代碼如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

int main()
{
	struct S* ps = (struct S*)malloc(sizeof(struct S));
	if (ps == NULL)
	{
		printf("malloc()->%s\n", strerror(errno));
		return 1;
	}

	ps->arr = (int*)malloc(10 * sizeof(int));
	if (ps->arr == NULL)
	{
		printf("2: malloc()->%s\n", strerror(errno));
		return 1;
	}

	for (int i = 0; i < 10; i++)
	{
		ps->arr[i] = i + 1;
	}

	for (int i = 0; i < 10; i++)
	{
		printf("%d ", ps->arr[i]);
	}
	printf("\n");

	int* tmp = (int*)realloc(ps->arr, 20 * sizeof(int));
	if (tmp == NULL)
	{
		printf("realloc()->%s\n", strerror(errno));
		return 1;
	}
	else
	{
		ps->arr = tmp;
	}

	for (int i = 10; i < 20; i++)
	{
		ps->arr[i] = i + 1;
	}

	for (int i = 0; i < 20; i++)
	{
		printf("%d ", ps->arr[i]);
	}

	return 0;
}

最后別忘了把a(bǔ)rr和ps都free掉,而且順序不能錯(cuò)了。如果你先f(wàn)ree掉了ps,結(jié)構(gòu)體就沒(méi)了,里面的arr就成為了野指針,內(nèi)存就泄露了。實(shí)現(xiàn)代碼如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

int main()
{
	struct S* ps = (struct S*)malloc(sizeof(struct S));
	if (ps == NULL)
	{
		printf("malloc()->%s\n", strerror(errno));
		return 1;
	}

	ps->arr = (int*)malloc(10 * sizeof(int));
	if (ps->arr == NULL)
	{
		printf("2: malloc()->%s\n", strerror(errno));
		return 1;
	}

	for (int i = 0; i < 10; i++)
	{
		ps->arr[i] = i + 1;
	}

	for (int i = 0; i < 10; i++)
	{
		printf("%d ", ps->arr[i]);
	}
	printf("\n");

	int* tmp = (int*)realloc(ps->arr, 20 * sizeof(int));
	if (tmp == NULL)
	{
		printf("realloc()->%s\n", strerror(errno));
		return 1;
	}
	else
	{
		ps->arr = tmp;
	}

	for (int i = 10; i < 20; i++)
	{
		ps->arr[i] = i + 1;
	}

	for (int i = 0; i < 20; i++)
	{
		printf("%d ", ps->arr[i]);
	}

	free(ps->arr);
	ps->arr = NULL;
	free(ps);
	ps = NULL;

	return 0;
}

那這種實(shí)現(xiàn)的內(nèi)存分布是怎么樣的呢?這個(gè)結(jié)構(gòu)體是存儲(chǔ)在堆上的,用ps來(lái)管理,結(jié)構(gòu)體里的一個(gè)指針arr又指向了堆上的另一塊空間,如下圖:

C語(yǔ)言柔性數(shù)組怎么使用

這種實(shí)現(xiàn)方式和柔性數(shù)組的方式感覺(jué)差不多呀!都是在堆上有個(gè)結(jié)構(gòu)體,結(jié)構(gòu)體里有個(gè)大小可以變化的數(shù)組。那為什么非要搞出來(lái)個(gè)柔性數(shù)組的概念呢?那是因?yàn)?,柔性?shù)組有它獨(dú)特的優(yōu)勢(shì)。

四、柔性數(shù)組的優(yōu)勢(shì)

前面我們先用柔性數(shù)組實(shí)現(xiàn)了一種效果,又不使用柔性數(shù)組實(shí)現(xiàn)了相似的效果,對(duì)比兩種實(shí)現(xiàn)方式,我們可以做一些總結(jié):

1.使用上:柔性數(shù)組malloc了一次,free了一次;不使用柔性數(shù)組要malloc兩次,free兩次。柔性數(shù)組的使用更加簡(jiǎn)單,不容易出錯(cuò)。如果不使用柔性數(shù)組,可能會(huì)忘記free掉結(jié)構(gòu)體里的arr指針,導(dǎo)致內(nèi)存泄漏。

2.效率上:柔性數(shù)組的存儲(chǔ)空間是連續(xù)的,訪問(wèn)時(shí)效率更高。

所以,雖然有相似的效果,我更推薦使用柔性數(shù)組的方式。

以上就是“C語(yǔ)言柔性數(shù)組怎么使用”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會(huì)為大家更新不同的知識(shí),如果還想學(xué)習(xí)更多的知識(shí),請(qǐng)關(guān)注億速云行業(yè)資訊頻道。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI