在實際問題中,一組數據往往具有不同的數據類型。例如,在學生登記表中,姓名為字符型,學號為整型或字符型,年齡為整型,性別為字符型,成績為整型或實數型別,顯然,不能使用一個數組來存放這一組數據。因為數組中各個元素的類型和長度都必須一致,以便于編譯系統處理。為了解決這個問題,C語言中給出了另一種構造數據類型–結構。他相當于其他高級語言中的記錄。
“結構”是一種構造類型,他是由若干“成員”組成的。每一個成員可以是一個基本數據類型或者又是一個構造類型。結構是一種“構造”而成的數據類型,在說明和使用之前先定義它,也就是構造它。就像是定義函數一樣。
1:結構的定義
定義一個結構的一般形式為:
struct 結構名
{
成員列表
};
2:結構類型變量的說明
說明結構變量有3中方法,以結構stu為例。
~~~
struct stu
{
int num;
char name[20];
char sex;
float score;
};
//說明結構變量
struct stu boy1,boy2;
~~~
說明變量boy1和boy2為stu結構類型。也可以使用宏定義用一個符號常量來表示一個結構類型,例如
~~~
#define STU struct stu
STU
{
int num;
char name[20];
char sex;
float score;
};
STU boy1,boy2;
~~~
還可以在定義結構類型的同時說明結構變量,例如:
~~~
struct stu
{
int num;
char name[20];
char sex;
float score;
} boy1,boy2;
~~~
或者是直接說明結構變量,例如
~~~
struct
{
int num;
char name[20];
char sex;
float score;
}boy1,boy2;
~~~
注意:
如果結構變量是全局變量或為靜態變量,則可以對它進行 初始化賦值。對局部或自動結構變量不能進行初始化賦值。
3:結構數組
繼續使用上面stu的例子:
struct stu boys[20];
4:結構指針變量
當使用一個指針變量指向一個結構變量時,稱之為結構指針變量。結構變量中的值是所指向的結構變量的首地址。通過結構指針即可訪問該結構
變量,這與數組指針和函數指針的情況是相同的。結構指針變量說明的一般形式為:
struct 結構名 *結構指針變量名
例如,如果要說明一個指向stu的指針變量pstu,可寫為:
struct stu *pstu;
當然,也可以在定義stu結構的時候同時說明pstu。與前面變量的聲明相同。結構指針變量必須要先賦值后才能使用。賦值是把結構變量的首地址賦予該指針變量,不能把結構名賦予該指針變量,如過boy是被說明為stu類型的結構變量,則”pstu=&boy”是正確的,但是”pstu=&stu”是錯誤的。
結構名和結構變量是兩個不同的概念,不能混淆。結構名只能表示一個結構形式,編譯系統并不對他分配空間。只有當變量說明為這種類型的結構時,才對該變量分配內存空間。因此”&stu”的寫法是錯誤的,不可能去取一個結構名的首地址。有了結構指針變量,就能更方便的訪問結構變量的各個成員。
程序訪問的一般形式為:(*結構指針變量).成員名 或為:
結構指針變量->成員名
例如”(*pstu).num”或者”pstu->num”。
應該注意(*pstu)兩側的括號不可少,因為成員符號“.”的優先級高于”*“。如果去掉括號協作*pstu.num,就等效于”*(pstu.num)”,這樣意義就不對了。
5:結構指針變量作為函數參數
在ANSI C標準中允許使用結構變量作為函數參數進行整體傳送。但是這種傳送要將全部成員逐個傳送,特別是成員為數組時將會使傳送的時間和空間開銷很大,嚴重的降低了程序的效率。因此最好的辦法就是使用指針,即用指針變量作為函數參數進行傳送,由于實參傳向星燦的只是地址,從而減少了時間和空間的開銷。
在本例中,假設一個通訊錄由以下幾項數據信息組成
數據項 類型
姓名 字符串
地址 字符串
郵政編碼 字符串
電話號碼 字符串
下面請看一下代碼的實現:
~~~
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ZIPLEN 10
#define PHONLEN 10
struct addr{
char *name; /* 姓名 */
char *address; /* 地址 */
char zip[ZIPLEN]; /* 郵編 */
char phone[PHONLEN]; /* 手機號碼 */
};
int readaddr(struct addr *dpt);
int writeaddr(struct addr *dpt);
/**
* 編制一個包含姓名,地址,郵編和電話的通訊錄
* 輸入輸出函數。
*/
int main()
{
struct addr p[1];
int i,j;
for(i=0;readaddr(p+i);i++);
for(j = 0;j < i;j++)
writeaddr(p+j);
puts("Press any key to quit...\n");
getch();
return 0;
}
/**
* 向結構中的成員賦值
*
*/
int readaddr(struct addr *dpt)
{
int len;
char buf[120]; //輸入字符串的緩沖區
printf("Please input the Name:\n");
if(scanf("%s",buf)==1){
len = strlen(buf);
dpt->name = (char *)malloc(len+1);
strcpy(dpt->name,buf);
}else return 0;
printf("Please input the Address:\n");
if(scanf("%s",buf) == 1){
len = strlen(buf);
dpt->address = (char *)malloc(len+1);
strcpy(dpt->address,buf);
}else{
free(dpt->name);
return 0;
}
printf("Please input the Zip:\n");
if(scanf("%s",buf) == 1){
strncpy(dpt->zip,buf,ZIPLEN-1);
}else{
free(dpt->name);
free(dpt->address);
return 0;
}
printf("Please input the Phone:\n");
if(scanf("%s",buf) == 1){
strncpy(dpt->phone,buf,PHONLEN-1);
}else{
free(dpt->name);
free(dpt->address);
return 0;
}
return 1;
}
/**
* 輸出通訊錄
*/
int writeaddr(struct addr *dpt)
{
printf("Name : %s\n",dpt->name); /* 輸出姓名 */
printf("Address : %s\n",dpt->address); /* 輸出地址 */
printf("Zip : %s\n",dpt->zip); /* 輸出郵編 */
printf("Phone : %s\n",dpt->phone); /* 輸出手機號 */
}
~~~
下面是運行結果:

