數據類型
1.基本類型/基礎類型
-
整型
-
短整型:short[int] --2字節
-
基本整型:int --4字節
-
長整型:long[int] --32位4字節/64位8字節
-
長長整型:long long [int] (C99)
注意:以上類型又都分為signed(有符號)和unsigned(無符號)
-
-
浮點型
-
單精度:float --4字節
-
雙精度:double --8字節
-
長雙精度: long double --(C99新增)
-
-
字符型
-
char -- 1字節
-
2.指針類型
-
數據類型*:
int* char* float*
--8字節 -
void*:通用類型指針(萬能指針)--8字節
3.空值類型
-
void:無返回值,無形參(不能定義變量)
4.構造類型(自定義類型)
-
結構體類型:struct
-
共用體/聯合體類型:union
-
枚舉類型:enum
結構體
結構體的定義(定義類型)
- 定義:自定義數據類型的一種,關鍵字struct,結構體類型的變量可以存儲多個不同數據類型的數據。
- 語法:
struct 結構體名 //定義數據類型名字
{數據類型1 成員名稱1;數據類型2 成員名稱2;...
}
注意:結構體中定義的變量,稱之為成員變量
-
格式說明:
-
結構體名:合法的標識符,建議首字母大寫(所謂的結構體名,就是自定義類型的類型名稱)
-
數據類型n:C語言支持的所有類型(包括函數,函數在這里用函數指針表示)
-
成員名稱n:合法的標識符,就是變量的命名標準
-
數據類型n成員名稱n:類似于定義變量,定義了結構體中的成員
-
- 注意:結構體在定義的時候,成員不能賦值
struct Cat
{int age = 5; //錯誤double height; //正確
}
常見的定義格式
-
方式1:常規定義(命名結構體,只定義數據類型)---推薦
-
方式2:定義匿名結構體(常用于作為其他結構體的成員使用)
-
注意:定義匿名結構體的同時必須定義結構體成員,否則編譯報錯,結構體可以作為另一個結構體的成員(內嵌)
總結:
-
結構體可以定義在局部位置,也可以定義在全局位置(用的比較多,因為可以實現復用)
-
全局位置的結構體名和局部位置的結構體名可以相同,遵循就近原則(和變量的定義同理)
-
-
結構體類型的使用:
利用結構體類型定義變量、定義數組、也可以作為函數的返回值和參數:結構體類型的使用與基本數據類型的使用類似。
結構體變量的定義(定義變量)
三種形式定義結構體變量
結構體變量也稱之為結構體實例
-
第一種:
①先定義結構體(定義數據類型)
②然后使用(使用數據類型定義變量)
-
第2種
①在定義結構體的同時,定義結構體變量
舉例:
?struct A{int a;char b;}x,y;
此時定義了一個結構體A,x和y是這個結構體類型的變量。
-
第3種(不推薦)
在定義匿名結構體的同時,定義結構體變量
struct A
{int a;char b;struct{int a1;char b1;}c,d;
}e;
此時定義了一個沒有名字的結構體(匿名結構體):c,d是這個結構體類型的變量
-
匿名結構體
-
優點:少些一個結構體名稱
-
缺點:只能使用一次,定義結構體類型的同時必須定義變量
-
應用場景:
-
當結構體的類型只需要使用一次,并且定義類型的同時定義變量。
-
作為其他結構體的成員使用。
-
-
-
定義結構體的同時,定義結構體變量初始化
-
結構體成員部分初始化時,大括號{}不能省略
-
結構體成員,沒有默認值,是隨機值。
-
結構體變量的使用
-
結構體變量訪問結構體成員
-
語法:
?結構體變量名.成員名;
①可以通過訪問給成員賦值(存數據)
②可以通過訪問獲取成員的值(取數據)
-
結構體變量未初始化,結構體的成員是隨機值(和普通的變量、數組同理)
-
-
結構體變量在定義時,可以初始化
-
建議用大括號標明數據的范圍
-
結構體成員初始化,可以部分初始化(和數組類以),部分初始化時一定要帶大括號標明數據的范圍。
-
結構體數組的定義
-
什么時候需要結構體數組
比如:我們需要管理一個學生對象,只需要定義一個struct student kelei; 假如:我們需要管理一個班的學生對象,此時就需要定義一個結構體數組struct student stus[33];
-
四種形式定義結構體數組
-
第1種:結構體→結構體變量→結構體數組
-
第2種:結構體→結構體數組,
-
第3種:結構體、結構體數組一體化(含初始化)
-
第4種:結構體、結構體數組一體化(不含初始化)
-
結構體數組的訪問
語法:
結構體 -> 成員名
舉例:
(*p).成員名
p -> 成員名
注意:
當
->
和[]
共存的時候,它們的優先級關系:[]?
>??->
構造體類型
構造體數組
舉例:
#include <stdio.h>#pragma pack(1)
struct Student
{char *name;int age;float score[3];
};
#pragma pack()void stu_print(struct Student *stu)
{printf("學生的名字是:%s\n",stu -> name);printf("學生的年齡是:%d\n",stu -> age);printf("語文成績是:%.2f\n",stu -> score[0]);printf("數學成績是:%.2f\n",stu -> score[1]);printf("英語成績是:%.2f\n",stu -> score[2]);
}int get_avg(struct Student *stu)
{struct Student *p = stu;for(; p < stu + 2; p++){float sum = 0;for(int i = 0; i < 3; i ++){sum += p -> score[i];}float avg = sum / 3;printf("%s的平均分為:%.2f\n",p -> name, avg);}
}
int main(int argc,char *argv[])
{struct Student stu = {"張三",20,{90,88,75}};stu_print(&stu);struct Student stus[] = {{"李四",21,{67,87,68}},{"王五",22,{76,92,70}}};get_avg(stus);return 0;
}
構造體指針
-
定義:結構體類型的指針變量指向結構體變量或者數組的起始地址。
-
語法:
struct 結構體名 *指針變量列表;
- 舉例
#include <stdio.h>struct Product
{char *name;int id;int or_price;int now_price;char *production_deta;char *due_deta;
};typedef struct Product Pro;
//打印商品信息
void product_print(Pro *p)
{Pro *t_p = p;printf("名字是:%s\n",t_p -> name);printf("商品ID為:%d\n",t_p -> id);printf("原價為:%d\n",t_p -> or_price);printf("現價為:%d\n",t_p -> now_price);printf("生產日期:%s\n",t_p -> production_deta);printf("到期時間是:%s\n",t_p ->due_deta);
}
int main(int argc,char *argv[])
{//typedef struct Product Pro;Pro p1 = {"麻辣公主",10001,100,10,"2025,1,10","2025,2,10"};product_print(&p1);return 0;
}
構造體成員的訪問
結構體成員訪問
-
結構體數組名訪問結構體成員
-
語法
-
結構體數組名 -> 成員名;
(*結構體數組名).成員名;
-
結構體成員訪問符
-
.
:左側是結構體變量,也可以叫做結構體對象訪問成員訪問符,右側是結構體成員。 -
->
:左側是結構體指針,也可以叫做結構體指針訪問成員符右側是結構體成員 -
舉例
-
struct Person *p = persons; // p就是結構體指針
for(; p < persons + 3; p++)printf("%s:%d\n",p -> name, p -> count);
結構體是自定義數據類型,它是數據類型,用法類似于基本類型的 int ;結構體數組它是存放結構體對象的數組,類似于 int 數組存放 int 數據;基本類型數組怎么用,結構體數組就怎么用 ---> 可以遍歷,可以作為形式參數,也可以做指針等;
結構體類型求大小?
字節對齊
- 字節對齊的原因:
- 字節對齊規則
????????1. 默認對齊規則?結構體的每個成員按其類型大小和編譯器默認對齊數(通常是類型的自然對齊數)對?齊。 結構體的總大小必須是最大對齊數的整數倍。????????2. 對齊細節基本類型的對齊數 : char ( 1 字節)、 short ( 2 字節)、 int ( 4 字節)、 double (8字節)。結構體成員的對齊 :每個成員的起始地址必須是對齊數的整數倍。結構體總大小的對齊 :結構體的總大小必須是其最大對齊數的整數倍????????3. #pragma pack(n) 的影響 使用 #pragma pack(n) 可以強制指定對齊數為 n ( n 為 1 、 2、 4 、 8 、 16 )。此時:每個成員的對齊數取 n 和其類型大小的較小值。結構體的總大小必須是 n 和最大對齊數中的較小值的整數倍。
共用體
union 共用體名稱
{數據類型 成員名;數據類型 成員名;...
}
共用體的定義和結構體類似。1.可以有名字,也可以匿名2.共用體在定義時也可以定義共用體變量3.共用體在定義時也可以初始化成員4.共用體也可以作為形參和返回值類型使用5.共用體也可以定義共用體變量...???????? 也就是說,結構體的語法,共用體都支持注意:????????共用體弊大于利,盡量少用,一般很少用;????????共用體變量在某一時刻只能存儲一個數據,并且也只能取出一個數????????共用體所有成員共享同一內存空間,同一時間只能存儲一個值,可能導致數據覆蓋????????共用體和結構體都是自定義數據類型,用法類似于基本數據類型?????????共用體可以是共用體的成員,也可以是結構體的成員????????結構體可以是結構體的成員,也可以是共用體的成員
枚舉類型
建議:如果定義不相干的常量,使用宏定義(符號常量);如果需要定義一組相關的常量,如月份0~11,星期0-6,方向0-3等,使用枚舉,進行統一管理。以后正式開發中,switch的case后訪問的就是枚舉中的常量。
-
定義
我們一般情況下,定義常量使用宏定義(#define 宏名稱 值),宏定義非常適合沒有關聯關系的常量;但是有時候我們可能需要對一組擁有關聯關系的量進行定義,如月份0~11,星期0-6,方向0-3等,那么使用宏定義,就不是很清晰,也不方便統一管理,這個時候就需要用到枚舉。
枚舉的存在就是將多個擁有關聯關系的常量組合到一起,提高代碼的可讀性。
-
說明
枚舉類型定義了一組常量,我們在開發中直接使用這些常量。(常用)
當然枚舉類型也可以類似于結構體一樣定義變量等操作。(不常用)
枚舉常量有默認值,從0開始依次+1我們可以在定義時指定它的默認值,如果個別沒有斌值,可以根據賦值依次+1推導。
-
特點
定義了一組常量,類似于定義了多個符號常量(宏定義)。
提高了代碼的可讀性。
-
語法:
-
定義枚舉類型名以后就可以定義該枚舉類型的變量。(枚舉的成員是常量)
enum 枚舉類型名 變量列表;
? ? ? ?在定義枚舉類型的同時定義該枚舉類型的變量。
enum 枚舉類型名(枚舉元素列表) 變量列表;
? ? ? 直接定義枚舉變量(變量)。
enum(枚舉元素列表) 變量列表;
typedef
-
說明:給類型重命名,不會影響到類型本身。
-
作用:給己有的類型起別名
-
格式:
typedaef 已有類型名 新類型名;
- 舉例:
#include <stdio.h>struct Product
{char *name;int id;int or_price;int now_price;char *production_deta;char *due_deta;
};typedef struct Product Pro;
//打印商品信息
void product_print(Pro *p)
{Pro *t_p = p;printf("名字是:%s\n",t_p -> name);printf("商品ID為:%d\n",t_p -> id);printf("原價為:%d\n",t_p -> or_price);printf("現價為:%d\n",t_p -> now_price);printf("生產日期:%s\n",t_p -> production_deta);printf("到期時間是:%s\n",t_p ->due_deta);
}
int main(int argc,char *argv[])
{//typedef struct Product Pro;Pro p1 = {"麻辣公主",10001,100,10,"2025,1,10","2025,2,10"};product_print(&p1);return 0;
}
-
應用場景:
-
數據類型復雜(結構體、共用體、枚舉、結構體指針、無符號的長整型)時使用
-
為了跨平臺的兼容性,例如:
-
size_t:類型重名后的數據類型:
typedef unsigned long size_t;
-
unit16:類型重命名后的數據類型。
-