1. 程式人生 > >結構體(宣告、初始化、記憶體對齊、如何傳參)

結構體(宣告、初始化、記憶體對齊、如何傳參)

結構基礎知識

聚合資料型別能夠同時儲存超過一個的單獨資料。C提供了兩種型別的聚合資料型別,分別是陣列和結構體。陣列是相同元素的集合,它的每個元素是通過下標引用或指標間接訪問的。結構體也是一些值的的集合,這些值稱為它 的成員,但一個結構的成員可能具有不同的型別。陣列元素可以通過下標訪問,這是因為陣列元素長度相同,但在結構體中並非如此,由於每個成員的型別可能不同,那麼長度也就可能不同,所以就不能通過下標來訪問。但是結構體成員都有自己的名字,他們是通過名字訪問的。另外,結構體在表示式中使用時,不能被替換為指標。結構體變數也無法使用下標來選擇特定的成員。

結構體的宣告


這個結構體建立了結構體變數x,結構體包含了2個成員:整型a,字元ch。

結構體宣告哪些可以省略?

標籤A可以省略,那麼就是匿名結構體型別,但不建議。在宣告時可以沒有結構體變數x,如果有,那麼該變數為全域性變數。如果在main函式中,就是區域性變數。

如下:


struct A  x;

int          x;

struct A 相當於int ,也就是型別,屬於結構體型別,x是結構體變數。

a[20]包含了20個結構,p是一個指標,它指向結構。

上面兩個結構都忽略了結構體標籤(如A),那麼這個語句成立嗎?p=&x?

警告:這兩個宣告被編譯器當做兩種截然不同 的型別,即使成員相同。所以,變數a,p,x,型別不同,不可p=&x。


注:用typedef後,simple是個型別名,可以建立變數。

訪問結構體成員

通過.操作符訪問成員:


通過->進行訪問:


兩者結果為:10  zhangsan

結構體自引用

我們已經知道在結構體中可以包含陣列,指標,標量,結構體...那麼結構體裡面能不能包含該結構體本身呢?


不可以,因為不知道結構體大小,無法開闢空間存y。

正確的結構體自引用如下:


因為struct stu *y是指標型別,即為4個位元組,可以開闢空間。

結構的不完整宣告

偶爾,必須宣告一些相互之間存在依賴的結構。即,一個結構包含了另一個結構的一個或多個成員。和自引用一樣,至少一個結構必須在另一個結構中以指標的形式存在。問題在於宣告部分:如果每個結構體都引用了其他 結構的標籤,哪個結構應該首先宣告?

這個問題的解決方案是使用不完整宣告,它宣告一個作為結構標籤的識別符號。然後,把這個標籤用在不需要知道這個結構的長度的宣告中,如宣告指向這個結構的指標。


結構體變數的定義和初始化

結構的初始化方式和陣列初始化很相似。一個位於一對花括號內部,由逗號分隔的初始值列表可用於結構的初始化。這些值根據結構成員列表的順序寫出。


注:陣列不可以整體賦值,可整體初始化。同理,結構體不可整體賦值,可以整體初始化。結構體地址數值等於第一個成員地址數值。

結構體記憶體對齊

為什麼存在記憶體對齊?

1.平臺原因(移植原因)

不是所有的硬體平臺都能訪問任意地址上的任意資料;某些硬體平臺只能在某些地址處取某些特定型別的資料,否則就丟擲硬體異常。

2.效能原因:

資料結構(尤其是棧)應該盡能地在自然邊界上對齊。原因在於,為了訪問未對齊的記憶體,處理器需要做兩次記憶體訪問;而對齊的記憶體訪問需要訪問一次。

圖如下:


結構體對齊規則:

1.第一個成員在與結構體變數偏移量為0的地址處。

2.其他成員變數要對齊到某個數字(對齊數)的整數倍的地址處。對齊數=編譯器預設的對齊數與該成員大小的較小值。VS中預設對齊數為8,linux預設對齊數為4.

3.結構體總大小為最大對齊數(每個成員都有一個對齊數)的整數倍。

4.如果嵌套了結構體的情況,巢狀的結構體對齊到自己的最大對齊數的整數倍處,結構體的整體大小就是所有最大對齊數(含巢狀結構體的對齊數)的整數倍。

那麼首先看一道題:


通過記憶體對齊規則,答案肯定不是6,答案是12,解釋如下:


再看其他例子:


結果為8。1+1+2+4=8,8是最大對齊數4的倍數。


結果為16。8+1+3+4=16,16是最大對齊數4的倍數。


結果為32。1+7+16+8=32,32是最大對齊數8的倍數。

結構體傳參

我們知道陣列傳參會發生降級,那麼結構體會不會降級呢?


結構體傳參有兩種形式,一個是傳結構體,一個是傳地址,但是建議選擇傳地址。因為在棧幀知識中,函式傳參,是需要壓入棧的,但是如果傳結構體物件時,結構體過大,所佔空間也就過大,會導致效能下降。

結論:結構體傳參,是不會發生降級,要將引數設定為結構體的地址。

相關推薦

結構陣列的指標初始記憶體釋放

