今天來說一下C語言里的結構體(struct)、共用體(l聯合體)union、枚舉。
(一)結構體:struct
1.1 概念
- 是一種自定義的數據類型
- 結構體是構造類型的一種
- 不同數據類型的集合
- 地址空間連續,每次分配最大數據類型的寬度
- 占用內存為所有變量的總大小(注意字節對齊問題)
1.2 定義
1.先定義結構體類型,再說明結構體變量
struct stu
{char *name; //姓名int num; //學號int age; //年齡float score; //成績
};
struct stu student;
上面的程序使用strcuct關鍵字定義了一個結構體名為stu的結構體類型。和定義變量一樣,聲明一個結構體類型變量可以使用:數據類型 變量名 的形式。
struct stu student表示定義了一個變量名為stduent,類型為stu的結構體。該結構體含有4個成員:name、num、age、score
注意大括號后面的分號;不能少,這是一條完整的語句。
2.定義結構體類型的同時定義結構體變量
struct stu
{char *name; //姓名int num; //學號int age; //年齡float score; //成績
}student;
在定義時直接聲明結構體變量,只需要將結構體變量名放在花括號后面,并加上分號即可。
3.直接說明結構體變量
struct
{char *name; //姓名int num; //學號int age; //年齡float score; //成績
} student;
這種定義方式并不常用,這樣做書寫雖然簡單,但是因為沒有結構體名,后面就沒法用該結構體定義新的變量。
4.typedef重定義
typedef struct
{char *name; //姓名int num; //學號int age; //年齡float score; //成績
} STU;
STU student;
這種方式比較常見,我們使用typedef重定義結構體為STU,這里STU就是此結構體類型,可以用STU去定義結構體變量
1.3 初始化
1.在定義結構體變量的時候全部初始化
struct stu
{char *name; //姓名int num; //學號int age; //年齡float score; //成績
}student={“ha”,1234,56,99};
2.定義完結構體變量后,之后只能單個賦值
struct stu
{char *name; //姓名int num; //學號int age; //年齡float score; //成績
};
struct stu student;
student.name="ha";
student.num=1234;
student.age=56;
student.score=99;
1.4 調用
結構體變量.成員
結構體變量名+點(’.’)+成員就可以調用了
1.5 結構體指針
當一個指針變量指向結構體時,我們就稱它為結構體指針。C語言結構體指針的定義形式一般為:
struct 結構體名 *變量名;
//結構體
struct stu{char *name; //姓名int num; //學號int age; //年齡float score; //成績
} stu1 = { "hah", 12, 18, 23, 136.5 };
//結構體指針
struct stu *pstu = &stu1;
注意結構體變量名和數組名不同,數組名在表達式中會被轉換為數組指針,而結構體變量名不會,無論在任何表達式中它表示的都是整個集合本身,要想取得結構體變量的地址,必須在前面加&,所以給 pstu 賦值只能寫作:
1.6 獲取結構體成員
通過結構體指針可以獲取結構體成員,一般形式為:
(*pointer).memberName
或者:
pointer->memberName
第一種寫法中,.的優先級高于*,(pointer)兩邊的括號不能少。如果去掉括號寫作pointer.memberName,那么就等效于*(pointer.memberName),這樣意義就完全不對了。
第二種寫法中,->是一個新的運算符,習慣稱它為“箭頭”,有了它,可以通過結構體指針直接取得結構體成員;這也是->在C語言中的唯一用途。
1.7 結構體內存分析
注意點
- 給整個結構體變量分配儲存空間和數組一樣,從內存地址比較大的開始分配
- 給結構體變量中的屬性分配儲存空間也和數組一樣,從所占內存地址比較小的開始分配
- 定義結構體類型不會分配儲存空間,只有定義結構體變量的時候才會分配儲存空間
- 結構體在分配內存的時候,會做一個內存對齊的操作
- 會先獲取所有屬性中占用內存最大的屬性的字節數
- 然后在開辟出最大屬性字節的內存給第一個屬性,如果分配給第一個屬性之后還能繼續分配給第二個屬性,那么就繼續分配給第二個屬性
- 如果分配給第一個屬性之后,剩余的內存不夠分配給第二個屬性了,那么會再次開辟最大屬性的內存,再次分配 依次類推
#include <stdio.h>int main(){//定義結構體struct Person{char name; // 1 個節點 //開辟4個字節 char 占用1個int age; // 4個字節 // 剩余三個 不夠int 再開辟4個字節int money; // 4個字節 // 再開辟4個字節};struct Person p; // 所以p = 4+4+4printf("sizeof(p) = %i\n",sizeof(p)); // 12個字節return 0;
}
(二)共用體(聯合體):union
2.1概念
- 所有變量共用一段空間
- 每次分配按最大長度進行分配
- 是一種構造數據類型
- 同一時刻只能保存一個成員的值
- 不能直接引用共用體變量名
2.2定義
它的定義和結構體一樣,分為先定義共用體再說明共用體變量、在定義共用體的同時說明共用體變量、直接說明共用體變量
union 共用體名{成員列表
};
示例:
//先定義共用體再說明共用體變量
union data{int n;char ch;double f;
};
union data a, b, c;
2.3 引用
和結構體一樣,通過共用體變量名 . 成員名
union data{int n;char ch;double f;
} a, b, c;
a.n=3;
關于共用體的詳細介紹可以看下這篇文章C語言共用體(C語言union用法)詳解,講到共用體這里要說明一下大小端模式的問題。
小端模式:低地址存放低字節,高地址存放高字節
大端模式:低地址存放高字節,高地址存放低字節
(三)枚舉:enum
3.1 概念
- 作用:列舉出所有的可能性,增強代碼的可閱讀性
- 枚舉成員都是常量
- 不能再對已經定義好的枚舉常量賦值
3.1 定義
enum 枚舉名
{
枚舉變量
};
示例:
enum week
{
Mon, Tues, Wed, Thurs, Fri, Sat, Sun};
typedef enum
{
Mon, Tues, Wed, Thurs, Fri, Sat, Sun
}Date;
枚舉是一種類型,通過它可以定義枚舉變量:
Date a,b,c
我們也可以給每個名字都指定一個值:
enum week{ Mon = 1, Tues = 2, Wed = 3, Thurs = 4, Fri = 5, Sat = 6, Sun = 7 };
更為簡單的方法是只給第一個名字指定值:
enum week{ Mon = 1, Tues, Wed, Thurs, Fri, Sat, Sun };
這樣枚舉值就從 1 開始遞增,跟上面的寫法是等效的。
也可以在定義枚舉類型的同時定義變量:
enum week{ Mon = 1, Tues, Wed, Thurs, Fri, Sat, Sun } a, b, c;
有了枚舉變量,就可以把列表中的值賦給它:
enum week{ Mon = 1, Tues, Wed, Thurs, Fri, Sat, Sun };
enum week a = Mon, b = Wed, c = Sat;
或者:
enum week{ Mon = 1, Tues, Wed, Thurs, Fri, Sat, Sun } a = Mon, b = Wed, c = Sat;
特點:可以在定義枚舉時給成員賦值,被賦值的成員往后依次增加1,也可以在中間改變某一個成員的值。
3.1 引用
直接使用就行,需要注意的是**枚舉列表中的數據作用范圍是全局的,不能在定義與它們名字相同的白能量;Mon、Tues、Wed 等都是常量,不能對它們賦值,只能將它們的值賦給其他的變量。
示例:
#include <stdio.h>
int main(){enum week{ Mon = 1, Tues, Wed, Thurs, Fri, Sat, Sun } day;scanf("%d", &day);switch(day){case 1: puts("Monday"); break;case 2: puts("Tuesday"); break;case 3: puts("Wednesday"); break;case 4: puts("Thursday"); break;case 5: puts("Friday"); break;case 6: puts("Saturday"); break;case 7: puts("Sunday"); break;default: puts("Error!");}return 0;
}
Mon、Tues、Wed 這些名字都被替換成了對應的數字。這意味著,Mon、Tues、Wed 等都不是變量,它們不占用數據區(常量區、全局數據區、棧區和堆區)的內存,而是直接被編譯到命令里面,放到代碼區,所以不能用&取得它們的地址。這就是枚舉的本質。
本文章僅供學習交流用禁止用作商業用途,文中內容來水枂編輯,如需轉載請告知,謝謝合作
微信公眾號:zhjj0729
微博:文藝to青年