#### 17. 結構體
C 數組允許定義可存儲相同類型數據項的變量,**結構**是 C 編程中另一種用戶自定義的可用的數據類型,它允許您存儲不同類型的數據項。
結構用于表示一條記錄,假設您想要跟蹤圖書館中書本的動態,您可能需要跟蹤每本書的下列屬性:
* Title
* Author
* Subject
* Book ID
**定義結構**
為了定義結構,您必須使用 **struct** 語句。struct 語句定義了一個包含多個成員的新的數據類型,struct 語句的格式如下:
~~~
struct name{
member-list;
member-list;
...
}name_tag,
~~~
*name* 是結構的標簽。
*member-list* 是標準的變量定義,比如 int i;或者 float f,或者其它有效的變量定義。
*name_tag* 結構變量,定義在結構的末尾,最后一個分號之前,你可以指定一個或多個結構變量,下面是聲明 Book 的結構方式:
~~~
struct Books{
char title[50];
char author[50];
char subject[100];
int book_id;
} book;
~~~
注意:在定義結構體的時候**name、member-list、name\_tag** 這 3 部分至少要出現 2 個。
**結構體變量的初始化**
和其它類型變量一樣,在初始化的時候可以指定初始值。
~~~
//定義一個 Books 結構,類似于 Java 中的數據 bean
struct Books {
char title[50];
char author[50];
char subject[100];
int book_id;
double rmb;
} book = {"Java", "Android", "C 語言", 666, 55.5};
void main(){
//打印 Books
printf("title : %s\nauthor: %s\nsubject: %s\nbook_id: %d\nrmb: %f\n", book.title,
book.author, book.subject, book.book_id, book.rmb);
}
~~~
輸出:
~~~
title : Java
author: Android
subject: C 語言
book_id: 666
rmb: 55.500000
~~~
**訪問結構成員**
~~~
struct Books2 {
char title[50];
char author[50];
char subject[100];
int book_id;
};
void main(){
//訪問 Books2 結構成員
struct Books2 Books2A;//聲明 Books2A 類型為 Books2
struct Books2 Books2B;//聲明 Books2B 類型為 Books2
//Books2A 詳述
strcpy(Books2A.title, "C Plus");
strcpy(Books2A.author, "Nuha Ali");
strcpy(Books2A.subject, "C");
Books2A.book_id = 666888;
//Books2B 詳述
strcpy(Books2B.title, "C++ Plus");
strcpy(Books2B.author, "DevYK");
strcpy(Books2B.subject, "C++");
Books2B.book_id = 666999;
// 輸出 Book1 信息
printf("Book 1 title : %s\n", Books2A.title);
printf("Book 1 author : %s\n", Books2A.author);
printf("Book 1 subject : %s\n", Books2A.subject);
printf("Book 1 book_id : %d\n", Books2A.book_id);
// 輸出 Book2 信息
printf("Book 2 title : %s\n", Books2B.title);
printf("Book 2 author : %s\n", Books2B.author);
printf("Book 2 subject : %s\n", Books2B.subject);
printf("Book 2 book_id : %d\n", Books2B.book_id);
}
~~~
輸出:
~~~
Book 1 title : C Plus
Book 1 author : Nuha Ali
Book 1 subject : C
Book 1 book_id : 666888
Book 2 title : C++ Plus
Book 2 author : DevYK
Book 2 subject : C++
Book 2 book_id : 666999
~~~
**結構作為函數參數**
~~~
//函數聲明
void printBook(struct Books2 books2);
void main(){
//訪問 Books2 結構成員
struct Books2 Books2A;//聲明 Books2A 類型為 Books2
struct Books2 Books2B;//聲明 Books2B 類型為 Books2
//Books2A 詳述 ,將 CPlus copy 到 title 中
strcpy(Books2A.title, "C Plus");
strcpy(Books2A.author, "Nuha Ali");
strcpy(Books2A.subject, "C");
Books2A.book_id = 666888;
//Books2B 詳述
strcpy(Books2B.title, "C++ Plus");
strcpy(Books2B.author, "DevYK");
strcpy(Books2B.subject, "C++");
Books2B.book_id = 666999;
// 輸出 Book1 信息
printf("Book 1 title : %s\n", Books2A.title);
printf("Book 1 author : %s\n", Books2A.author);
printf("Book 1 subject : %s\n", Books2A.subject);
printf("Book 1 book_id : %d\n", Books2A.book_id);
// 輸出 Book2 信息
printf("Book 2 title : %s\n", Books2B.title);
printf("Book 2 author : %s\n", Books2B.author);
printf("Book 2 subject : %s\n", Books2B.subject);
printf("Book 2 book_id : %d\n", Books2B.book_id);
printf("\n\n\n");
//結構作為函數參數
printBook(Books2A);
printBook(Books2B);
}
void printBook(struct Books2 book) {
printf("Book title : %s\n", book.title);
printf("Book author : %s\n", book.author);
printf("Book subject : %s\n", book.subject);
printf("Book book_id : %d\n", book.book_id);
}
~~~
輸出:
~~~
Book 1 title : C Plus
Book 1 author : Nuha Ali
Book 1 subject : C
Book 1 book_id : 666888
Book 2 title : C++ Plus
Book 2 author : DevYK
Book 2 subject : C++
Book 2 book_id : 666999
Book title : C Plus
Book author : Nuha Ali
Book subject : C
Book book_id : 666888
Book title : C++ Plus
Book author : DevYK
Book subject : C++
Book book_id : 666999
~~~
**指向結構的指針**
您可以定義指向結構的指針,方式與定義指向其他類型變量的指針相似,如下所示:
~~~
struct Books *struct_pointer;
~~~
現在,您可以在上述定義的指針變量中存儲結構變量的地址。為了查找結構變量的地址,請把 & 運算符放在結構名稱的前面,如下所示:
~~~
struct_pointer = &Book1;
~~~
為了使用指向該結構的指針訪問結構的成員,您必須使用 -> 運算符,如下所示:
~~~
struct_pointer->title;
~~~
例子:
~~~
//定義指向結構的指針
void printBookZZ(struct Books2 *books2);
void main(){
//訪問 Books2 結構成員
struct Books2 Books2A;//聲明 Books2A 類型為 Books2
struct Books2 Books2B;//聲明 Books2B 類型為 Books2
//Books2A 詳述 ,將 CPlus copy 到 title 中
strcpy(Books2A.title, "C Plus");
strcpy(Books2A.author, "Nuha Ali");
strcpy(Books2A.subject, "C");
Books2A.book_id = 666888;
//Books2B 詳述
strcpy(Books2B.title, "C++ Plus");
strcpy(Books2B.author, "DevYK");
strcpy(Books2B.subject, "C++");
Books2B.book_id = 666999;
//通過內存地址傳遞信息,為了查找結構變量的地址,請把 & 運算符放在結構名稱的前面
printBookZZ(&Books2A);
printBookZZ(&Books2B);
}
/**
* 為了使用指向該結構的指針訪問結構的成員,您必須使用 -> 運算符,如下所示:
* @param book
*/
void printBookZZ(struct Books2 *book) {
printf("Book -> title : %s\n", book->title);
printf("Book -> author : %s\n", book->author);
printf("Book -> subject : %s\n", book->subject);
printf("Book -> book_id : %d\n", book->book_id);
}
~~~
**位域**
有些信息在存儲時,并不需要占用一個完整的字節,而只需占幾個或一個二進制位。例如在存放一個開關量時,只有 0 和 1 兩種狀態,用 1 位二進位即可。為了節省存儲空間,并使處理簡便,C 語言又提供了一種數據結構,稱為"位域"或"位段"。
所謂"位域"是把一個字節中的二進位劃分為幾個不同的區域,并說明每個區域的位數。每個域有一個域名,允許在程序中按域名進行操作。這樣就可以把幾個不同的對象用一個字節的二進制位域來表示。
典型的實例:
* 用 1 位二進位存放一個開關量時,只有 0 和 1 兩種狀態。
* 讀取外部文件格式——可以讀取非標準的文件格式。
`位域ed 定義:`
~~~
struct 位域結構名稱{
位域列表
};
~~~
位域列表的形式為:
~~~
類型說明符 位域名:位域長度
~~~
例如:
~~~
struct bean {
int a:8;
int b:4;
int c:4;
}data;
~~~
說明 data 為 bean 變量,共占 2個字節。其中位域 a 占 8 位,位域 b 占 4 位,位域 c 占 4 位。
注意:
* 一個位域存儲在同一個字節中,如一個字節所剩空間不夠存放另一位域時,則會從下一單元起存放該位域。也可以有意使某位域從下一單元開始。例如:
~~~
struct bean{
unsigned a:4;
unsigned :4;//空域
unsigned b:4;//從下一個單元開始存放
unsigned c:4;
}
~~~
在這個位域定義中共占用 2 個字節,a 占第一字節的 4 位,后 4 位填 0 表示不使用,b 從第二字節開始,占用 4 位,c 占用 4 位。
> * 由于位域不允許跨兩個字節,因此位域的長度不能大于一個字節的長度,也就是說不能超過8位二進位。如果最大長度大于計算機的整數字長,一些編譯器可能會允許域的內存重疊,另外一些編譯器可能會把大于一個域的部分存儲在下一個字中。
> * 位域可以是無名位域,這時它只用來作填充或調整位置。無名的位域是不能使用的。例如:
>
> ~~~
> struct k{
> int a:1;
> int :2; /* 該 2 位不能使用 */
> int b:3;
> int c:2;
> };
> ~~~
>
> 從以上分析可以看出,位域在本質上就是一種結構類型,不過其成員是按二進位分配的。
**位域的使用**
位域的使用和結構成員的使用相同,其一般形式為:
> 位域變量名.位域名
>
> 位域變量名->位域名
位域允許用各種格式輸出。
例子:
~~~
void main(){
//位域
struct bs {
unsigned int a:1;//占 位段a 1 位
unsigned b:6;//占 位段b 3 位
unsigned c:7;//占 位段c 4 位
} bit, *pbit;
// 給位域賦值(應注意賦值不能超過該位域的允許范圍)
bit.a = 1; //以二進制 1 表示 1 bit位
bit.b = 50;//以二進制 110010 表示 6 bit位
bit.c = 100;//以二進制 1100100 標志 7 bit位
printf("%d,%d,%d\n",bit.a,bit.b,bit.c); // 以整型量格式輸出三個域的內容
pbit=&bit; //把位域變量 bit 的地址送給指針變量 pbit
pbit->a=0; //用指針方式給位域 a 重新賦值,賦為 0
pbit->b&=3; //使用了復合的位運算符 "&=",相當于:pbit->b=pbit->b&3,位域 b 中原有值為 50,與 3 作按位與運算的結果為 2(110010&011=010,十進制值為 2)
pbit->c|=1; //使用了復合位運算符"|=",相當于:pbit->c=pbit->c|1,其結果為 (1100100 | 0000001)= 1100101 = 101
printf("%d,%d,%d\n",pbit->a,pbit->b,pbit->c); //用指針方式輸出了這三個域的值
}
~~~
輸出:
~~~
1,50,100
0,2,101
~~~
- 前言
- JNI基礎知識
- C語言知識點總結
- ①基本語法
- ②數據類型
- 枚舉類型
- 自定義類型(類型定義)
- ③格式化輸入輸出
- printf函數
- scanf函數
- 編程規范
- ④變量和常量
- 局部變量和外部變量
- ⑤類型轉換
- ⑥運算符
- ⑦結構語句
- 1、分支結構(選擇語句)
- 2、循環結構
- 退出循環
- break語句
- continue語句
- goto語句
- ⑧函數
- 函數的定義和調用
- 參數
- 函數的返回值
- 遞歸函數
- 零起點學通C語言摘要
- 內部函數和外部函數
- 變量存儲類別
- ⑨數組
- 指針
- 結構體
- 聯合體(共用體)
- 預處理器
- 預處理器的工作原理
- 預處理指令
- 宏定義
- 簡單的宏
- 帶參數的宏
- 預定義宏
- 文件包含
- 條件編譯
- 內存中的數據
- C語言讀文件和寫文件
- JNI知識點總結
- 前情回顧
- JNI規范
- jni開發
- jni開發中常見的錯誤
- JNI實戰演練
- C++(CPP)在Android開發中的應用
- 掘金網友總結的音視頻開發知識
- 音視頻學習一、C 語言入門
- 1.程序結構
- 2. 基本語法
- 3. 數據類型
- 4. 變量
- 5. 常量
- 6. 存儲類型關鍵字
- 7. 運算符
- 8. 判斷
- 9. 循環
- 10. 函數
- 11. 作用域規則
- 12. 數組
- 13. 枚舉
- 14. 指針
- 15. 函數指針與回調函數
- 16. 字符串
- 17. 結構體
- 18. 共用體
- 19. typedef
- 20. 輸入 & 輸出
- 21.文件讀寫
- 22. 預處理器
- 23.頭文件
- 24. 強制類型轉換
- 25. 錯誤處理
- 26. 遞歸
- 27. 可變參數
- 28. 內存管理
- 29. 命令行參數
- 總結
- 音視頻學習二 、C++ 語言入門
- 1. 基本語法
- 2. C++ 關鍵字
- 3. 數據類型
- 4. 變量類型
- 5. 變量作用域
- 6. 常量
- 7. 修飾符類型
- 8. 存儲類
- 9. 運算符
- 10. 循環
- 11. 判斷
- 12. 函數
- 13. 數學運算
- 14. 數組
- 15. 字符串
- 16. 指針
- 17. 引用
- 18. 日期 & 時間
- 19. 輸入輸出
- 20. 數據結構
- 21. 類 & 對象
- 22. 繼承
- 23. 重載運算符和重載函數
- 24. 多態
- 25. 數據封裝
- 26. 接口(抽象類)
- 27. 文件和流
- 28. 異常處理
- 29. 動態內存
- 30. 命名空間
- 31. 預處理器
- 32. 多線程
- 總結
- 音視頻學習 (三) JNI 從入門到掌握
- 音視頻學習 (四) 交叉編譯動態庫、靜態庫的入門學習
- 音視頻學習 (五) Shell 腳本入門
- 音視頻學習 (六) 一鍵編譯 32/64 位 FFmpeg 4.2.2
- 音視頻學習 (七) 掌握音頻基礎知識并使用 AudioTrack、OpenSL ES 渲染 PCM 數據
- 音視頻學習 (八) 掌握視頻基礎知識并使用 OpenGL ES 2.0 渲染 YUV 數據
- 音視頻學習 (九) 從 0 ~ 1 開發一款 Android 端播放器(支持多協議網絡拉流/本地文件)
- 音視頻學習 (十) 基于 Nginx 搭建(rtmp、http)直播服務器
- 音視頻學習 (十一) Android 端實現 rtmp 推流
- 音視頻學習 (十二) 基于 FFmpeg + OpenSLES 實現音頻萬能播放器
- 音視頻學習 (十三) Android 中通過 FFmpeg 命令對音視頻編輯處理(已開源)