結構體如下: Typedef structstudent { Int num; Char* name; } Tom,*Lily; 如果定義成Tom的形式,不需要為結構體分配記憶體,但是需要對name分配記憶體 Tom.name =(char*)malloc(sizeof(

5. C 結構 陣列的指標 初始記憶體釋放

結構體如下: struct student{ Int num; Char* name; } Tom,*Lily; 1.如果定義成Tom的形式,不需要為結構體分配記憶體,但是需要對name

結構宣告初始記憶體如何

結構基礎知識聚合資料型別能夠同時儲存超過一個的單獨資料。C提供了兩種型別的聚合資料型別,分別是陣列和結構體。陣列是相同元素的集合,它的每個元素是通過下標引用或指標間接訪問的。結構體也是一些值的的集合,這些值稱為它 的成員,但一個結構的成員可能具有不同的型別。陣列元素可以通過下

C語言結構宣告中冒號的使用佔位符 & C結構的亂序初始

有些資訊在儲存時,並不需要佔用一個完整的位元組, 而只需佔幾個或一個二進位制位。例如在存放一個開關量時,只有0和1 兩種狀態, 用一位二進位即可。為了節省儲存空間,並使處理簡便,C語言又提供了一種資料結構,稱為“位域”或“位段”。所謂“位域”是把一個位元組中的二進位劃分為

Java中陣列表示1一維陣列的定義初始記憶體中陣列的表示

各個語言中都有陣列,但Java中是有區別的,Java中只有一維陣列,沒有多維陣列,多維陣列使用陣列的陣列來表示的。所以下面介紹的陣列主要以一維陣列來表示。 1.陣列的定義 陣列型別也是一種型別,本身是一種引用型別,例如int是一個基本資料型別,但是int[]就是一種引用資

定義結構變量及初始

style 不想 占用空間 clas 個學生 truct 學生 釋放 ring   雖然已經了解結構體類型,但是結構體類型變量的定義只有一種方法麽,這個當然不是的,所以我把我所知道的幾種方法列出來供給大家參考一下;   首先是第一種,也是我們經常用的一種: 1 #inc

結構和陣列的初始和賦值

{} 這種語法不能用於結構體的賦值,只能用於初始化。例如這樣是錯誤的: struct complex_struct z1; z1 = { 3.0, 4.0 }; 結構體變數之間使用賦值運算子是允許的,用一個結構體變數初始化另一個結構體變數也是允許的; 陣列不

OAI UE結構和執行緒初始

UE結構體和執行緒初始化 UE重要結構圖 UE call stack UE init PHY_VARS_UE * PHY_vars_UE_g[MAX_UE][MAX_NUM_CCs]={NULL}; UE建立三大執行緒    載入USRP硬體 &nbs

結構中函式指標初始

/** * 為結構體中的指標陣列賦值 */ #include <stdio.h> typedef struct test { void (*p)(void); void (*q)(void); void (*y)(void); }t

C語言之struct大小首地址與記憶體—由結構成員地址得到結構首地址

被問到如下問題:給定一個結構體中某個變數地址,可否得到結構體變數的地址? 答案是可以,但是對不同的場合有不同的結果;這與微處理器平臺、編譯器的處理不可分割。 首先,對於處理器,大尾端、小尾端的因素必須考慮; 其次: 一、 ANSIC標準中並沒有規定,相鄰宣告的變數在記憶體中一定要相鄰。 為了程式的高效性,

結構的4種初始方式

[objc]  view plain  copy //   //  main.c   //  C語言學習

[收集]記憶體sizeof#pragma pack(n)

本文主要包括二個部分: 第一部分:重點介紹在VC中,怎麼樣採用sizeof來求結構的大小,以及容易出現的問題,並給出解決問題的方法, 第二部分:總結出VC中sizeof的主要用法。 1、 sizeof應用在結構上的情況請看下面的結構:struct MyStruct { double dda1; ch

Servlet學習筆記之Servlet原理初始生命週期結構體系

Servlet是用java語言編寫的應用到Web伺服器端的擴充套件技術,與java物件的區別是,Servlet物件主要封裝了對HTTP請求的處理,並且它的執行需要Servlet容器的支援(以下會介紹原因,也可以看之前的一篇介紹Servlet容器的部落格,(http://blog.csdn.net/megust

淺析C++中結構的定義初始和引用

#include<iostream>using namespace std; struct Date{        //宣告一個結構體型別Date   int month;      //日期中的月份   int day;        //日期中的天   int year;       //日

Java簡單類變數詳解概念和分類宣告命名初始

1初識JAVA簡單類 (1)建立第一個Java程式的具體步驟: 第一步:建立一個工程,在Package Explorer空白區域中右擊New->點選Java Project->填寫Project name(例如:javastudy),然後填寫Finish

Spring Boot實戰筆記-- Spring常用配置Bean的初始和銷毀Profile

div nbsp troy string 實例化 public ive work 初始 一、Bean的初始化和銷毀   在我們的實際開發的時候,經常會遇到Bean在使用之前或之後做些必要的操作,Spring對Bean的生命周期操作提供了支持。在使用Java配置和註解配置下提

變量的聲明定義初始

局部變量 聲明和定義 包含 int 外部變量 存儲 變量聲明 bsp 運行 先分享一下關於變量聲明和定義的區別: 變量的聲明有兩種情況: (1) 一種是需要建立存儲空間的(定義、聲明)。例如:int a在聲明的時候就已經建立了存儲空間。 (2) 另一種是不需要

Effective C++筆記之一:宣告定義初始與賦值

一.宣告(Declaration)        區分宣告和定義可以讓C++支援分開編譯,宣告常常見於標頭檔案中。原始檔包含標頭檔案之後,就可以使用這個變數,即使沒有看到該變數的定義。 宣告的語法如下: extern int i; // object decl

【C++】類中靜態成員的宣告初始

【C++】類中靜態成員的宣告、初始化 類中靜態成員的宣告 初始化 靜態資料成員值的改變 完整例子 有參考大佬 零點零一 的文章: https://blog.csdn.net/thanklife/article/details/784

tensorflow入門 變數的定義初始值的檢視

1、常量 constant是TensorFlow的常量節點,通過constant方法建立,其是計算圖(Computational Graph)中的起始節點,是傳入資料; import tensorflow as tf sess = tf.Interact