爬爬爬之路 結構體的初始化及結構體陣列的初始化

2021-07-05 22:30:58 字數 3989 閱讀 9780

定義結構體如下

typedef struct mypoint  mypoint;

一:結構體變數的初始化

通常不能直接用結構體自身對自己進行賦值, 需通過結構體的變數來進行初始化

如:1.

mypoint p;

p.x = 5;

p.y = 6;

這是宣告和賦值分離

2.

也可宣告的同時進行賦值:

mypoint p = ;

3.

當然也可以宣告的同時, 不完整賦值

mypoint p1 = ;

如此時只給了乙個值, 按照順序, 這個值是傳給結構體中第乙個成員x, 第二個成員y沒有賦值, 預設為0

4.

c語言結構體不允許跳過某乙個值, 對其下乙個成員進行賦值

如:

mypoint p2 = ;

這是不允許的. 由於結構體空間是至上而下的, 在賦值的時候編譯器會從上往下訪問成員變數的位址, 首先訪問到成員x的位址, 對其賦值, 再找到成員y的位址, 對其賦值.這意味著 這個語句給第乙個成員賦上空值, 第二個成員賦值為5.  而空值是無法確定該值的位址, 也就是c語言找不到這個空值的位址, 也就是無法知道具體給x賦上了什麼值, 導致編譯失敗

那麼要怎麼做才能跳過第乙個值, 直接對後面的值賦值呢?

可以通過訪問成員變數的位址, 給其賦值

如:

mypoint p2 = ;

這麼做是直接跳過x的位址, 直接訪問到成員y的位址, 對其賦值

同理, 要給全部成員賦值也可以這麼寫:

mypoint p2 = ;

由於本方法是直接讓系統訪問到相應成員的空間對其賦值, 所以用本方法可以無視賦值順序, 先給第二個成員賦值 再給第乙個成員賦值結果也是一樣, 是可以通過編譯的

5.

可以通過強制轉換資料型別對其進行編譯

如:

mypoint p3 = (mypoint);

可以理解為  資料 是在結構體mypoint 宣告的空間進行的賦值  注意這裡的強轉名和變數的型別要匹配 不能再定義另乙個成員和mypoint 完全相同的結構體作為強轉名, 這會導致型別不匹配的問題不通過編譯

附: 通常同型別的強轉不會失敗, 但是卻常常是多此一舉的. 因為不論進不進行強轉 系統都會通過被複製的變數的型別開闢本型別的空間, 再宣告是否是本型別的資料就顯得沒有意義了, 所以通常會預設(mypoint)

二.結構體陣列的初始化

首先得明白兩個c語言規則

1.首先得明確一點, 在陣列的初始化中是不能進行宣告的

int a[5] = ;

比如這就是不允許的 同理, 結構體陣列也是一樣

原因是 :  因為宣告意味著新開闢乙個空間, 而賦值是已經給定好了一塊空間, 在這塊空間進行書寫.  由於位址是常量, 在賦值過程宣告, 相當於在一塊定值大小空間裡再開闢一塊新空間,相當於要改變原位址的值, 這是在c語言中不允許的. 

2.賦值是傳值過程, 比如說int a = 5; int b = a; 這時a 和 b均有空間, 賦值語句 b = a 意思是將 a空間的值 賦值乙份 再傳到 b的空間裡, a, b的空間依然還存在

明確了這2點後進行接下來的討論結構陣列的初始化.

1.

由於不能在陣列裡面不能在宣告乙個新的變數,所以:

mypoint po[2] = ;

這麼寫是不允許的. 那怎麼才能將結構體變數放到結構體陣列中呢

根據規則2, 可以先定義結構體變數, 然後將結構體變數的值傳入陣列中

mypoint p1 = , p2 = ;

mypoint po[2] = ;

這裡暫且稱p1, p2是陣列po的資料來源

這樣就讓陣列po複製儲存了 p1, p2的值了, 可以通過陣列的操作方式, 來對這個陣列進行處理

