計算機二級C語言結構體要點
結構體與共用體要點
一、概述
結構體(structure)是一種數(shù)據(jù)類型,它把互相聯(lián)系的數(shù)據(jù)組合成一個整體。
把不同類型的數(shù)據(jù)組合成一個有機的整體,可以用結構體解決。
結構體中的每一項數(shù)據(jù),稱為結構體“成員”(member)或“分量”。
聲明結構體類型的一般形式:struct 結構體名
{成員表列};
聲明各成員的形式:類型名 成員名;
例如:學生數(shù)據(jù)struct student
{int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
}; 注意不要忽略最后的分號
student結構體類型占59個字節(jié)。
二、定義結構體類型變量的方法
1.先聲明結構體類型再定義變量名
struct student student1, student2;要求指定為某一特定的結構體類型
2.在聲明類型的同時定義變量
struct 結構體名
{成員表列
}變量名表列;
例如:struct student
{int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
} student1, student2;
3.直接定義結構體類型變量
struct
{成員表列
}變量名表列;
幾點說明:
(1)類型與變量是不同的概念;
(2)結構體中的成員可單獨使用,其作用與地位相當于普通變量;
(3)成員也可以是一個結構體變量;
(4)成員名與普通變量名相同,不代表同一對象。
三、結構體變量的引用
(1)不能將結構體變量整體進行輸入和輸出,只能對各個成員分別進行輸入和輸出。
printf("%d,%s,%c,%d,%f,%s\n",student1);錯誤
(2)引用成員的方式:結構體變量名.成員名
student1.num=10010;
student1.birthday.month=3;(若干個成員運算符)
當成員是另一個結構體變量時,應一級一級地引用成員。
僅在以下兩種情況下,可以把結構體變量作為一個整體來訪問。
(1) 結構體變量整體賦值
例、student2 = student1;
(2)取結構體變量地址
例、printf("%x", &student1); /*輸出student1的地址 */
四、結構體變量的初始化
struct student
{long int num; /* 學號 */
char name[20]; /* 姓名 */
char sex; /* 性別 */
char addr[20]; /* 地址 */
}a = {89031, "Li Lin", 'M', "123 Beijing Road"};
注意:不能在結構體內賦初值。
例、下面程序錯誤
struct student
{ long int num = 89031;
char name[20] = "Li Lin";
char sex = 'M';
char addr[30] = "123 Bejing Road";
}a;
五、結構體數(shù)組
每個數(shù)組元素都是一個結構體類型數(shù)據(jù)
1.定義結構體數(shù)組
和定義結構體變量的方法相仿(三種方法)
2.結構體數(shù)組的初始化
在定義數(shù)組的后面加上:={初始表列};
struct student
{ int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
}stu[3] = {{10101,"Li Lin", 'M', 18, 87.5, "103 Bejing Road"},
{10102,"Zhang Fun",'M', 19, 99, "130 Shanghai Roaad"},
{10104,"Wang Min", 'F', 20, 78.5, "1010 Zhongshan Road"} };
六、指向結構體類型數(shù)據(jù)的指針
結構體變量的指針:就是該變量所占據(jù)的內存段的起始地址。
1.指向結構體變量的指針
(*p).num表示:p指向的結構體變量中的成員num
成員運算符“.”優(yōu)先于“*”運算符,不能寫成*p.num≡*(p.num)
三種表示形式:
(1)構體變量名. 成員名
(2)(*p).成員名 該方式用得很少
(3)p->成員名
2.指向結構體數(shù)組的指針
注意:
(1)p=stu;,則p++指向stu[1]
(2)運算符“->”優(yōu)先于“++”運算符
++p->num:使p所指向的num成員值加1
(++p)->num:先使p+1,然后得到它指向的元素中的num成員值
例:有4個學生,每個學生包括學號、姓名和成績。要求找出成績最高者的姓名和成績。
#include "stdio.h"
void main()
{ struct student
{int num; /* 學號 */
char name[20]; /* 姓名 */
float score; /* 成績 */
};
struct student stu[4]; /* 4個學生 */
struct student *p;
int i;
int temp = 0; /* 成績最高學生在數(shù)組中的序號,0~3 */
float max; /* 最高成績 */
for(i=0; i<4; i++) /* 輸入4個學生的學號、姓名、成績 */
scanf("%d %s %f", &stu[i].num, stu[i].name, &stu[i].score);
for(max=stu[0].score, i=1; i<4; i++) /* stu[0]已賦給max */
{if (stu[i].score > max)
{
max = stu[i].score;
temp = i;
}
}
p = stu + temp; /* p指向成績最高的學生結構 */
printf("\nThe maximum score:\n");
printf("No.: %d\n name: %s\n score: %4.1f\n",
p->num, p->name, p->score);
}
3、結構體變量、指向結構體的指針均可作為函數(shù)參數(shù)
例:有一個結構體變量stu,內含學生學號、姓名和三門課程的成績。要求在main中賦以值,在函數(shù)print中打印輸出。
#include "stdio.h"
#include "string.h"
#define format "%d\n %s\n %f\n %f\n %f\n"
struct student
{ int num; /* 學號 */
char name[20]; /* 姓名 */
float score[3]; /* 三門課程的成績 */
};
void print(struct student *p); /* print函數(shù)原型聲明 */
void main()
{struct student stu;
stu.num = 12345;
strcpy(stu.name, "Li Li");
stu.score[0] = 67.5;
stu.score[1] = 89;
stu.score[2] = 78.6;
print(&stu); /*如果stu是結構體數(shù)組,則不要&符號*/
}
void print(struct student *p) /* print函數(shù)定義 */
{printf(format, p->num, p->name, p->score[0], p->score[1], p->score[2]);
printf("\n");
}
(1)結構體的成員作函數(shù)的參數(shù)。
與普通變量作函數(shù)參數(shù)的用法相同。值傳送,不能修改實參的值。
(2)結構體指針作函數(shù)的參數(shù)。
將結構體的地址傳送給函數(shù),效率高,可以修改實參的值。
(3)結構體作函數(shù)的參數(shù)。
將結構體的全部成員值傳送給函數(shù),效率低,不能修改實參的值。
例:
#include<string.h>
struct STU
{char name[10];
int num;
};
void f(char *name,int num)
{struct STU s[2]={{"SunDan",2004},{"Penghua",20045}};
num=s[0].num;
strcpy(name,s[0].name);
}
main()
{struct STU s[2]={{"YangSan",20041},{"LiSiGuo",20042}},*p;
p=&s[1];
f(p->name,p->num);前一個參數(shù)的地址,后一個是數(shù)值
printf("%s %d\n",p->name,p->num);
getch();
}
運行結果:SunDan 20042前一個隨子函數(shù)變化,后一個不變仍是主函數(shù)中的值。
七、用指針處理鏈表(一定要學會畫圖)
1.鏈表概述
鏈表:動態(tài)地進行存儲分配的一種結構,它動態(tài)地進行存儲分配。
數(shù)組:存放不同班級的學生數(shù)據(jù),數(shù)組定得足夠大,浪費內存。
數(shù)組必須事先定義固定的長度(元素個數(shù)),不能適應數(shù)據(jù)動態(tài)地增減的情況。當數(shù)據(jù)增加時,可能超出原先定義的元素個數(shù);當數(shù)據(jù)減少時,造成內存浪費。
鏈表動態(tài)地進行存儲分配,可以適應數(shù)據(jù)動態(tài)地增減的情況,且可以方便地插入、刪除數(shù)據(jù)項。(數(shù)組中插入、刪除數(shù)據(jù)項時,需要移動其它數(shù)據(jù)項)。
鏈表有單向鏈表、雙向鏈表、環(huán)形鏈表等形式。
結點:鏈表中的每一個元素,包括兩部分
①用戶需要的實際數(shù)據(jù)
②下一個結點的地址
┌─┬─┐ ┌─┬─┐ ┌─┬─┐ ┌─┬──┐
head─→│ A│·┼→│B │·┼→│C │·┼→│D │NULL│
└─┴─┘ └─┴─┘ └─┴─┘ └─┴──┘
head指向第一個元素,第一個元素又指向第二個元素,…直到最后一個元素,該元素不再指向其它元素。
表尾:地址部分放一個“NULL”(表示空地址)
※結點應為結構體類型,一個結點中應包含一個指針變量,用它存放下一個結點的地址。
例:struct student
{int num;
float score;
struct student next;/*next指向struct student類型數(shù)據(jù)*/
};
student鏈表
2.簡單鏈表
所有結點都是在程序中定義的,不是臨時開辟的,是“靜態(tài)鏈表”
3.處理動態(tài)鏈表所需的函數(shù)
(1)malloc(size)
作用:在內存的動態(tài)存儲區(qū)中。
函數(shù)返回值:該分配域的起始地址。不成功,則返回NULL。
(2)calloc(n,size)
分配n個長度為size的連續(xù)空間
(3)free(p)
釋放由p指向的內存區(qū)。函數(shù)無返回值。
4.建立動態(tài)鏈表
即從無到有,一個一個地開辟結點和輸入各結點數(shù)據(jù),并建立起前后相鏈的關系。
例、寫一函數(shù)建立一個有3名學生數(shù)據(jù)的單向動態(tài)鏈表
過程:開辟單元→輸入數(shù)據(jù)→加入鏈表
head:頭指針
p1、p2:工作指針,p2跟著p1向后走
sizeof:求字節(jié)運算符
(struct student *):返回的指針轉換為指向struct student類型數(shù)據(jù)的指針。
5.輸出鏈表
一般從鏈表首部依次輸出。
6.對鏈表的刪除操作
刪去結點,即是把它從鏈表中分離出來即可。
(1)刪除頭結點
(2)刪除中后結點
7.對鏈表的插入操作
將一個結點按指定次序,插入到一個已有的鏈表中
(1)頭部
(2)中部
(3)后部
例:
(1)下列程序用來從鍵盤上讀入一行字符,并按輸入順序建立一個“反式”鏈表。即讀入的第1個字符存入尾結點,讀入的第2個字符存入倒數(shù)第2個結點,依此類推,讀入的最后一個字符存入頭結點。讀入完成后,按鏈表輸出這一行字符,最后釋放全部結點空間。
例如:讀入abcd,建立的鏈表如下圖
┌─┬─┐ ┌─┬─┐ ┌─┬─┐ ┌─┬─┐
head─→│d │·┼→│c │·┼→│b │·┼→│a │ 0│
└─┴─┘ └─┴─┘ └─┴─┘ └─┴─┘
最后輸出的一行字符為 dcba
#define NULL 0
#define LEN sizeof(struct node)
#include "stdio.h"
struct node
{char info; struct node *next; }
main()
{struct node *head,*p;
char c;
head= NULL ;
while((c=getchar())!='\n')
{p=( struct node *)malloc(LEN);
p->info=c;
p->next=head;
head= p ;}
while(head!=NULL)
{p= head ;
head= head->next或p->next ;
putchar(p->info);
free(p);/*釋放一個結點*/}
}
(2)建立一條鏈,鏈中的數(shù)據(jù)按從小到大的順序排列.
#include <stdio.h>
struct node
{int data; struct node *next; };
struct node *addx(struct node *head,int x)
{struct node *p,*p1,*p2;
p=(struct node *)malloc(sizeof(struct node));
p->data=x;
if ( head=NULL )
{head=p;p->next=NULL;return(head);}
if (head->data>=p->data)
{ ( p->next=head );head=p;return (head);}
p1=head; p2=p1->next;
if (p2==NULL)
{p1->next=p;p->next=NULL;return (head);}
while (p2->next!=NULL&&( p2->data<p->data ))
{p1=( p2 ); p2=p2->next; }
if (p2->data<p->data)
{p2->next=p;p->next=NULL;}
else
{( p->next=p2 );p1->next=p;}
return(head); }
main()
{struct node *head;
int i,x;
head=NULL;
for (i=0;i<5;i++)
{printf("\nInput %2dth number!",i);
scanf("%d",&x);
head=addx(head,x); }
while (head!=NULL)
{printf("\n%d",head->data); head=head->next; }
}
八、共用體
1.共用體的概念
幾種不同類型的變量共占同一段內存單元(同一地址開始)。
共用體變量定義的一般形式:
struct 共用體名
{成員表列
}變量表列;
與結構體一樣可以有三種定義形式。
例如:union data
{int i;
char ch;
float f;
}a,b,c;
注意:共用體變量所占的內存長度等于最長的成員的長度。
2.共用體變量的引用方式
不能引用共用體變量,而只能引用共用體變量中的成員
如:a.i、 a.ch、 a.f
3.共用體類型數(shù)據(jù)的特點
每一瞬間只能存放其中一種成員,起作用的是最后一次存放的成員。
例題:
main()
{union {int count[2]; char ch[4];} un;
int i;
char letter=6;
for(i=0;i<4;i++) un.ch[i]=letter++;
for(i=0;i<2;i++) printf("%d:%x, ", i, un.count[i];
}
結果:0:706,1:908
九、枚舉類型
枚舉類型enmu:將變量的值一一列舉出來,變量的值只限于列舉出來的值的范圍。
如聲明枚舉類型:enum weekday{sun,mon,tue,wed,thu,fri,sat};
括號中的稱為枚舉元素或枚舉常量
用它來定義變量:enum weekday workday,week_end;
(類似的三種方法定義枚舉變量)
說明:
(1)枚舉元素是常量,不能被賦值
(2)枚舉元素是有值的0,1,2…,定義時也可以改變枚舉元素的值
enum weekday{sun=7,mon=1,tue,wed,thu,fri,sat} workday,week_end;
(3)枚舉值可以用來做判斷比較
(4)一個數(shù)值不能直接賦給一個枚舉變量