結構體概述 : 結構體是 多個 變量的集合, 變量的類型可以不同;
-- 可進行的操作 : 結構體可以進行 拷貝 賦值操作, 可以作為 函數參數 和 函數返回值;
結構體聲明 : struct 結構標記 {結構成員} 普通變量;
-- 結構體示例 :
struct student
{
char *name;
int age;
};
-- 結構成員 : 在 {} 中定義的變量就是結構成員;
-- 普通變量 : 在聲明結構體的時候後面可以加上若干普通變量, 相當於定義結構體變量;
結構體變量聲明 : 可以在定義的時候聲明變量, 也可以在定義完結構體使用 結構標記 聲明變量;
-- 定義結構體時聲明變量 : 這種聲明變量的方式可以不用 結構標記, 變量名寫在 花括號 後面, 用頭號隔開;
struct student
{
char *name;
int age;
} s1, s2, s3;
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
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
, s1.name, s1.age);
printf(s2 : name = %s, age = %d
, s2.name, s2.age);
printf(c1 : s1 : name = %s, age = %d ; s2 : name = %s, age = %d
, c1.s1.name, c1.s1.age, c1.s1.name, c1.s2.age);
printf(c2 : s1 : name = %s, age = %d ; s2 : name = %s, age = %d
, 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
結構體的合法操作 :
-- 整體復制 : 結構體可以復制;
-- 整體賦值 : 聲明結構體的時候可以整體賦值, 在其它情況下不可以;
-- & 取地址 : 使用 & 運算符獲取 結構體地址;
-- 訪問成員 : 使用 結構體變量名.成員變量名 可以訪問成員變量;
函數傳遞結構體方法 :
-- 傳遞結構體成員 : 將結構體拆開, 將其中的成員變量分別傳入;
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
, (*s).name, (*s).age);
printf(student : s->name = %s, s->age = %d
, 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
/*聲明一個結構體類型, 其成員變量是普通變量*/
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
, (*s).name, (*s).age);
printf(student : s->name = %s, s->age = %d
, s->name, s->age);
}
int main(int argc, char **argv)
{
/*使用函數獲取一個結構體, 傳入結構體的值*/
struct student s1 = create_student(Tom, 11);
printf(student : name = %s, age = %d
, 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
, 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
聲明結構體數組 :
-- 聲明結構體的時候聲明結構體數組 : 格式為 : 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
/*
* 聲明結構體
* 同時也聲明結構體類型數組
* 為數組初始化
* 直接將每個結構體成員的值依次列出即可
*/
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
, team1[i].name, team1[i].age);
}
for(i = 0; i < 2; i++)
{
printf(team2 : team2[i].name = %s, team2[i].age = %d
, 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
需求 : 實現一個統計 C 語言關鍵字出現次數;
代碼 :
/*************************************************************************
> File Name: word_count.c
> Author: octopus
> Mail: octopus_work.163.com
> Created Time: 2014年03月24日 星期一 17時12分32秒
************************************************************************/
#include
#include
#include
#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
, 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) 判斷字符是否是 空格 '' '
' '
' ' ' ''
* 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 = '';
return c;
}
/*
* 循環條件 a. 接收的最大字符個數 lim, 每讀取一個字符, 該變量自減
* 當該變量自減為0時停止循環接收字符串
* 循環條件 b. 當讀取到的字符 不是 字母 或者數字的時候, 停止循環
*/
for(; --lim > 0; wp++)
{
if(!isalnum(*wp = getc(stdin)))
{
ungetc(*wp, stdin);
break;
}
}
*wp = '';
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;
else
return mid;
}
return -1;
}
執行結果 :
[root@ip28 struct]# gcc word_count.c [root@ip28 struct]# ./a.out auto break break char 1 auto 2 break 1 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])
使用指針進行二分查找 :
-- 使用下標找中值 : 在之前找中值時通過 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
#include
#include
#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
, 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 = '';
return c;
}
/*循環接收字符串, 字符串接收到非標識符 或者 到達個數上限停止循環*/
for(; --max > 0; wp++)
if(!isalnum(*wp = getc(stdin)))
{
ungetc(*wp, stdin);
break;
}
*wp = '';
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後一個元素的首地址*/
else
return 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 break 2 auto 1 break 1 case
結構體數組指針算術運算 : 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
struct word
{
char c;
int i;
};
int main(int argc, char **argv)
{
printf(sizeof(struct word) = %d
, 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
.