C語言柔性數(shù)組實(shí)例詳解
本文實(shí)例分析了C語言柔性數(shù)組的概念及用法,對(duì)于進(jìn)一步學(xué)習(xí)C程序設(shè)計(jì)有一定的借鑒價(jià)值。分享給大家供大家參考。具體如下:
一般來說,結(jié)構(gòu)中最后一個(gè)元素允許是未知大小的數(shù)組,這個(gè)數(shù)組就是柔性數(shù)組。但結(jié)構(gòu)中的柔性數(shù)組前面必須至少一個(gè)其他成員,柔性數(shù)組成員允許結(jié)構(gòu)中包含一個(gè)大小可變的數(shù)組,sizeof返回的這種結(jié)構(gòu)大小不包括柔性數(shù)組的內(nèi)存。包含柔數(shù)組成員的結(jié)構(gòu)用malloc函數(shù)進(jìn)行內(nèi)存的動(dòng)態(tài)分配,且分配的內(nèi)存應(yīng)該大于結(jié)構(gòu)的大小以適應(yīng)柔性數(shù)組的預(yù)期大小。柔性數(shù)組到底如何使用?
不完整類型
C和C++對(duì)于不完整類型的定義是一樣的,不完整類型是這樣一種類型,它缺乏足夠的信息例如長(zhǎng)度去描述一個(gè)完整的對(duì)象。
不完整類型舉例:
前向聲明就是一種常用的不完整類型
struct test; //test 只給出了聲明,沒有給出定義
不完整數(shù)據(jù)類型必須通過某種方式補(bǔ)充完整,才能使它們進(jìn)行實(shí)例化。否則只能用于定義指針或引用,因?yàn)榇藭r(shí)實(shí)例化的是指針或引用本身,不是base和test對(duì)象
一個(gè)未知長(zhǎng)度的數(shù)組也屬于不完整類型:
extern int a[];
extern 關(guān)鍵字不能去掉,因?yàn)閿?shù)組的長(zhǎng)度未知,不能作為定義出現(xiàn)。不完整類型的數(shù)組需要補(bǔ)充完整才能使用。不完整類型的數(shù)組可以通過幾種方式補(bǔ)充完整,大括號(hào)形式的初始化就是其中的一種方式:
int a[] = { 10,20 };
結(jié)構(gòu)體
首先,我們需要知道——所謂變量,其實(shí)是內(nèi)存地址的一個(gè)抽像名字罷了。在靜態(tài)編譯的程序中,所有的變量名都會(huì)在編譯時(shí)被轉(zhuǎn)成內(nèi)存地址。機(jī)器是不知道我們?nèi)〉拿值模恢赖刂贰?/p>
所以有了——棧內(nèi)存區(qū),堆內(nèi)存區(qū),靜態(tài)內(nèi)存區(qū),常量?jī)?nèi)存區(qū),我們代碼中的所有變量都會(huì)被編譯器預(yù)先放到這些內(nèi)存區(qū)中。
有了上面這個(gè)基礎(chǔ),我們來看一下結(jié)構(gòu)體中的成員的地址是什么?我們先簡(jiǎn)單化一下代碼:
struct test{ int i; char *p; };
上面代碼中,test結(jié)構(gòu)中i和p指針,在C的編譯器中保存的是相對(duì)地址——也就是說,他們的地址是相對(duì)于struct test的實(shí)例的。如果我們有這樣的代碼:
struct test t;
下面做個(gè)實(shí)驗(yàn):
#include<stdio.h> struct test{ int i; char *p; }; int main(void) { struct test t; printf("%p\n", &t); printf("%p\n", &(t.i)); printf("%p\n", &(t.p)); return 0; }
運(yùn)行結(jié)果:
我們可以看到,t.i的地址和t的地址是一樣的,t.p的址址相對(duì)于t的地址多了個(gè)8。說白了,t.i 其實(shí)就是(&t + 0×0), t.p 的其實(shí)就是 (&t + 0×8)。0×0和0×8這個(gè)偏移地址就是成員i和p在編譯時(shí)就被編譯器給hard code了的地址。于是,你就知道,不管結(jié)構(gòu)體的實(shí)例是什么——訪問其成員其實(shí)就是加成員的偏移量。
下面再來做個(gè)實(shí)驗(yàn):
#include<stdio.h> struct test{ int i; short c; char *p; }; int main(void) { struct test *pt=NULL; printf("%p\n", &(pt->i)); printf("%p\n", &(pt->c)); printf("%p\n", &(pt->p)); return 0; }
運(yùn)行結(jié)果:
注意:上面的pt->p的偏移之所以是0×8而不是0×6,是因?yàn)閮?nèi)存對(duì)齊了(我在64位系統(tǒng)上)。關(guān)于內(nèi)存對(duì)齊,具體可以參看本站C語言內(nèi)存對(duì)齊實(shí)例詳解一文。
柔性數(shù)組
柔性數(shù)組成員(flexible array member)也叫伸縮性數(shù)組成員,這種代碼結(jié)構(gòu)產(chǎn)生于對(duì)動(dòng)態(tài)結(jié)構(gòu)體的需求。在日常的編程中,有時(shí)候需要在結(jié)構(gòu)體中存放一個(gè)長(zhǎng)度動(dòng)態(tài)的字符串,一般的做法,是在結(jié)構(gòu)體中定義一個(gè)指針成員,這個(gè)指針成員指向該字符串所在的動(dòng)態(tài)內(nèi)存空間,例如:
struct s_test { int a; double b; char* p; };
p指向字符串,這種方法造成字符串與結(jié)構(gòu)體是分離的,不利于操作。把字符串和結(jié)構(gòu)體連在一起的話,效果會(huì)更好,可以修改如下:
char a[] = "Hello world"; struct s_test *ptest = (struct s_test*)malloc(sizeof(s_test)+streln(a)+1); strcpy(ptest+1,a);
這樣一來,(char*)(ptestt + 1)就是字符串“hello world”的地址。這時(shí)候p成了多余的東西,可以去掉。但是,又產(chǎn)生了另外一個(gè)問題:老是使用(char*)(ptestt + 1)不方便。如果能夠找出一種方法,既能直接引用該字符串,又不占用結(jié)構(gòu)體的空間,就完美了,符合這種條件的代碼結(jié)構(gòu)應(yīng)該是一個(gè)非對(duì)象的符號(hào)地址,在結(jié)構(gòu)體的尾部放置一個(gè)0長(zhǎng)度的數(shù)組是一個(gè)絕妙的解決方案。不過,C/C++標(biāo)準(zhǔn)規(guī)定不能定義長(zhǎng)度為0的數(shù)組,因此,有些編譯器就把0長(zhǎng)度的數(shù)組成員作為自己的非標(biāo)準(zhǔn)擴(kuò)展,例如:
struct s_test2 { int a; double b; char c[0]; };
c就叫柔性數(shù)組成員,如果把ptest指向的動(dòng)態(tài)分配內(nèi)存看作一個(gè)整體,c就是一個(gè)長(zhǎng)度可以動(dòng)態(tài)變化的結(jié)構(gòu)體成員,柔性一詞來源于此。c的長(zhǎng)度為0,因此它不占用test的空間,同時(shí)ptest->c就是“hello world”的首地址,不需要再使用(char*)(ptestt + 1)這么丑陋的語法了。
鑒于這種代碼結(jié)構(gòu)所產(chǎn)生的重要作用,C99甚至把它收入了標(biāo)準(zhǔn)中:
As a special case, the last element of a structure with more than one named member may have an incomplete array type; this is called a flexible array member.
C99使用不完整類型實(shí)現(xiàn)柔性數(shù)組成員,標(biāo)準(zhǔn)形式是這樣的:
struct s_test { int a; double b; char c[]; };
c同樣不占用test的空間,只作為一個(gè)符號(hào)地址存在,而且必須是結(jié)構(gòu)體的最后一個(gè)成員。柔性數(shù)組成員不僅可以用于字符數(shù)組,還可以是元素為其它類型的數(shù)組,例如:
struct s_test { int a; double b; float[]; };
首先,我們要知道,0長(zhǎng)度的數(shù)組在ISO C和C++的規(guī)格說明書中是不允許的。這也就是為什么在VC++2012下編譯你會(huì)得到一個(gè)警告:“arning C4200: 使用了非標(biāo)準(zhǔn)擴(kuò)展 : 結(jié)構(gòu)/聯(lián)合中的零大小數(shù)組”。
那么為什么gcc可以通過而連一個(gè)警告都沒有?那是因?yàn)間cc 為了預(yù)先支持C99的這種玩法,所以,讓“零長(zhǎng)度數(shù)組”這種玩法合法了。關(guān)于GCC對(duì)于這個(gè)事的文檔在這里:“Arrays of Length Zero”,文檔中給了一個(gè)例子,完整代碼如下:
#include <stdlib.h> #include <string.h> struct line { int length; char contents[0]; // C99的玩法是:char contents[]; 沒有指定數(shù)組長(zhǎng)度 }; int main(){ int this_length=10; struct line *thisline = (struct line *) malloc (sizeof (struct line) + this_length); thisline->length = this_length; memset(thisline->contents, 'a', this_length); return 0; }
上面這段代碼的意思是:我想分配一個(gè)不定長(zhǎng)的數(shù)組,于是我有一個(gè)結(jié)構(gòu)體,其中有兩個(gè)成員,一個(gè)是length,代表數(shù)組的長(zhǎng)度,一個(gè)是contents,代碼數(shù)組的內(nèi)容。后面代碼里的 this_length(長(zhǎng)度是10)代表是想分配的數(shù)據(jù)的長(zhǎng)度。
相信本文所述對(duì)大家C程序設(shè)計(jì)的學(xué)習(xí)有一定的借鑒價(jià)值。
上一篇:Cocos2d-x學(xué)習(xí)筆記之Hello World!
欄 目:C語言
下一篇:C標(biāo)準(zhǔn)庫&lt;assert.h&gt;的實(shí)現(xiàn)詳解
本文標(biāo)題:C語言柔性數(shù)組實(shí)例詳解
本文地址:http://mengdiqiu.com.cn/a1/Cyuyan/3404.html
您可能感興趣的文章
- 04-02c語言函數(shù)調(diào)用后清空內(nèi)存 c語言調(diào)用函數(shù)刪除字符
- 04-02c語言的正則匹配函數(shù) c語言正則表達(dá)式函數(shù)庫
- 04-02func函數(shù)+在C語言 func函數(shù)在c語言中
- 04-02c語言中對(duì)數(shù)函數(shù)的表達(dá)式 c語言中對(duì)數(shù)怎么表達(dá)
- 04-02c語言用函數(shù)寫分段 用c語言表示分段函數(shù)
- 04-02c語言編寫函數(shù)冒泡排序 c語言冒泡排序法函數(shù)
- 04-02c語言沒有round函數(shù) round c語言
- 04-02c語言分段函數(shù)怎么求 用c語言求分段函數(shù)
- 04-02C語言中怎么打出三角函數(shù) c語言中怎么打出三角函數(shù)的值
- 04-02c語言調(diào)用函數(shù)求fibo C語言調(diào)用函數(shù)求階乘


