结构和其他数据形式
0x01 結構聲明
結構聲明(structure declaration)描述了一個結構的組織布局。
struct book{char title[MAXTITL];char author[MAXAUTL];float value; };該聲明描述了一個由兩個字符數組和一個float類型變量組成的結構。該聲明并未創建實際的數據對象,只描述了該對象由什么組成。
 struct,它表明跟在其后的是一個結構,后面是一個可選的標記(該例中是 book),稍后程序中可以使用該標記引用該結構。
 我們在后面的程序中可以這樣聲明:
這把library聲明為一個使用book結構布局的結構變量。
#include "stdio.h"#define MAXTITL 30 #define MAXAUTL 30struct book{char title[MAXTITL];char author[MAXAUTL];float value; };int a; struct book book2; int main() {struct book book1={"Hello","d1l1endh",7.6};printf("title=%s\n",book1.title);printf("author=%s\n",book1.author);printf("value=%f\n",book1.value);return 0; }反匯編我們看看結構聲明會產生什么:
 
 struct book相當于一個類型,和int 相似,book2相當于a,結構布局告訴編譯器如何表示數據,但是它并未讓編譯器為數據分配空間。
0x02 定義結構變量
struct book book2;編譯器執行這行代碼便創建了一個結構變量book2。編譯器使用book模
 板為該變量分配空間:一個內含MAXTITL個元素的char數組、一個內含
 MAXAUTL個元素的char數組和一個float類型的變量。這些存儲空間都與一
 個名稱book2結合在一起
 struct book book2;
 是以下聲明的簡化:
換言之,聲明結構的過程和定義結構變量的過程可以組合成一個步驟。如果打算多次使用結構模板,就要使用帶標記的形式;或者,使用typedef。
2.1 初始化結構
初始化一個結構變量(ANSI之前,不能用自動變量初始化結構;ANSI之后可以用任意存儲類別)與初始化數組的語法類似:
struct book book1={"Hello","d1l1endh",7.6};2.2 訪問結構成員
使用結構成員運算符——點(.)訪問結構中的成員。
0x03 嵌套結構
在一個結構中包含另一個結構
#include "stdio.h"#define LEN 30struct names{char first[LEN];char last[LEN]; };struct guy{struct names handle;char favfood[LEN];char job[LEN];float income;};int main() {struct guy fellow={{"Ell","end"},"salmon","programmer",100000};printf("firset=%s\n",fellow.handle.first);printf("job=%s\n",fellow.job);printf("income=%f\n",fellow.income);return 0; }訪問嵌套結構的成員,這需要使用兩次點運算符。handle是fellow的成員,first是handle的成員
0x04 指向結構的指針
4.1 聲明和初始化指針
我們定義一個int類型指針是:
int *p;結構也是一種類型,所以聲明結構體指針很簡單
struct guy *him;struct guy 是一種類型,相當于int,這個語法和其他指針聲明一樣。該聲明并未創建一個新的結構,但是指針him現在可以指向任意現有的guy類型的結構。如果barney是一個guy類型的結構,可以這樣寫:
him = &barney;和數組不同的是,結構名并不是結構的地址,因此要在結構名前面加上&運算符。
4.2 用指針訪問成員
使用->運算符。
 ->運算符后面的結構指針和.運算符后面的結構名工作方式相同
 如果him == &barney,那么him->income 即是 barney.income
4.3 向函數傳遞結構的信息
這里我們重點說傳遞結構的地址和傳遞結構
 傳遞結構的地址
 因為結構名不是其地址別名,所以我們必須用&運算符,然后通過->運算符獲取值
傳遞結構
#include "stdio.h"#define LEN 30struct names{char first[LEN];char last[LEN]; };struct guy{struct names handle;char favfood[LEN];char job[LEN];float income;};double sum(struct guy );int main() {struct guy fellow={{"Ell","end"},"salmon","programmer",100000};double sum_income=sum(fellow);//printf("firset=%s\n",fellow.handle.first);//printf("job=%s\n",fellow.job);printf("sum_income=%f\n",sum_income);return 0; }double sum(struct guy people) {return (people.income+people.income); }傳遞結構直接把結構名當參數就行
0x05 typedef
typedef工具是一個高級數據特性,利用typedef可以為某一類型自定義名稱。
typedef unsigned char BYTE;隨后,便可使用BYTE來定義變量:
BYTE x, y[10], * z;該定義的作用域取決于typedef定義所在的位置。
0x06 函數與指針
聲明一個函數指針時,必須聲明指針指向的函數類型。為了指明函數類型,要指明函數簽名,即函數的返回類型和形參類型。
void ToUpper(char *); // 把字符串中的字符轉換成大寫字符ToUpper()函數的類型是“帶char * 類型參數、返回類型是void的數”。
void (*pf)(char *); // pf 是一個指向函數的指針第1對圓括號把*和pf括起來,表明pf是一個指向函數的指針
 把**函數名ToUpper替換為表達式(*pf)**是創建指向函數指針最簡單的方式。
 所以,如果想聲明一個指向某類型函數的指針,可以寫出該函數的原型后把函數名替換成(*pf)形式的表達式,創建函數指針聲明。
 聲明一個函數指針時,必須聲明指針指向的函數類型。包括返回值、參數,如果想聲明一個指向某類型函數的指針,可以寫出該函數的原型后把函數名替換成(*pf)形式的表達式,這樣就聲明好一個函數指針了。用函數指針調用函數是有兩種方式:
- 指針名(參數)
- (* 指針名)(參數)
 我們反匯編看一下
可以看出,把首地址賦值給我們的函數指針,也就是把函數首地址放到dword ptr [ebp-10h]里,調用的時候直接call dword ptr [ebp-10h],和平常調用函數一樣
總結
 
                            
                        - 上一篇: 《拟阮公夜中不能寐诗》第三句是什么
- 下一篇: 清泉河的迷雾剧情介绍
