C語言深入了解自定義數(shù)據(jù)類型的使用
一、自定義數(shù)據(jù)類型(上)
類型命名關(guān)鍵字 (typedef)
C語言中可以對(duì)類型賦予新名字
語法:
typedef Type New TypeName;
注意:typedef 并沒有創(chuàng)建新類型,只是創(chuàng)建了類型別名
深入 typedef 應(yīng)用
- typedef 可在函數(shù)中定義“局部類型名”
- typedef 常用于簡化類型名(如: unsigned long long)
- typedef 定義類型名,能夠以統(tǒng)一的方式創(chuàng)建變量(Type var; )
下面看一段代碼:
#include <stdio.h>
typedef unsigned char byte;
void func()
{
typedef byte uint8;
uint8 var = 200;
byte b = var; // 本質(zhì)為相同類型變量之間的初始化
printf("sizeof(uint8) = %d\n", sizeof(uint8));
printf("var = %d\n", var);
printf("b = %d\n", b);
}
int main()
{
// uint8 var = 1; // ERROR
byte b = 128;
func();
printf("sizeof(byte) = %d\n", sizeof(byte));
printf("b = %d\n", b);
return 0;
}??????下面為輸出結(jié)果:

????需要注意:本代碼中的 byte 和 uint8 為同一個(gè)自定義類型,所以它們之間可以相互賦值。
再來看一段代碼:
#include <stdio.h>
typedef float(FArr5)[5]; // 定義數(shù)組類型名
typedef int(IFuncII)(int, int); // 定義函數(shù)類型名
typedef FArr5* PFArr5;
typedef IFuncII* PIFuncII;
float g_arr[5] = {0.1, 0.2, 0.3};
int add(int a, int b)
{
return a + b;
}
int main()
{
FArr5* pa = &g_arr; // float(*)[5]
IFuncII* pf = add; // int(*)(int,int)
PFArr5 npa = pa;
PIFuncII npf = pf;
int i = 0;
for(i=0; i<5; i++)
{
printf("%f\n", (*pa)[i]);
printf("%f\n", (*npa)[i]);
}
printf("%d\n", pf(2, 3));
printf("%d\n", npf(2, 3));
return 0;
}下面為輸出結(jié)果:

這里要特別注意函數(shù)指針的用法,可以通過 typedef 使得函數(shù)指針的定義簡化。
C語言中的結(jié)構(gòu)體( struct )
- struct 是C語言中的自定義類型關(guān)鍵字
- struct能夠定義不同數(shù)據(jù)類型變量的集合類型
語法:
struct TypeName
{
Type1 var1;
Type2var2;
......;
typeN varn;
};
下面看一段代碼:
#include <stdio.h>
#include <string.h>
struct Student
{
char name[20];
int id;
short major;
};
int main()
{
struct Student s1 = {"Autumn", 908, 1};
struct Student s2 = s1;
printf("s1.name = %s\n", s1.name);
printf("s1.id = %d\n", s1.id);
printf("s1.major = %d\n", s1.major);
strcpy(s2.name, "Hu");
s2.id = 909;
s2.major = 2;
printf("s2.name = %s\n", s2.name);
printf("s2.id = %d\n", s2.id);
printf("s2.major = %d\n", s2.major);
return 0;
}下面為輸出結(jié)果:

