程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C >> 關於C >> C語言 結構體相關 函數 指針 數組

C語言 結構體相關 函數 指針 數組

編輯:關於C

 

 

結構體概述 : 結構體是 多個 變量的集合, 變量的類型可以不同;

-- 可進行的操作 : 結構體可以進行 拷貝 賦值操作, 可以作為 函數參數 和 函數返回值;

 

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

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 


 

 

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 
, (*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 


 

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

/*
 * 聲明結構體 
 * 同時也聲明結構體類型數組
 * 為數組初始化
 * 直接將每個結構體成員的值依次列出即可
 */
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 


 

(2) 結構體數組示例程序

 

需求 : 實現一個統計 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])


 

 

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
#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 

 

 

(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

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

.

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved