【C 语言】结构体相关 的 函数 指针 数组
.
作者 : 萬境絕塵
轉載請注明出處 :?http://www.hanshuliang.com/?post=30
.
結構體概述 : 結構體是 多個 變量的集合, 變量的類型可以不同;
-- 可進行的操作 : 結構體可以進行 拷貝 賦值操作, 可以作為 函數參數 和 函數返回值;
1. 結構體的基本使用
結構體聲明 : struct 結構標記 {結構成員} 普通變量;
-- 結構體示例 :?
struct student{char *name;int age;};
-- 結構標記 : struct 后面的 student 是結構標記, 這個標記 可寫 可不寫, 其作用是 為結構命名, 結構標記可以代表 {} 中的聲明的所有的成員變量;
-- 結構成員 : 在 {} 中定義的變量就是結構成員;
-- 普通變量 : 在聲明結構體的時候后面可以加上若干普通變量, 相當于定義結構體變量;
結構體變量聲明 : 可以在定義的時候聲明變量, 也可以在定義完結構體使用 結構標記 聲明變量;
-- 定義結構體時聲明變量 : 這種聲明變量的方式可以不用 結構標記, 變量名寫在 花括號 后面, 用頭號隔開;
struct student{char *name;int age;} s1, s2, s3;
-- 使用結構標記聲明 : 結構標記 student 代表了花括號的聲明, 是 結構體的簡寫, 可以使用結構標記代替花括號中的內容;
struct student s4, s5, s6;
結構體內存分配 : 結構體內存是在聲明變量的時候分配的, 如果只聲明了結構體, 沒有聲明對應變量, 那么不會分配內存;
結構體變量初始化 :?
-- 聲明結構體的時候初始化 : struct student s1 = {"Tom", 12} ; 注意 初值表中必須時結構體對應類型的常量表達式;
-- 聲明之后初始化 : 結構體變量名.成員名 可以訪問結構體中的成員變量, s1.name = "Tom"; s2.age = 12;
結構體嵌套 : 結構體中的成員變量可以是 結構體變量;
struct student{char *name;int age;} s1;struct class{struct student s1;struct student s2;} c1;
結構體代碼示例 :?
/*************************************************************************> File Name: base_struct.c> Author: octopus> Mail: octopus_work.163.com > Created Time: 2014年03月24日 星期一 10時49分46秒************************************************************************/#include<stdio.h>int main(int argc, char **argv) {/** 聲明結構體 同時聲明變量s1*/struct student{char *name;int age;} s1;/** 結構體嵌套*/struct class{struct student s1;struct student s2;} c1;struct student s2 = {"Tom", 12};/*只有聲明的時候才能對結構體初始化才能使用花括號賦值*/struct class c2 = {{"Jack", 13}, {"Pig", 15}};s1.name = "Hack"; /*變量聲明后對結構體賦值只能一個一個賦值*/s1.age = 14;//s1 = {"fuck", 1}; /*只有在初始化的時候才能使用 花括號初始化結構體變量*/c1.s1.name = "CJ";c1.s1.age = 21;c1.s2.name = "KW";c1.s2.age = 22;/*訪問結構體中的變量, 使用 . 進行訪問*/printf("s1 : name = %s, age = %d \n", s1.name, s1.age);printf("s2 : name = %s, age = %d \n", s2.name, s2.age);printf("c1 : s1 : name = %s, age = %d ; s2 : name = %s, age = %d \n", c1.s1.name, c1.s1.age, c1.s1.name, c1.s2.age);printf("c2 : s1 : name = %s, age = %d ; s2 : name = %s, age = %d \n", c2.s1.name, c2.s1.age, c2.s1.name, c2.s2.age);return 0; }
執行結果 :?
octopus@octopus-Vostro-270s:~/code/c/struct$ gcc base_struct.c octopus@octopus-Vostro-270s:~/code/c/struct$ ./a.out s1 : name = Hack, age = 14 s2 : name = Tom, age = 12 c1 : s1 : name = CJ, age = 21 ; s2 : name = CJ, age = 22 c2 : s1 : name = Jack, age = 13 ; s2 : name = Jack, age = 15
2. 結構體與函數
結構體的合法操作 :?
-- 整體復制 : 結構體可以復制;
-- 整體賦值 : 聲明結構體的時候可以整體賦值, 在其它情況下不可以;
-- & 取地址 : 使用 & 運算符獲取 結構體地址;
-- 訪問成員 : 使用 結構體變量名.成員變量名 可以訪問成員變量;
函數傳遞結構體方法 :?
-- 傳遞結構體成員 : 將結構體拆開, 將其中的成員變量分別傳入;
struct class create_class(struct student s2, struct student s3) {struct class c1 = {s2, s3};return c1; }
-- 傳遞結構體 : ?將整個結構體當做參數傳入, 這種情況和傳遞其它類型參數一樣, 都是通過值傳遞的;
struct class create_class(struct student s2, struct student s3) {struct class c1 = {s2, s3};return c1; }
-- 傳遞結構體指針 : 傳遞結構體的指針, 訪問形式如下;
/** 傳入一個結構體指針* 通過指針訪問結構體的方法 : * (*結構體指針變量).成員變量 訪問;* 結構體指針變量 -> 成員變量 訪問;*/ void printf_struct_pointer(struct student *s) {printf("student : (*s).name = %s, (*s).age = %d \n", (*s).name, (*s).age);printf("student : s->name = %s, s->age = %d \n", s->name, s->age); }
結構體指針訪問 :
-- 示例 : 定義一個結構體指針;
struct student{char *name;int age;}*p;
-- "." 和 "->"優先級 : 這兩個運算符都是從左到右運算, 都是右結合; "." 和 "->" 優先級比 "*" , "++" 優先級要高; 這兩個運算符 與 () [] 是四個優先級最高的運算符;
-- ++p->age 分析 : 是對結構體中的 age 進行自增操作;
-- *p->name 分析 : 獲取 結構體中的 name 字符串的值(注意不是指針|地址);
-- *p++->name 分析 : 先獲取 name 字符串的值, 再將p自增;
結構體函數示例 :
/*************************************************************************> File Name: method_struct.c> Author: octopus> Mail: octopus_work.163.com > Created Time: 2014年03月24日 星期一 14時46分16秒************************************************************************/#include<stdio.h>/*聲明一個結構體類型, 其成員變量是普通變量*/ struct student {char *name;int age; };/*聲明一個結構體類型, 其成員變量是結構體*/ struct class {struct student s1;struct student s2; };/** 傳遞 2 個結構體的成員變量* 在函數中創建結構體并返回*/ struct student create_student(char *name, int age) {struct student s1 = {name, age};return s1; }/** 傳遞 2 個結構體變量*/ struct class create_class(struct student s2, struct student s3) {struct class c1 = {s2, s3};return c1; }/** 傳入一個結構體指針* 通過指針訪問結構體的方法 : * (*結構體指針變量).成員變量 訪問;* 結構體指針變量 -> 成員變量 訪問;*/ void printf_struct_pointer(struct student *s) {printf("student : (*s).name = %s, (*s).age = %d \n", (*s).name, (*s).age);printf("student : s->name = %s, s->age = %d \n", s->name, s->age); }int main(int argc, char **argv) {/*使用函數獲取一個結構體, 傳入結構體的值*/struct student s1 = create_student("Tom", 11);printf("student : name = %s, age = %d \n", s1.name, s1.age);/*創建一個成員變量是結構體的結構體, 并打印結構體數據*/struct class c1 = create_class(create_student("Jack", 12), create_student("CJ", 13));printf("c1 : s1 : name = %s, age = %d ; s2 : name = %s, age = %d \n", c1.s1.name, c1.s1.age, c1.s2.name, c1.s2.age);/*聲明結構體指針*/struct student *p = &s1;printf_struct_pointer(p);return 0; }
執行結果 :?
octopus@octopus-Vostro-270s:~/code/c/struct$ gcc method_struct.c octopus@octopus-Vostro-270s:~/code/c/struct$ ./a.out student : name = Tom, age = 11 c1 : s1 : name = Jack, age = 12 ; s2 : name = CJ, age = 13 student : (*s).name = Tom, (*s).age = 11 student : s->name = Tom, s->age = 11
3. 結構體數組
(1) 結構體數組聲明初始化
聲明結構體數組 :?
-- 聲明結構體的時候聲明結構體數組 : 格式為 : struct 結構標記 {} 數組名[];?
-- 使用結構標記聲明結構體數組 : 格式為 : struct 結構標記 數組名[];
結構體數組聲明初始化 :?
-- 逐個元素初始化 : 數組名[] = {{結構體1}, {結構體2}};
-- 總體初始化 : 數組名[] = {常量1, 常量2 ...};?
結構體初始化 :?
/*************************************************************************> File Name: array_struct.c> Author: octopus> Mail: octopus_work.163.com > Created Time: 2014年03月24日 星期一 16時40分15秒************************************************************************/#include<stdio.h>/** 聲明結構體 * 同時也聲明結構體類型數組* 為數組初始化* 直接將每個結構體成員的值依次列出即可*/ struct student {char *name;int age; } team1[] = {"Tom", 12,"Jack", 13 };int main(int argc, char **argv) {int i;/*將每個結構體初始化, 賦值, 每個結構體初始化內容使用 花括號括起來*/struct student team2[] = {{"CJ", 34}, {"KI", 32}};for(i = 0; i < 2; i++){printf("team1 : team1[i].name = %s, team1[i].age = %d \n", team1[i].name, team1[i].age);}for(i = 0; i < 2; i++){printf("team2 : team2[i].name = %s, team2[i].age = %d \n", team2[i].name, team2[i].age);}return 0; }
執行結果 :?
octopus@octopus-Vostro-270s:~/code/c/struct$ gcc array_struct.c octopus@octopus-Vostro-270s:~/code/c/struct$ ./a.out team1 : team1[i].name = Tom, team1[i].age = 12 team1 : team1[i].name = Jack, team1[i].age = 13 team2 : team2[i].name = CJ, team2[i].age = 34 team2 : team2[i].name = KI, team2[i].age = 32
(2) 結構體數組示例程序
需求 : 實現一個統計 C 語言關鍵字出現次數;
代碼 :?
/*************************************************************************> File Name: word_count.c> Author: octopus> Mail: octopus_work.163.com > Created Time: 2014年03月24日 星期一 17時12分32秒************************************************************************/#include<stdio.h> #include<ctype.h> #include<string.h>#define MAXWORD 10/** 定義結構體類型 key * 該類型結構體中存儲一個 字符串(關鍵字) 和 int 數據(關鍵字出現次數)* 同時聲明一個結構體數組* 對結構體數組進行初始化***/ struct key {char *word;int count; }key_count[] = {"auto", 0,"break", 0,"case", 0,"char", 0,"const", 0,"continue", 0,"default", 0,"void", 0,"volatitle", 0,"while", 0 };int main(int argc, char **argv) {int n;char word[MAXWORD];/*循環接收字符串, 如果字符串與結構體數組中匹配, 結構體的count ++*/while(getword(word, MAXWORD) != EOF)if(isalpha(word[0]))if((n = binsearch(word, key_count, 10)) >= 0)key_count[n].count++;/*打印大于0的關鍵字 及 個數*/for (n = 0; n < 10; n ++)if(key_count[n].count > 0)printf("%2d %s\n", key_count[n].count, key_count[n].word);return 0; }/* * 重要api解析 :* int getc(FILE *stream) 從標準輸入流中讀取字符* int ungetc(int c, FILE *stream) 將字符退回到標準輸入流中* int isspace(int c) 判斷字符是否是 空格 '\f' '\r' '\n' '\t' '\v'* int isalpha(int c) 判斷是否是字母*/ int getword(char *word, int lim) {int c, getc(FILE*), ungetc(int, FILE*);char *wp = word;/*過濾空格, 如果輸入的不是 空, 就繼續向下執行*/while(isspace(c = getc(stdin)));/*如果輸入的不是結束符, 那么 wp指針, 先取值, 之后地址自增*/if(c != EOF)*wp++ = c;/*如果輸入的不是字母, 直接返回, 關鍵字里面沒有數字開頭的*/if(!isalpha(c)){*wp = '\0';return c;}/** 循環條件 a. 接收的最大字符個數 lim, 每讀取一個字符, 該變量自減 * 當該變量自減為0時停止循環接收字符串* 循環條件 b. 當讀取到的字符 不是 字母 或者數字的時候, 停止循環*/for(; --lim > 0; wp++){if(!isalnum(*wp = getc(stdin))){ungetc(*wp, stdin);break;}}*wp = '\0';return word[0]; }/** 參數解析 : word 是要查找的字符串 tab 字符串數組 n 字符串大小*/ int binsearch(char *word, struct key tab[], int n) {/** cond 判斷 查找的字符串 是在mid 坐標之前 (<0) 之后(>0) 或者就是mid坐標* * 如果查找的不是正好中間的變量符合, 就返回 -1 失敗*/int cond, low, high, mid;low = 0;high = n - 1;/** 要找的值的下標在low 和 high之間* mid 是 low 和 high 的中值* 如果 word 小于中值下標 將比較范圍 縮小*/while(low <= high){mid = (low + high) / 2;if((cond = strcmp(word, tab[mid].word)) < 0)high = mid - 1;else if(cond > 0)low = mid + 1;elsereturn mid;}return -1; }
?
執行結果 :?
[root@ip28 struct]# gcc word_count.c [root@ip28 struct]# ./a.out auto break break char1 auto2 break1 char
宏定義方法 : 獲取結構體數組大小;
-- sizeof 方法 : sizeof (對象) | sizeof (類型名稱) 可以獲取對象 或者 類型占用的存儲空間, 其返回值是 size_t 類型的, 定義在stddef.h 頭文件中;
-- 使用類型測量 :?
#define KEYS (sizeof(key_count) / sizeof(struct key))-- 使用對象測量 :?
#define KEYS (sizeof(key_count) / sizeof(struct key_count[0])
4. 指向結構體指針
(1) 使用指針方式實現上面的關鍵字統計程序?
使用指針進行二分查找 :?
-- 使用下標找中值 : 在之前找中值時通過 mid = (low + high)方法, 這樣做可行是因為 low 從0開始的;
-- 如果是指針情況 : mid low high 都是指針, 那么就不能使用上面的那種方法了, 使用 mid = low + (high - low) / 2;.
-- 指針操作情況的 high 和 low : 其中 low 是首元素的 首地址, high 是 尾元素的尾地址, 只有這樣 它們的差的 0.5 倍才是準確的中值的首地址;
指針指向數組注意點 : 不要生成非法的指針, 指針不能指向數組之外的元素;
-- &key_count[-1] : 這個指針時非法的;
-- &key_count[n] : 對數組的最后一個元素后面的第一個元素進行 & 運算時合法的, 其它操作都是非法的;
示例程序 :?
/*************************************************************************> File Name: pointer_struct.c> Author: octopus> Mail: octopus_work.163.com > Created Time: Tue 25 Mar 2014 12:31:08 AM CST************************************************************************/#include<stdio.h> #include<ctype.h> #include<string.h>#define MAXWORD 20 /*計算結構體數組的大小*/ #define KEYS (int)(sizeof(key_count) / sizeof(struct key))struct key {char *word;int count; } key_count[] = {"auto", 0,"break", 0,"case", 0,"char", 0,"const", 0 };int getword(char *, int); struct key *binsearch(char*, struct key*, int);int main(int argc, char **argv) {char word[MAXWORD];struct key *p; /*存放查找方法返回的結構體指針, 該指針指向數組中查找到元素的下標*/while(getword(word, MAXWORD) != EOF)if(isalpha(word[0]))if((p = binsearch(word, key_count, KEYS)) != NULL)p->count++;for(p = key_count; p < key_count + KEYS; p++)if(p->count > 0)printf("%2d %s \n", p->count, p->word);return 0; }/** 沒有循環控制變量的 for 循環, 在內部通過條件 break*/ int getword(char *word, int max) {int c, getc(FILE*), ungetc(int, FILE*);char *wp = word;/*處理第一個字符, 第一個字符不是 空 不是 EOF 再進行下面的操作*/while(isspace(c = getc(stdin)));if(c != EOF)*wp++ = c;if(!isalpha(c)){*wp = '\0';return c;}/*循環接收字符串, 字符串接收到非標識符 或者 到達個數上限停止循環*/for(; --max > 0; wp++)if(!isalnum(*wp = getc(stdin))){ungetc(*wp, stdin);break;}*wp = '\0';return word[0]; }/** 注意點 : * 取兩個地址的中值 : 一個數組n個元素, 其中值計算 是由 首元素的首地址 和 尾元素的尾地址計算的* 二分查找 : * 如果要把區間前移, 那么就需要將尾地址設置為 中間元素前一個元素的尾地址, 即中間元素的首地址* 如果要把區間后移, 那么就需要將首地址設置為 中間元素后一個元素的首地址, 即中間元素 + 1 的地址** 指向結構體數組的指針 : * struct key tab * 是指向結構體數組指針, 該指針可以操作結構體數組*/ struct key *binsearch(char *word, struct key *tab, int n) {int cond;struct key *low = &tab[0]; /*0元素的首地址*/struct key *high = &tab[n]; /*尾元素的尾地址*/struct key *mid;while(low < high){/*計算中間值的地址*/mid = low + (high - low) / 2;if((cond = strcmp(word, mid->word)) < 0)high = mid; /*mid 是 中間元素前一個元素的尾地址*/else if(cond > 0)low = mid + 1; /*這里low要成為mid后一個元素的首地址*/elsereturn mid;}return NULL; }
執行結果 :?
octopus@octopus-Vostro-270s:~/code/c/struct$ gcc pointer_struct.c octopus@octopus-Vostro-270s:~/code/c/struct$ ./a.out auto case auto break2 auto 1 break 1 case
(2) 結構體大小討論?
結構體數組指針算術運算 : struct key *p = word_count; 指針 p 指向 結構體數組, 如果 p + 1 , 結果是 p 地址 加上 結構體所占內存大小;
結構體大小 : 結構體的大小不是完全等于各個成員的長度之和, 對象之間有對齊要求;
-- 空穴 : 對象間對齊, 會產生空穴, 占有空間, 但是不存儲數據;
示例 : 結構體中由一個 char 和 int , 占用的空間卻是 8個字節, 它們的和是 5個字節;
/*************************************************************************> File Name: memory_struct.c> Author: octopus> Mail: octopus_work.163.com > Created Time: 2014年03月25日 星期二 12時55分45秒************************************************************************/#include<stdio.h>struct word {char c;int i; };int main(int argc, char **argv) {printf("sizeof(struct word) = %d \n", sizeof(struct word));return 0; }
執行結果 :?
octopus@octopus-Vostro-270s:~/code/c/struct$ gcc memory_struct.c octopus@octopus-Vostro-270s:~/code/c/struct$ ./a.out sizeof(word) = 8
.
作者?:?萬境絕塵
轉載請注明出處?:?http://www.hanshuliang.com/?post=30
.
總結
以上是生活随笔為你收集整理的【C 语言】结构体相关 的 函数 指针 数组的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【嵌入式开发】C语言 命令行参数 函数指
- 下一篇: 【Android 应用开发】Androi