小結(jié)
- C語言中通過 typedef 關(guān)鍵字對(duì)數(shù)據(jù)類型賦予新名字
- typedef 并不會(huì)創(chuàng)建一個(gè)全新的數(shù)據(jù)類型
- struct 是C語言中的自定義類型關(guān)鍵字
- struct 用于創(chuàng)建不同數(shù)據(jù)類型變量的集合類型
二、自定義數(shù)據(jù)類型(中)?????
深入 struct 結(jié)構(gòu)體類型
- struct 結(jié)構(gòu)體變量的本質(zhì)是變量的集合
- struct 結(jié)構(gòu)體變量中的成員占用獨(dú)立的內(nèi)存
- struct 結(jié)構(gòu)體類型可用 typedef 賦予新類型名
- 可定義struct 結(jié)構(gòu)體類型的指針,并指向?qū)?yīng)類型的變量
- struct 結(jié)構(gòu)體類型可先前置聲明,再具體定義
- 前置類型聲明只能用于指針定義
- 類型完整定義之后才能進(jìn)行變量定義
- struct 結(jié)構(gòu)體類型可以省略類型名
- 類型名省略時(shí),每次創(chuàng)建變量必須給出完整結(jié)構(gòu)體定義
- struct 結(jié)構(gòu)體類型可以省略類型名(無名結(jié)構(gòu)體類型)
- 類型名省略時(shí),每次創(chuàng)建變量必須給出完整結(jié)構(gòu)體定義
- 無名結(jié)構(gòu)體類型總是互不相同的類型(互不兼容)
先看第1段代碼:
#include <stdio.h>
#include <string.h>
typedef struct Student Stu;
struct Student
{
char name[20];
int id;
short major;
};
int main()
{
Stu s;
Stu* ps = &s;
strcpy(ps->name, "Autumn");
ps->id = 1;
ps->major = 908;
(*ps).major = 910; // ==> s.major = 910
printf("s.name = %s\n", s.name);
printf("s.id = %d\n", s.id);
printf("s.major = %d\n", s.major);
return 0;
}下面為輸出結(jié)果:

這里注意結(jié)構(gòu)體變量指針通過 -> 操作符訪問成員變量。
再看第2段代碼:
#include <stdio.h>
#include <string.h>
struct Test;
struct Test* g_pt; // 只要有了類型聲明就可以創(chuàng)建對(duì)應(yīng)的指針變量
// 必須先給出類型的完整定義才能創(chuàng)建相應(yīng)類型的變量
struct Test
{
int a;
int b;
};
int main()
{
struct Test t;
t.a = 1;
t.b = 2;
g_pt = &t;
printf("g_pt = %p\n", g_pt);
printf("g_pt->a = %d\n", g_pt->a);
printf("g_pt->b = %d\n", g_pt->b);
return 0;
}下面為輸出結(jié)果:

這里注意兩個(gè)問題:
1.只要有了類型聲明就可以創(chuàng)建對(duì)應(yīng)的指針變量
2.必須先給出類型的完整定義才能創(chuàng)建相應(yīng)類型的變量
再看第3段代碼:
#include <stdio.h>
#include <string.h>
int main()
{
struct { int a, b; } v1;
struct { int a, b; } v2;
struct { int a, b; }*pv;
v1.a = 1;
v1.b = 2;
v2 = v1;
pv = &v2;
return 0;
}這段代碼編譯會(huì)出錯(cuò):

這段代碼充分說明無名結(jié)構(gòu)體類型總是互不相同的類型(互不兼容)
位域
- 現(xiàn)代程序設(shè)計(jì)中,內(nèi)存使用的最小單位為字節(jié)(約定俗成)
- 在一些特定場(chǎng)合,可將比特位作為最小單位使用內(nèi)存
- 結(jié)構(gòu)體類型能夠指定成員變量占用內(nèi)存的比特位寬度(位域)
深入位域 ???????
- 位域成員必須是整型,默認(rèn)情況下成員依次排列
- 位域成員占用的位數(shù)不能超過類型寬度(錯(cuò)誤示例: char c : 9; )
- 當(dāng)存儲(chǔ)位不足時(shí),自動(dòng)啟用新存儲(chǔ)單元
- 可以舍棄當(dāng)前未使用的位,重新啟用存儲(chǔ)單元
下面看一段代碼:
#include <stdio.h>
struct BW
{
unsigned char a : 4;
unsigned char b : 2;
unsigned char c : 2;
};
int main()
{
struct BW bw = {0};
bw.a = 10;
bw.b = 4; // 4 大于 b 能表示的最大值,因此賦值后 b 回轉(zhuǎn)到 0
bw.c = 3;
printf("sizeof(struct BW) = %d\n", sizeof(struct BW));
printf("bw.a = %d\n", bw.a);
printf("bw.b = %d\n", bw.b);
printf("bw.c = %d\n", bw.c);
return 0;
}下面為輸出結(jié)果:

