一、題目描述
????????定義一個學生結(jié)構(gòu)體兜挨,包含有:學號膏孟,姓名,成績拌汇。輸入N個學生的信息骆莹,并進行基本的鏈表操作。(更好的閱讀體驗担猛,請在我的博客網(wǎng)站上閱讀此文:使用單鏈表數(shù)據(jù)結(jié)構(gòu)存儲結(jié)構(gòu)化的學生信息)
二幕垦、分析與解答
????????這是一道主要考察基礎(chǔ)知識點運用的題目,涉及到結(jié)構(gòu)體傅联、指針先改、字符數(shù)組等相關(guān)的概念。因此蒸走,要熟練的掌握這些知識點的定義與使用仇奶。
2.1學生結(jié)構(gòu)體的定義
typedef struct student_node{
unsigned num; //學號,無符號整型
char name[10]; //姓名比驻,字符數(shù)組
float score; //成績该溯,浮點型
struct student_node *next;
}StudentNode, *PStuNode;
????????其中,struct關(guān)鍵字表示定義的是結(jié)構(gòu)體數(shù)據(jù)類型别惦,student_node是結(jié)構(gòu)體類型名狈茉,花括號中依次列舉該類型的每個成員變量的類型及其名稱,每個成員變量的數(shù)據(jù)類型可以是基本數(shù)據(jù)類型也可以是自定義數(shù)據(jù)類型掸掸。一旦定義了一個結(jié)構(gòu)體類型氯庆,就可以像基本數(shù)據(jù)類型一樣使用,定義該類型的變量扰付、數(shù)組和指針堤撵。如下所示:
1)struct student_node stu_node; // 定義了一個student_node型的變量 stu_node;
2)struct student_node s[20]; //定義了一個student_node類型的數(shù)組s羽莺,用于存放20個該類型的學生數(shù)據(jù)实昨。
3)struct student_node *p; //定義了一個student_node型的指針變量p;
4)為指針p初始化賦值的方式,和基本數(shù)據(jù)類型一致: p = &stu_node盐固。使用指針訪問結(jié)構(gòu)體變量的成員可以使用如下兩種方式:
①(*結(jié)構(gòu)體指針變量名).成員名; (*p).num;
②結(jié)構(gòu)體指針變量名->成員名; p->num;
????????為了簡化結(jié)構(gòu)體變量的定義荒给,可以使用C語言提供的類型別名定義語句typedef族跛,為結(jié)構(gòu)體類型取一個別名。StudentNode,*PStuNode就是struct student_node的別名锐墙,然后可以使用student_node的別名StudentNode定義變量stu_node礁哄,可以使用PStuNode定義指向student_node類型的指針p。如果不再使用student_node定義變量溪北,則可以在定義結(jié)構(gòu)體類型的時候省去桐绒,如果需要使用到,則不可以省略去之拨。
2.2 使用尾插法建立不帶頭結(jié)點的學生鏈表
//尾插法創(chuàng)建學生鏈表.
StudentNode * init_list_tail(){
int i=0,n;
StudentNode *head = NULL, *tail = NULL, *p;
//輸入N個學生的信息
scanf("%d",&n);
while(i++<n){
//申請節(jié)點所占用的內(nèi)存空間
if( (p = (StudentNode *)malloc(sizeof(StudentNode))) == NULL){
printf("memery is not available");
exit(1);
}
//錄入學生節(jié)點的基本信息
scanf("%u",&(p->num)); //輸入學號,無符號整形
getchar();//scanf//消除scanf函數(shù)不接收的 回車符(\n)
gets(p->name); //name中可以包含空格
scanf("%f",&(*p).score); //注意這里的幾個括號茉继,'.'的優(yōu)先級高于'*',因此要打一個括號
p->next = NULL;
//當前申請的是第一個節(jié)點
if(head == NULL){
head = tail = p;
}else{
//鏈尾插值
tail->next = p;
tail = p;
}
}
return head;
}
????????init_list_tail()是返回值為StudentNode型指針的函數(shù)蚀乔。
gets(p->name)是輸入姓名字符串烁竭。在C語言中,輸入字符的方式有g(shù)etchar()吉挣、scanf("%s",str)派撕、gets(str),其中①scanf函數(shù)不能輸入空格;②getchar()函數(shù)是逐個字符輸入;③gets()會將'\n'作為輸入終止符睬魂,因此要注意在這個函數(shù)前將回車符消除掉终吼。
2.3 增加鏈表節(jié)點
//在鏈表頭部新增學生節(jié)點信息
int insert_stu_head(PStuNode *head){
PStuNode p;
//申請節(jié)點所占用的內(nèi)存空間
if( (p = (PStuNode)malloc(sizeof(StudentNode))) == NULL){ // 標注 p 之鄉(xiāng)的空間類型是 PStuNode。與 StudentNode * 相同的功能
printf("memery is not available");
return 0;
}
//錄入學生節(jié)點的基本信息
scanf("%u",&(p->num));
scanf("%s",p->name); // %s,這里的字符串輸入不能有空格
scanf("%f",&(*p).score);
//頭插法插入一個節(jié)點
p->next = *head;
*head = p;
return 1; //只是返回標志
}
????????malloc()是申請內(nèi)存空間的函數(shù)氯哮,與之對應的是free()函數(shù)际跪。p = (PStuNode)malloc(sizeof(StudentNode)))代表申請sizeof(StudentNode)大小的內(nèi)存空間,并轉(zhuǎn)換為PStuNode類型的指針賦給p喉钢。
2.3 刪除score<60的學生節(jié)點
//刪除score<60的學生節(jié)點
void del_stu_by_score(PStuNode *head){
PStuNode pre_p = *head, p = *head;
while(p){
//由于使用的是不帶頭結(jié)點的鏈表姆打,因此,頭節(jié)點需要區(qū)別處理
if((p->score) < 60){
PStuNode temp = p;
if(p == *head){
*head = p->next;
pre_p = p = *head;
}else{
pre_p->next = p->next;
p = pre_p->next;
}
free(temp);
}else{
pre_p = p;
p = pre_p->next;
}
}
}
????????因為刪除的節(jié)點可能會是首節(jié)點肠虽,可能需要改變首節(jié)點的指向幔戏,因此要傳入(PStuNode *head,二級指針)這個參數(shù)舔痕。由于使用的是不帶頭結(jié)點的鏈表评抚,在做判斷的時候豹缀,需要區(qū)分第一個節(jié)點和其余節(jié)點伯复。
2.4 查詢學生姓名為"xiaoming"的學生信息
StudentNode * search_stu_by_name(PStuNode head, char *str){
PStuNode p = head;
while(p){
if( strcmp(p->name,str) == 0 ){
p->next = NULL; //只返回p節(jié)點
return p;
}
p = p->next;
}
return NULL;
}
????????注意,這里的傳參邢笙,是一個字符指針str啸如。要注意字符指針和字符數(shù)組的區(qū)別,字符數(shù)組名是一個常量氮惯,字符指針變量本身是一個變量叮雳,用于存放字符串的首地址想暗,字符串本身是存儲在以該首地址開始的一塊連續(xù)的內(nèi)存空間中并以'\0'作為字符串的結(jié)束。
常用的字符串處理函數(shù)由<string.h>提供支持帘不。①strlen说莫,字符串長度統(tǒng)計函數(shù);②strcat寞焙,連接兩個字符串储狭;③strcpy將一個字符串復制到另一個字符數(shù)組中;④strcmp捣郊,比較兩個字符串的大辛杀贰;⑤strlwr呛牲,將字符串中大寫字母轉(zhuǎn)換成小寫字母刮萌;⑥strupr,將字符串中小寫字母轉(zhuǎn)換成大寫字母娘扩。
2.5 修改學生信息
//修改學生學號為 modify_num 的學生姓名為 'itour'着茸。1:成功,0:未找到該人
int edit_stu_by_num(PStuNode head){
PStuNode p = head;
unsigned modify_num;
printf("請輸入待修改學生信息的學號: ");
scanf("%u",&modify_num);
while(p){
if(p->num == modify_num){
char modify_name[10]; //修改后的姓名
printf("請輸入num=%u的學生的姓名:",modify_num);
getchar(); //消除回車鍵的影響
gets(modify_name);
strcpy(p->name,modify_name);
return 1;
}
p = p->next;
}
return 0;
}
2.6 鏈表的遍歷訪問
void print_list(PStuNode head){
PStuNode p = head;
while(p){
printf("num: %d \t name: %s \t score: %.2f\n",p->num,p->name,p->score);
p = p->next;
}
}
三琐旁、總結(jié)
????????指針元扔、結(jié)構(gòu)體、字符串旋膳、數(shù)組澎语,是C語言中最重要的幾個模塊。在編程開發(fā)中验懊,這幾個知識點往往會配合使用擅羞,比如常見的有:指向字符串的指針、指向數(shù)組的指針义图、指向結(jié)構(gòu)體的指針减俏、字符數(shù)組等等。熟練掌握后碱工,使用起來會很靈活娃承,能實現(xiàn)的功能也是異常強大。
使用C語言可以很方便的控制計算機硬件怕篷,因此历筝,它會經(jīng)常的被用在操作系統(tǒng)、嵌入式廊谓、物聯(lián)網(wǎng)梳猪、驅(qū)動開發(fā)等領(lǐng)域。我們所熟知的操作系統(tǒng)蒸痹,如Windows春弥、Linux就是使用C語言進行開發(fā)的呛哟。操作系統(tǒng)的某些模塊開發(fā)會經(jīng)常的涉及到鏈表、結(jié)構(gòu)體匿沛,比如常見的內(nèi)存管理模塊中扫责,一個內(nèi)存頁就是使用一個結(jié)構(gòu)體進行描述,多個內(nèi)存頁會使用鏈表進行連接起來逃呼,從而達到高效的使用公给。