閱讀排行
- 1C語言 while語句的用法詳解
- 2java 實(shí)現(xiàn)簡(jiǎn)單圣誕樹的示例代碼(圣誕
- 3利用C語言實(shí)現(xiàn)“百馬百擔(dān)”問題方法
- 4C語言中計(jì)算正弦的相關(guān)函數(shù)總結(jié)
- 5c語言計(jì)算三角形面積代碼
- 6什么是 WSH(腳本宿主)的詳細(xì)解釋
- 7C++ 中隨機(jī)函數(shù)random函數(shù)的使用方法
- 8正則表達(dá)式匹配各種特殊字符
- 9C語言十進(jìn)制轉(zhuǎn)二進(jìn)制代碼實(shí)例
- 10C語言查找數(shù)組里數(shù)字重復(fù)次數(shù)的方法
本欄相關(guān)
- 04-02c語言函數(shù)調(diào)用后清空內(nèi)存 c語言調(diào)用
- 04-02func函數(shù)+在C語言 func函數(shù)在c語言中
- 04-02c語言的正則匹配函數(shù) c語言正則表達(dá)
- 04-02c語言用函數(shù)寫分段 用c語言表示分段
- 04-02c語言中對(duì)數(shù)函數(shù)的表達(dá)式 c語言中對(duì)
- 04-02c語言編寫函數(shù)冒泡排序 c語言冒泡排
- 04-02c語言沒有round函數(shù) round c語言
- 04-02c語言分段函數(shù)怎么求 用c語言求分段
- 04-02C語言中怎么打出三角函數(shù) c語言中怎
- 04-02c語言調(diào)用函數(shù)求fibo C語言調(diào)用函數(shù)求
隨機(jī)閱讀
- 04-02jquery與jsp,用jquery
- 08-05織夢(mèng)dedecms什么時(shí)候用欄目交叉功能?
- 01-10C#中split用法實(shí)例總結(jié)
- 01-11ajax實(shí)現(xiàn)頁面的局部加載
- 08-05dedecms(織夢(mèng))副欄目數(shù)量限制代碼修改
- 08-05DEDE織夢(mèng)data目錄下的sessions文件夾有什
- 01-10使用C語言求解撲克牌的順子及n個(gè)骰子
- 01-10SublimeText編譯C開發(fā)環(huán)境設(shè)置
- 01-10delphi制作wav文件的方法
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文