這里注意a : 4 ,所以 a 的取值范圍是 0000 ~ 1111 之間,即 0 ~ 15 之間。
再看一段代碼:
#include <stdio.h>
#include <string.h>
struct Bits1
{
int a : 16;
short b : 8;
char c : 8;
float f; // float f : 32; ==> 浮點(diǎn)型成員不能指點(diǎn)位寬度
};
struct Bits2
{
unsigned char a : 6;
unsigned char b : 6;
unsigned char c : 6;
// unsigned char d : 9; ==> 指定的位寬度不能大于聲明類型的位寬度
};
struct Bits3
{
unsigned char a : 4;
unsigned char : 0; // 重啟一個(gè)存儲(chǔ)單元表示新的成員
unsigned char b : 4;
};
int main()
{
printf("sizeof(Bits1) = %d\n", sizeof(struct Bits1));
printf("sizeof(Bits2) = %d\n", sizeof(struct Bits2));
printf("sizeof(Bits3) = %d\n", sizeof(struct Bits3));
return 0;
}下面為輸出結(jié)果:

這里注意三點(diǎn):
1.浮點(diǎn)型成員不能指點(diǎn)位寬度
2.指定的位寬度不能大于聲明類型的位寬度
3.unsigned char : 0 重啟一個(gè)存儲(chǔ)單元表示新的成員
小結(jié) ???????
- struct 結(jié)構(gòu)體變量中的成員占用獨(dú)立的內(nèi)存
- struct 結(jié)構(gòu)體類型可用 typedef 賦予新類型名
- 結(jié)構(gòu)體類型能夠指定成員變量占用內(nèi)存的比特位寬度
- 位域成員必須是整型,占用的位數(shù)不能超過類型寬度
- 當(dāng)存儲(chǔ)位不足時(shí),自動(dòng)啟用新存儲(chǔ)單元
三、自定義數(shù)據(jù)類型(下)?????
C語言中的聯(lián)合體( union )
- union 是C語言中的自定義類型關(guān)鍵字
- union 是 struct 的兄弟關(guān)鍵字,用法上非常相似
語法:
union TypeName
{
Type1 var1;
Type2 var2;
//......
TypeN varn;
};
union 與 struct 的不同
- union 類型所有成員共享同一段內(nèi)存(所有成員起始地址相同)
- union 類型的大小取決于成員的最大類型
- union類型的變量只能以第一個(gè) 成員類型的有效值進(jìn)行初始化
下面看一段代碼:
#include <stdio.h>
#include <string.h>
union UTest
{
int a;
float f;
};
struct STest
{
int a;
float f;
};
int main()
{
union UTest ut = {987654321};
struct STest st = {987654321, 0.1f};
printf("union UTest size = %d\n", sizeof(union UTest));
printf("&ut.a = %p\n", &ut.a);
printf("&ut.f = %p\n", &ut.f);
printf("struct STest size = %d\n", sizeof(struct STest));
printf("&st.a = %p\n", &st.a);
printf("&st.f = %p\n", &st.f);
printf("ut.a = %d\n", ut.a);
printf("ut.f = %f\n", ut.f);
ut.f = 987654321.0f;
printf("ut.a = %d\n", ut.a);
printf("ut.f = %f\n", ut.f);
return 0;
}下面為輸出結(jié)果:

這里注意整型數(shù)據(jù)和浮點(diǎn)類型數(shù)據(jù)在內(nèi)存中的表示方式不一樣,所以在同一段內(nèi)存,同是4個(gè)字節(jié),按照整型的方式解釋這4個(gè)字節(jié)的數(shù)據(jù)時(shí)是一種結(jié)果,按照浮點(diǎn)數(shù)類型解釋這4個(gè)字節(jié)時(shí)就是另一種結(jié)果。
union 類型的應(yīng)用-判斷系統(tǒng)大小端 ???????
- 小端系統(tǒng):低位數(shù)據(jù)存儲(chǔ)在低地址內(nèi)存中
- 大端系統(tǒng):低位數(shù)據(jù)存儲(chǔ)在高地址內(nèi)存中
例如,對(duì)于 unsigned ui = 1;

下面看一段判斷大小端的代碼:
#include <stdio.h>
int isLittleEndian()
{
union
{
int i;
char a[4];
} test = {0};
test.i = 1;
return (test.a[0] == 1);
}
int main()
{
printf("System Endian: %d\n", isLittleEndian());
return 0;
}下面為輸出結(jié)果:

