結構體 (C語言)

C语言

C語言中,結構體(struct)指的是一種資料結構,是C語言中複合資料類型(aggregate data type)的一類。結構體可以被聲明為變數指標陣列等,用以實現較複雜的資料結構。結構體同時也是一些元素的集合,這些元素稱為結構體的成員(member),且這些成員可以為不同的類型,成員一般用名字訪問。

定義與聲明

結構體的定義如下所示,struct為結構體關鍵字,tag為結構體的標誌,member-list為結構體成員列表,其必須列出其所有成員;variable-list為此結構體聲明的變數。

 struct tag { member-list } variable-list ; 

在一般情況下,tag、member-list、variable-list這3部分至少要出現2個。以下為範例:

//此声明声明了拥有3个成员的结构体,分别为整型的a,字符型的b和双精度的c
//同时又声明了结构体变量s1
//这个结构体并没有标明其标签
struct 
{
    int a;
    char b;
    double c;
} s1;

//此声明声明了拥有3个成员的结构体,分别为整型的a,字符型的b和双精度的c
//结构体的标签被命名为SIMPLE,没有声明变量
struct SIMPLE
{
    int a;
    char b;
    double c;
};
//用SIMPLE标签的结构体,另外声明了变量t1、t2、t3
struct SIMPLE t1, t2[20], *t3;

//也可以用typedef创建新类型
typedef struct
{
    int a;
    char b;
    double c; 
} Simple2;
//现在可以用Simple2作为类型声明新的结构体变量
Simple2 u1, u2[20], *u3;

在上面的聲明中,第一個和第二聲明被編譯器當作兩個完全不同的類型,即使他們的成員列表是一樣的,如果令t3=&s1,則是非法的。

結構體的成員可以包含其他結構體,也可以包含指向自己結構體類型的指標,而通常這種指標的應用是為了實現一些更進階的資料結構如鏈結串列和樹等。

//此结构体的声明包含了其他的结构体
struct COMPLEX
{
    char string[100];
    struct SIMPLE a;
};

//此结构体的声明包含了指向自己类型的指针
struct NODE
{
    char string[100];
    struct NODE *next_node;
};

如果兩個結構體互相包含,則需要對其中一個結構體進行不完整聲明,如下所示:

struct B;    //对结构体B进行不完整声明

//结构体A中包含指向结构体B的指针
struct A
{
    struct B *partner;
    //other members;
};

//结构体B中包含指向结构体A的指针,在A声明完后,B也随之进行声明
struct B
{
    struct A *partner;
    //other members;
};

結構體成員訪問

結構體成員依據結構體變數類型的不同,一般有2種訪問方式,一種為直接訪問,一種為間接訪問。直接訪問應用於普通的結構體變數,間接訪問應用於指向結構體變數的指標。直接訪問使用結構體變數名.成員名,間接訪問使用(*結構體指標名).成員名或者使用結構體指標名->成員名。相同的成員名稱依靠不同的變數字首區分。

struct SIMPLE
{
    int a;
    char b;
};

//声明结构体变量s1和指向结构体变量的指针s2
struct SIMPLE s1, *s2;

//给变量s1和s2的成员赋值,注意s1.a和s2->a并不是同一成员
s1.a = 5;
s1.b = 6;
s2->a = 3;
s2->b = 4;

結構體變數儲存

在主記憶體中,編譯器按照成員列表順序分別為每個結構體變數成員分配主記憶體,當儲存過程中需要滿足邊界對齊的要求時,編譯器會在成員之間留下額外的主記憶體空間。如果想確認結構體占多少儲存空間,則使用關鍵字sizeof,如果想得知結構體的某個特定成員在結構體的位置,則使用offsetof宏(定義於stddef.h)。

struct SIMPLE
{
    int a;
    char b;
};

//获得SIMPLE类型结构体所占内存大小
int size_simple = sizeof( struct SIMPLE );

#define offsetof(structName, memName) (int)&((structName*) 0)->memName

//获得成员b相对于SIMPLE储存地址的偏移量
int offset_b = offsetof( struct SIMPLE, b );

匿名struct

匿名struct、匿名union以及C++的匿名class,是指既沒有類型名,也沒有直接用這種類型定義了對象;如果緊隨類型定義之後,又定義了該類型的對象,就不算是匿名類型,與普通情形的使用是一樣的。

匿名類型作為巢狀定義,即在一個外部類(這裡的類是指struct、union、class)的內部定義,則編譯器就在匿名類型定義之後定義一個無名變數,並把該匿名類型的資料成員的名字提升到匿名類的外部類的作用域內。如果匿名類型是連續巢狀,則最內部的匿名類型的成員名字被提升到最外部的可用變數名字訪問的類的作用域內。

例如,

    struct sn{
        struct { int i;};  /* 匿名 struct */
    } v1;

   v1.i=101;

參考書目

  • [美]Brian W.Kernighan,Dennis M.Ritchie. C程序设计语言(第2版·新版). 機械工業出版社 (中文). 
  • Kenneth A.Reek. C和指针. 人民郵電出版社 (中文).