C說話柔性數組實例詳解。本站提示廣大學習愛好者:(C說話柔性數組實例詳解)文章只能為提供參考,不一定能成為您想要的結果。以下是C說話柔性數組實例詳解正文
本文實例剖析了C說話柔性數組的概念及用法,關於進一步進修C法式設計有必定的自創價值。分享給年夜家供年夜家參考。詳細以下:
普通來講,構造中最初一個元素許可是未知年夜小的數組,這個數組就是柔性數組。但構造中的柔性數組後面必需至多一個其他成員,柔性數構成員許可構造中包括一個年夜小可變的數組,sizeof前往的這類構造年夜小不包含柔性數組的內存。包括柔數構成員的構造用malloc函數停止內存的靜態分派,且分派的內存應當年夜於構造的年夜小以順應柔性數組的預期年夜小。柔性數組究竟若何應用?
不完全類型
C和C++關於不完全類型的界說是一樣的,不完全類型是如許一品種型,它缺少足夠的信息例如長度去描寫一個完全的對象。
不完全類型舉例:
前向聲明就是一種經常使用的不完全類型
struct test; //test 只給出了聲明,沒有給出界說
不完全數據類型必需經由過程某種方法彌補完全,能力使它們停止實例化。不然只能用於界說指針或援用,由於此時實例化的是指針或援用自己,不是base和test對象
一個未知長度的數組也屬於不完全類型:
extern int a[];
extern 症結字不克不及去失落,由於數組的長度未知,不克不及作為界說湧現。不完全類型的數組須要彌補完全能力應用。不完全類型的數組可以經由過程幾種方法彌補完全,年夜括號情勢的初始化就是個中的一種方法:
int a[] = { 10,20 };
構造體
起首,我們須要曉得——所謂變量,實際上是內存地址的一個抽像名字而已。在靜態編譯的法式中,一切的變量名都邑在編譯時被轉成內存地址。機械是不曉得我們取的名字的,只曉得地址。
所以有了——棧內存區,堆內存區,靜態內存區,常量內存區,我們代碼中的一切變量都邑被編譯器事後放到這些內存區中。
有了下面這個基本,我們來看一下構造體中的成員的地址是甚麼?我們先簡略化一下代碼:
struct test{ int i; char *p; };
下面代碼中,test構造中i和p指針,在C的編譯器中保留的是絕對地址——也就是說,他們的地址是絕對於struct test的實例的。假如我們有如許的代碼:
struct test t;
上面做個試驗:
#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; }
運轉成果:
我們可以看到,t.i的地址和t的地址是一樣的,t.p的址址絕對於t的地址多了個8。說白了,t.i 其實就是(&t + 0×0), t.p 的其實就是 (&t + 0×8)。0×0和0×8這個偏移地址就是成員i和p在編譯時就被編譯器給hard code了的地址。因而,你就曉得,不論構造體的實例是甚麼——拜訪其成員其實就是加成員的偏移量。
上面再來做個試驗:
#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; }
運轉成果:
留意:下面的pt->p的偏移之所所以0×8而不是0×6,是由於內存對齊了(我在64位體系上)。關於內存對齊,詳細可以參看本站C說話內存對齊實例詳解一文。
柔性數組
柔性數構成員(flexible array member)也叫伸縮性數構成員,這類代碼構造發生於對靜態構造體的需求。在平常的編程中,有時刻須要在構造體中寄存一個長度靜態的字符串,普通的做法,是在構造體中界說一個指針成員,這個指針成員指向該字符串地點的靜態內存空間,例如:
struct s_test { int a; double b; char* p; };
p指向字符串,這類辦法形成字符串與構造體是分別的,晦氣於操作。把字符串和構造體連在一路的話,後果會更好,可以修正以下:
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”的地址。這時候候p成了過剩的器械,可以去失落。然則,又發生了別的一個成績:總是應用(char*)(ptestt + 1)不便利。假如可以或許找出一種辦法,既能直接援用該字符串,又不占用構造體的空間,就完善了,相符這類前提的代碼構造應當是一個非對象的符號地址,在構造體的尾部放置一個0長度的數組是一個絕妙的處理計劃。不外,C/C++尺度劃定不克不及界說長度為0的數組,是以,有些編譯器就把0長度的數構成員作為本身的非尺度擴大,例如:
struct s_test2 { int a; double b; char c[0]; };
c就叫柔性數構成員,假如把ptest指向的靜態分派內存看做一個全體,c就是一個長度可以靜態變更的構造體成員,柔性一詞起源於此。c的長度為0,是以它不占用test的空間,同時ptest->c就是“hello world”的首地址,不須要再應用(char*)(ptestt + 1)這麼丑惡的語法了。
鑒於這類代碼構造所發生的主要感化,C99乃至把它支出了尺度中:
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應用不完全類型完成柔性數構成員,尺度情勢是如許的:
struct s_test { int a; double b; char c[]; };
c異樣不占用test的空間,只作為一個符號地址存在,並且必需是構造體的最初一個成員。柔性數構成員不只可以用於字符數組,還可所以元素為其它類型的數組,例如:
struct s_test { int a; double b; float[]; };
起首,我們要曉得,0長度的數組在ISO C和C++的規格解釋書中是不許可的。這也就是為何在VC++2012下編譯你會獲得一個正告:“arning C4200: 應用了非尺度擴大 : 構造/結合中的零年夜小數組”。
那末為何gcc可以經由過程而連一個正告都沒有?那是由於gcc 為了事後支撐C99的這類弄法,所以,讓“零長度數組”這類弄法正當了。關於GCC關於這個事的文檔在這裡:“Arrays of Length Zero”,文檔中給了一個例子,完全代碼以下:
#include <stdlib.h> #include <string.h> struct line { int length; char contents[0]; // C99的弄法是:char contents[]; 沒有指定命組長度 }; 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; }
下面這段代碼的意思是:我想分派一個不定長的數組,因而我有一個構造體,個中有兩個成員,一個是length,代表數組的長度,一個是contents,代碼數組的內容。前面代碼裡的 this_length(長度是10)代表是想分派的數據的長度。
信任本文所述對年夜家C法式設計的進修有必定的自創價值。