由代碼可知,1 存在低位,所以我的電腦為小端系統(tǒng)。
C語言中的枚舉類型( enum )
- ???????enum 是C語言中的自定義類型關(guān)鍵字
- enum 能夠定義整型常量的集合類型
???????語法:
enum TypeName
{
IntConst1,
IntConst2,
//......
IntconstN
};
枚舉類型( enum )注意事項(xiàng)
- 第一個(gè)枚舉常量的默認(rèn)值為0
- 后續(xù)常量的值在前一一個(gè)常量值的基礎(chǔ)上加1
- 可以任意對(duì)枚舉常量指定整型值(只能指定整型值)
例如:

下面看一段代碼,感受一下:
#include <stdio.h>
#include <string.h>
enum Day { MON = 1, TUE, WED, THU, FRI, SAT, SUN };
enum Season { Spring, Summer = 3, Autumn, Winter = -1 };
enum { CONSTANT = 12345 };
int main()
{
enum Day d = TUE;
enum Season s = Winter;
int i = SUN;
int j = Autumn;
printf("d = %d\n", d); // 2
printf("s = %d\n", s); // -1
printf("i = %d\n", i); // 7
printf("j = %d\n", j); // 4
d = 0;
s = -2;
printf("d = %d\n", d);
printf("s = %d\n", s);
printf("sizeof(enum Day) = %d\n", sizeof(enum Day));
printf("sizeof(enum Season) = %d\n", sizeof(enum Season));
printf("CONSTANT = %d\n", CONSTANT);
// CONSTANT = 54321;
return 0;
}下面為輸出結(jié)果:

這段代碼也說明了 enum 枚舉類型的本質(zhì)就是整型。
小結(jié)
- union 是 struct 的兄弟關(guān)鍵字,用法上非常相似
- union 類型所有成員共享同一段內(nèi)存
- enum能夠定義整型常量的集合類型
- enum 的本質(zhì)是 int 類型,常用于整型常量定義
到此這篇關(guān)于C語言深入了解自定義數(shù)據(jù)類型的使用的文章就介紹到這了,更多相關(guān)C語言 自定義數(shù)據(jù)類型內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C/C++判斷傳入的UTC時(shí)間是否當(dāng)天的實(shí)現(xiàn)方法
在項(xiàng)目中經(jīng)常會(huì)顯示一個(gè)時(shí)間,如果這個(gè)時(shí)間在今日內(nèi)就顯示為時(shí)分秒,否則顯示為年月日,有需要的朋友可以參考一下2014-01-01
C++實(shí)現(xiàn)簡單班級(jí)成績管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)簡單班級(jí)成績管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-02-02
詳解C++中的內(nèi)存同步模式(memory order)
這篇文章主要介紹了C++中的內(nèi)存同步模式,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04
C語言SetConsoleTextAttribute函數(shù)使用方法
這篇文章介紹了C語言SetConsoleTextAttribute函數(shù)的使用方法,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-12-12
C語言深入細(xì)致講解動(dòng)態(tài)內(nèi)存管理
動(dòng)態(tài)內(nèi)存是相對(duì)靜態(tài)內(nèi)存而言的。所謂動(dòng)態(tài)和靜態(tài)就是指內(nèi)存的分配方式。動(dòng)態(tài)內(nèi)存是指在堆上分配的內(nèi)存,而靜態(tài)內(nèi)存是指在棧上分配的內(nèi)存,本文帶你深入探究C語言中動(dòng)態(tài)內(nèi)存的管理2022-05-05
windows下安裝QT及visual studio 2017搭建開發(fā)環(huán)境
這篇文章主要介紹了windows下安裝QT及visual studio 2017搭建開發(fā)環(huán)境,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03
淺析C/C++ 中return *this和return this的區(qū)別
return *this返回的是當(dāng)前對(duì)象的克隆或者本身,return this返回當(dāng)前對(duì)象的地址,下面通過本文給大家介紹C/C++ 中return *this和return this的區(qū)別,感興趣的朋友一起看看吧2019-10-10
Linux中使用VS Code編譯調(diào)試C++項(xiàng)目詳解
最近因?yàn)轫?xiàng)目的需求,需要在Linux下開發(fā)C++相關(guān)項(xiàng)目,經(jīng)過一番摸索最終實(shí)現(xiàn)了,下面這篇文章就給大家簡單總結(jié)了一下如何通過VS Code進(jìn)行編譯調(diào)試的一些注意事項(xiàng)。有需要的朋友們可以參考借鑒,下面來跟著小編一起看看吧。2016-12-12