注意:關于動態內存分配問題:
在數組中,數組的長度是預先定義好的,在整個程序中固定不變。C語言不允許動態數組類型。例如”int n;scanf(“%d”,n);int a[n];”,這是錯誤的。但是在實際編譯過程中,往往會發生這種情況,即所需的內存空間取決于實際輸入的數據,而無法預先確定。對于這種問題,用數組的辦法很難解決。為了解決上述問題,C語言提供了一些內存管理函數,這些內存管理函數可以按照需要動態分配內存空間,也可以把不再使用的空間收回待用。常用的內存管理函數有3個:
1:分配內存空間函數malloc。調用形式
(類型說明符 *)malloc(size);
在內存的動態存儲區中分配一塊長度為”size”字節的連續區域。函數的返回值為該區域的首地址。
2:分配內存空間函數 calloc。calloc也用于分配內存空間,調用形式:
(類型說明符 *)calloc(n,size);
在內存動態存儲區中分配n快長度為”size”字節的連續區域。函數的返回值為該區域的首地址。
3:釋放內存空間函數free.調用形式
free(void *ptr);
釋放ptr所指向的一塊內存區域,ptr是一個任意類型的指針變量,他指向被釋放區域的首地址。被釋放區域應是由malloc或calloc函數所分配的區域。
- 前言
- 實例一:HelloWorld
- scanf函數學習
- 實數比較
- sizeof()保留字獲取類型的大小
- 自增/自減學習
- C學習if條件判斷和for循環
- C實現的九九乘法表
- C實現一個比較簡單的猜數游戲
- 使用C模擬ATM練習switch..case用法
- 記錄一個班級的成績練習一維數組
- C數組實現矩陣的轉置
- C二維數組練習
- 利用數組求前n個質數
- C實現萬年歷
- C實現數組中元素的排序
- C實現任意進制數的轉化
- C判斷一個正整數n的d進制數是否是回文數
- C使用遞歸實現前N個元素的和
- 鋼材切割問題
- 使用指針比較整型數據的大小
- 指向數組的指針
- 尋找指定元素
- 尋找相同元素的指針
- 整數轉換成羅馬數字
- 字符替換
- 從鍵盤讀入實數
- C實現字符行排版
- C實現字符排列
- C實例--判斷一個字符串是否是回文數
- 通訊錄的輸入輸出
- 撲克牌的結構定義
- 使用“結構”統計學生成績
- 報數游戲
- 模擬社會關系
- 統計文件中字符個數
- C實現兩個文件的內容輸出到同一個屏幕