注意我用的是複製這個詞. 因為對陣列po進行數值操作, 資料來源的值是不會跟著改變的.

比如: 接上**繼續寫如下

po[0].x = 10;

printf("%d, %d",po[0].x, p1.x);

讓陣列po第0個元素(p1)的成員x 變成10, 再訪問資料**的結構體變數p1的成員x

發現列印結果為

10, 5

也就是說改變了陣列裡元素的值, 資料來源的值是不會隨著改變的

有興趣的讀者可以繼續實驗, 這裡就不跑題了  繼續討論結構體陣列的初始化方法

2.

如果不想在結構體陣列外再多餘開闢空間, 可以直接在陣列空間內賦值

mypoint po1[3] = ,,};

注意的是, 在陣列內賦值的規則同結構體變數的賦值規則, 只是在陣列內不能再宣告, 只能通過陣列的下標獲得對應元素

3.

同結構體的賦值, 若我定義了乙個元素個數為5 的陣列, 要怎麼跳過前邊的元素, 對後面的某個元素賦值呢?

比如:

mypoint po2[5] = ;

定義乙個元素個數為5的po2陣列, 直接對 下標為1, 4的元素進行賦值

根據前文的道理, 這是不允許的, 得通過直接找到並訪問要賦值的元素位址進行賦值才可以打破編譯器的順序賦值的順序進行想要的賦值

那怎麼直接訪問下標為1, 4的元素位址呢?

mypoint po2[5] = ;

可以直接通過下標來獲得對應下標的位址, 進行數值的賦值 

附: 結構體的空間開闢規則

如定義乙個結構體

struct p ;

它的空間大小是多少呢?

我們來計算一下:

陣列x是 int型陣列,共8個元素    int是4個位元組,    所以共佔4*10 = 40個位元組空間

變數y是int型   只有乙個   佔4個位元組空間

變數c是char型  只有乙個  只佔1個位元組空間

變數z是double型   只有乙個,   佔8個位元組空間

一共是40 + 4 + 1 + 8 = 53 , 所以乙個宣告乙個結構體變數, 會開闢大小為53的空間,  而實際上呢?

用sizeof()函式來看一下:

printf("%lu",sizeof(struct p));
結果為56.並不是53

這裡需要了解到結構體的自動位元組對齊

是什麼意思呢?

編譯器會先注意到結構體struct p內的成員 單個元素佔位元組空間最大的是8

所以編譯器會以8個位元組為單位開闢空間 順序是這樣的

先開闢了8個空間, 然後將陣列x放入, 放了a[0], a[1]以後空間已滿, 再放a[2]時就溢位了, 這時候就會再開闢8個空間, 如此遇滿再開乙個單位空間 直到結構體內的所有成員儲存完畢

#pragma pack(1)
結構體宣告的檔案裡 import語句下

加上本句, 可以取消結構體的自動位元組對齊功能  這時候再檢視結構體的空間  就會得到53了

爬爬爬之路 C語言 九 結構體指標與預編譯指令

結構體是一種自定義的資料型別 結構體的指標和基礎資料型別差不多 結構體變數名不能當成它的首元素位址 需要用取位址符獲得結構體變數的位址,但是結構變數的位址就相當於指向結構體變數的第乙個成員變數的位址 如以下 演示 typedef struct student student student stud...

結構體初始化

結構體變數初始化 tag 結構體,結構體變數,結構體變數宣告,結構體變數初始化,結構體變數引用,結構體成員變數引用 text c語言中引用變數的基本原則是在使用變數前,需要對變數進行定義並初始化。其方法是在定義變數的同時給其一初始值。結構體變數的初始化,遵循相同的規律。簡單變數的初始化形式如下 資料...

結構體的初始化

早先在看開源 中學到的乙個初始化結構體的技巧,今天剛剛用上。特意整理了一下。struct a 早先我所採用的方法 方法一 struct a a a.a 1 a.b 2 現在所採用的方法 方法二 是從開源 中所學會的,定義結構體的同時初始化結構體成員變數 struct a a 相比較方法一,方法二明顯...