指針原理:
創(chuàng)新互聯(lián)建站主要從事網(wǎng)站設(shè)計(jì)制作、成都網(wǎng)站制作、網(wǎng)頁設(shè)計(jì)、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務(wù)。立足成都服務(wù)大通,十余年網(wǎng)站建設(shè)經(jīng)驗(yàn),價(jià)格優(yōu)惠、服務(wù)專業(yè),歡迎來電咨詢建站服務(wù):028-86922220
指針就是指向一個(gè)特定內(nèi)存地址的一個(gè)變量。簡化了的內(nèi)存空間模型是按照從0到某一個(gè)數(shù)(比如1048575=1M-1)的一維線性空間,其中的每一個(gè)數(shù)對(duì)應(yīng)一個(gè)存儲(chǔ)單元,即1個(gè)字節(jié)。指針有兩個(gè)屬性:指向性和偏移性。指向性指的是指針一定要有一個(gè)確定的指向,偏移性則是體現(xiàn)指針重要應(yīng)用的方面,即指針可以按程序員的要求向前或向后偏移。
指針的應(yīng)用往往與數(shù)組聯(lián)系在一起,為了方便說明問題,不妨從數(shù)組開始解釋指針的偏移。數(shù)組就是許多的變量,它的一個(gè)重要特征就是在內(nèi)存空間中連續(xù)地存放,而且是按下標(biāo)順序存放。比如我們定義一個(gè)有100個(gè)變量的一維整型數(shù)組,它一定從內(nèi)存的某一個(gè)存儲(chǔ)單元開始按數(shù)組下標(biāo)順序存放,連續(xù)占用100*4=400字節(jié)。當(dāng)我們定義一個(gè)數(shù)組時(shí),系統(tǒng)就會(huì)自動(dòng)為它分配一個(gè)指針,這個(gè)指針指向數(shù)組的首地址。(在本文剩余部分的論述中,不加區(qū)分地使用“指向數(shù)組的首地址”與“指向數(shù)組的第一個(gè)元素”這兩種說法,事實(shí)上這兩種說法也是一致的。)
為了讓系統(tǒng)了解每一次指針偏移的單位,也為了方便程序員進(jìn)行指針偏移(讓程序員記住一個(gè)×××變量占用4字節(jié),一個(gè)字符型變量占用1字節(jié)等等是很麻煩的),不用每次去計(jì)算要偏移多少個(gè)字節(jié),C語言引入了指針的基類型的概念?;愋偷淖饔镁褪亲屜到y(tǒng)了解某個(gè)指針每次偏移的字節(jié)數(shù)。比如,對(duì)于一個(gè)字符型指針,它每次偏移(比如ptr=ptr+1)所起到的作用就是讓指針偏移1字節(jié);而對(duì)于一個(gè)整型指針,它每次偏移就應(yīng)該是4字節(jié)。這樣操作數(shù)組時(shí)就帶來了方便。比如對(duì)于一個(gè)指向某個(gè)整型數(shù)組起始存儲(chǔ)單元(稱為首地址)的指針ptr,ptr=ptr+1就表示將該指針指向這個(gè)數(shù)組的下一個(gè)元素的存儲(chǔ)單元,即向后移動(dòng)4字節(jié),而不僅僅是移動(dòng)一個(gè)存儲(chǔ)單元(即移動(dòng)1字節(jié))。
&()、*()、和[ ]運(yùn)算符的意義
在本文中,將&()、*()和[ ]都看成是運(yùn)算符。這樣可以方便理解這三個(gè)概念。簡單地說,&()將某個(gè)標(biāo)識(shí)符(比如變量)轉(zhuǎn)化為其在內(nèi)存空間中的地址,而*()是產(chǎn)生一個(gè)對(duì)應(yīng)于某個(gè)地址的標(biāo)識(shí)符,[ ]就更復(fù)雜一點(diǎn),ptr[i]表示將ptr這個(gè)指針虛擬地按其基類型進(jìn)行i個(gè)單位的后移,再進(jìn)行*(ptr)運(yùn)算。但這是一個(gè)虛擬的后移,即ptr[i]并不改變ptr的指向,只是將其后移i個(gè)單位并取*()運(yùn)算的結(jié)果算出來了而已。要改變指針的指向,我們只能通過類似于ptr=ptr+i這樣的語句來實(shí)現(xiàn)。
實(shí)際中,我們往往不愿意經(jīng)常改變指針的指向,因?yàn)橹羔樀囊苿?dòng)雖然是自由的,但移動(dòng)后往往會(huì)“移不回來”,因?yàn)槲覀兛赡軣o法清楚地確定指針的偏移量。后面我們將看到,對(duì)于用指針來表示的數(shù)組,其元素的引用和賦值是完全可以不用改變指向這個(gè)數(shù)組的首地址的指針指向的,而一旦要改變這個(gè)指針的指向,問題就會(huì)變得復(fù)雜一些。
指針類型和系統(tǒng)自動(dòng)分配的指針
指針可以指向幾乎所有我們感興趣的程序設(shè)計(jì)要素:函數(shù)、數(shù)組、結(jié)構(gòu)體、鏈表節(jié)點(diǎn)等等。其中不同函數(shù)間往往并不存在嚴(yán)格的線性關(guān)系。鏈表節(jié)點(diǎn)可以根據(jù)算法需要在邏輯上(或物理上)不按線性連續(xù)存儲(chǔ)。但數(shù)組、結(jié)構(gòu)體的共同特征就是它們?cè)谖锢砩隙际蔷€性連續(xù)存儲(chǔ)的。只要指針指向了它們的首地址,就可以通過簡單的偏移來訪問各個(gè)它們的元素。指針的偏移性在這兩種數(shù)據(jù)結(jié)構(gòu)中發(fā)揮著至關(guān)重要的作用。這時(shí),我們?cè)倩叵牖愋偷亩x目的,就會(huì)有更深層次的認(rèn)識(shí)了。對(duì)于一個(gè)數(shù)組或結(jié)構(gòu)體,它的基類型長度應(yīng)當(dāng)是其元素的長度(這里的長度即指在內(nèi)存空間中占用的字節(jié)數(shù)),而不再限于定義為某種簡單數(shù)據(jù)類型的長度。
在我們定義數(shù)組和函數(shù)時(shí),系統(tǒng)都會(huì)為其自動(dòng)分配一個(gè)指向其首地址的指針。其中,指針在數(shù)組中的應(yīng)用是最頻繁的,也是最基礎(chǔ)的。對(duì)于一個(gè)數(shù)組,其名稱就是一個(gè)指針變量,亦即假如我們定義“int a[10];”的同時(shí)就定義了“int *a=a;”(這只是為了說明問題,這樣的語句顯然是不合法的)。
數(shù)組應(yīng)用中典型的二級(jí)指針
設(shè)定一個(gè)指向指針的指針,即設(shè)定一個(gè)二級(jí)指針。一般認(rèn)為,指針不宜超過二級(jí),否則會(huì)大大增加邏輯錯(cuò)誤出現(xiàn)的可能性。
鏈表原理:
舉個(gè)例子,跳馬,依下圖將每一步跳馬之后的位置之后的位置(x,y)放到一個(gè)“結(jié)點(diǎn)”里,再用“鏈子穿起來”,形成一條鏈,相鄰兩結(jié)點(diǎn)間用一個(gè)指針將兩者連到一起。
為了表示這種既有數(shù)據(jù)又有指針的情況,引入結(jié)構(gòu)這種數(shù)據(jù)類型。
依上圖有7個(gè)結(jié)點(diǎn)。
用指針處理鏈表
鏈表是程序設(shè)計(jì)中一種重要的動(dòng)態(tài)數(shù)據(jù)結(jié)構(gòu),它是動(dòng)態(tài)地進(jìn)行存儲(chǔ)分配的一種結(jié)構(gòu)。
動(dòng)態(tài)性體現(xiàn)為:
鏈表中的元素個(gè)數(shù)可以根據(jù)需要增加和減少,不像數(shù)組,在聲明之后就固定不變;
元素的位置可以變化,即可以從某個(gè)位置刪除,然后在插入到一個(gè)新的地方;
結(jié)點(diǎn)里的指針是存放下一個(gè)結(jié)點(diǎn)的地址
鏈表中的元素稱為“結(jié)點(diǎn)”,每個(gè)結(jié)點(diǎn)包括兩個(gè)域:數(shù)據(jù)域和指針域;
單向鏈表通常由一個(gè)頭指針(head),用于指向鏈表頭;
單向鏈表有一個(gè)結(jié)尾點(diǎn),該結(jié)點(diǎn)的指針部分指向一個(gè)空結(jié)點(diǎn)(NULL)。
學(xué)生信息管理系統(tǒng)代碼:
/* *學(xué)生信息管理程序, *管理學(xué)生的個(gè)人信息及各科成績; */ #include<stdio.h> #include<conio.h> #include<string.h> #include<stdlib.h> typedef struct NodeNode; //定義成績信息節(jié)點(diǎn) //分別為語文、數(shù)學(xué)、英語和總成績; struct Score { int chinese,math,english,sum; }; //定義學(xué)生信息節(jié)點(diǎn) //分別為姓名、班級(jí)、學(xué)號(hào)、成績和指向下一個(gè)節(jié)點(diǎn)的指針 //定義了4個(gè)全局變量,頭節(jié)點(diǎn),和臨時(shí)節(jié)點(diǎn)變量; struct Node { char name[20],classs[20],number[20]; struct Score score; struct Node* next; }*head,*u,*p,*q; //定義多個(gè)學(xué)生的學(xué)生個(gè)數(shù)及各科平均成績優(yōu)秀率及格率; intn,C,M,E,Cj,Cy,Mj,My,Ej,Ey; char num[20]; //進(jìn)入菜單函數(shù) void Welcome() { printf("\t\t # # # # # # # # # # # # # # # ##\n"); printf("\t\t # 歡迎您使用學(xué)生成績管理系統(tǒng) #\n"); printf("\t\t # #\n"); printf("\t\t # 1.讀取文件 #\n"); printf("\t\t # #\n"); printf("\t\t # 2.保存文件 #\n"); printf("\t\t # #\n"); printf("\t\t # 3.添加學(xué)生成績 #\n"); printf("\t\t # #\n"); printf("\t\t # 4.修改學(xué)生成績 #\n"); printf("\t\t # #\n"); printf("\t\t # 5.刪除學(xué)生成績 #\n"); printf("\t\t # #\n"); printf("\t\t # 6.查詢個(gè)人成績 #\n"); printf("\t\t # #\n"); printf("\t\t # 7.查詢本班成績 #\n"); printf("\t\t # #\n"); printf("\t\t # 8.查詢?nèi)3煽?nbsp; #\n"); printf("\t\t # #\n"); printf("\t\t # 9.退出管理系統(tǒng) #\n"); printf("\t\t # #\n"); printf("\t\t # # # # # # # # # # # # # # # ##\n\n"); printf("\t\t 請(qǐng)輸入指令:(1-9)"); } //構(gòu)造節(jié)點(diǎn)函數(shù) Node* new_node(Node*uu) { uu = (Node*)malloc(sizeof(Node)); uu->next = NULL; return uu; } //添加學(xué)生信息 void Add() { //新建一個(gè)節(jié)點(diǎn); u = new_node(u); printf("\n請(qǐng)輸入您要加入的學(xué)生的信息:\n"); printf("\n姓名: "); scanf("%s",u->name); printf("\n班級(jí): "); scanf("%s",u->classs); printf("\n學(xué)號(hào): "); scanf("%s",u->number); printf("\n語文、數(shù)學(xué)、英語成績: "); scanf("%d%d%d",&u->score.chinese,&u->score.math,&u->score.english); //計(jì)算總成績; u->score.sum = u->score.chinese +u->score.math + u->score.english; //采用頭插法將新節(jié)點(diǎn)的尾指針指向第二個(gè)節(jié)點(diǎn)(掰開) u->next = head->next; //將新節(jié)點(diǎn)放在頭節(jié)點(diǎn)后面; head->next = u; printf("\n--->添加成功!\n"); } //根據(jù)學(xué)號(hào)修改信息 //和查找函數(shù)一樣,依次從第二個(gè)節(jié)點(diǎn)開始遍歷,如果找到這更新 void Mod() { n = 0; printf("\n請(qǐng)輸入您要修改的學(xué)號(hào): "); scanf("%s",num); for(u = head; u != NULL;u =u->next) { if(strcmp(u->number,num) == 0) { n = 1; printf("\n請(qǐng)輸入新的語文、數(shù)學(xué)、英語成績: "); scanf("%d%d%d",&u->score.chinese,&u->score.math,&u->score.english); u->score.sum =u->score.chinese + u->score.math + u->score.english; printf("\n--->修改成功!\n"); break; } } if(!n) printf("\n--->沒有這個(gè)學(xué)生的信息!\n"); } //根據(jù)學(xué)號(hào)刪除學(xué)生信息, //從頭節(jié)點(diǎn)開始遍歷,如果找到這刪除此節(jié)點(diǎn); void Del() { n = 0; printf("\n請(qǐng)輸入您要?jiǎng)h除的學(xué)生的學(xué)號(hào): "); scanf("%s",num); for(u = head; u != NULL;u =u->next) { if(strcmp(u->number,num) == 0) { n = 1; p->next = u->next; free(u); printf("\n--->刪除成功!\n"); break; } p = u; } if(!n) printf("\n--->沒有這個(gè)學(xué)生的信息!\n"); } void Sort() { int i,j; //記錄學(xué)生總數(shù); n = 0; for(u = head->next; u != NULL;u =u->next) n++; //采用冒泡法對(duì)各個(gè)節(jié)點(diǎn)按班級(jí)升序和總成績降序排列 for(i=1;i<=n;i++) { u = head; for(j=0;j<n-i;j++) { p = u->next; q = p->next; if(strcmp(p->classs,q->classs) > 0 ||strcmp(p->classs,q->classs) == 0 && p->score.sum <q->score.sum) { u->next = q; p->next = q->next; q->next = p; } u = u->next; } } } //按學(xué)號(hào)查找某一學(xué)生成績; void Que_One() { //標(biāo)志變量,記錄是否查找成功; n = 0; printf("\n請(qǐng)輸入您要查詢的學(xué)生的學(xué)號(hào): "); scanf("%s",num); //從第二個(gè)節(jié)點(diǎn)開始遍歷,直到最后一個(gè)節(jié)點(diǎn)為止; for(u = head->next; u != NULL;u =u->next) { //如果當(dāng)前節(jié)點(diǎn)學(xué)號(hào)與要查找學(xué)號(hào)一致這輸出此學(xué)生信息; if(strcmp(u->number,num) == 0) { n = 1; printf("\n"); puts("班級(jí) 姓名 語文 數(shù)學(xué) 英語總成績"); printf("%-11s%-15s",u->classs,u->name); printf("%-6d%-6d%-6d%-6d\n",u->score.chinese,u->score.math,u->score.english,u->score.sum); break; } } if(!n) printf("\n--->沒有這個(gè)學(xué)生的信息!\n"); } void Analyze_Sco(Node*uu) { //對(duì)查找到的節(jié)點(diǎn)進(jìn)行求各科平均成績 //求優(yōu)秀率及格率; C += uu->score.chinese; M += uu->score.math; E += uu->score.english; if(uu->score.chinese >= 60) Cj++; if(uu->score.chinese >= 90) Cy++; if(uu->score.math >= 60) Mj++; if(uu->score.math >= 90) My++; if(uu->score.english >= 60) Ej++; if(uu->score.english >= 90) Ey++; } //打印各科平均成績及格率優(yōu)秀率 void Print_Sco() { printf("語文平均成績: %-6.2f, 及格率: %%%-6.2f , 優(yōu)秀率:%%%-6.2f.\n\n",(float)C/n,(float)100*Cj/n,(float)100*Cy/n); printf("數(shù)學(xué)平均成績: %-6.2f, 及格率: %%%-6.2f , 優(yōu)秀率:%%%-6.2f.\n\n",(float)M/n,(float)100*Mj/n,(float)100*My/n); printf("英語平均成績: %-6.2f, 及格率: %%%-6.2f , 優(yōu)秀率:%%%-6.2f.\n\n",(float)E/n,(float)100*Ej/n,(float)100*Ey/n); } //查找某一班級(jí)所以學(xué)生的信息; void Que_Cla() { //對(duì)鏈表節(jié)點(diǎn)排序; Sort(); n = C = M = E = Cj = Cy = Mj = My = Ej = Ey= 0; printf("\n請(qǐng)輸入您要查詢的班級(jí): "); scanf("%s",num); printf("\n"); for(u = head->next; u != NULL;u =u->next) { //不是該班的學(xué)生則跳過; if(strcmp(u->classs,num)) continue; //如果是第一個(gè)學(xué)生則打印頭信息 if(!n) puts("學(xué)號(hào) 姓名 語文 數(shù)學(xué) 英語總成績"); n++; printf("%-11s%-15s",u->number,u->name); printf("%-6d%-6d%-6d%-d\n",u->score.chinese,u->score.math,u->score.english,u->score.sum); Analyze_Sco(u); } if(!n) { printf("沒有這個(gè)班級(jí)的學(xué)生信息!\n"); return ; } //打印該班級(jí)學(xué)生的各個(gè)成績的特征值; printf("\n該班共有學(xué)生 %d 人.\n\n",n); Print_Sco(); } //打印全校所以學(xué)生的信息 //具體情況同打印班級(jí)學(xué)生信息; void Que_All() { Sort(); n = C = M = E = Cj = Cy = Mj = My = Ej = Ey= 0; printf("\n"); if(head->next == NULL) { printf("--->沒有學(xué)生信息!\n"); return ; } puts("班級(jí) 學(xué)號(hào) 姓名 語文 數(shù)學(xué) 英語總成績"); for(u = head->next; u != NULL;u =u->next) { n++; printf("%-12s%-12s%-15s",u->classs,u->number,u->name); printf("%-6d%-6d%-6d%-d\n",u->score.chinese,u->score.math,u->score.english,u->score.sum); Analyze_Sco(u); } printf("\n全校共有學(xué)生 %d 人.\n\n",n); Print_Sco(); } //保存文件; void Save() { char c; printf("\n確認(rèn)保存?(Y/N): "); scanf("%*c%c",&c); if(c == 'N') return ; FILE *fp; if((fp=fopen("C:\\data.txt","w"))==NULL) { printf("\n--->無法打開文件\n"); return ; } //寫入數(shù)據(jù)表頭信息; fputs("班級(jí) 學(xué)號(hào) 姓名 語文 數(shù)學(xué) 英語總成績",fp); if(head->next != NULL) fputs("\n",fp); //從頭節(jié)點(diǎn)開始依次寫入文件; for(u = head->next; u != NULL;u = u->next) { fprintf(fp,"%-11s%-11s%-15s",u->classs,u->number,u->name); fprintf(fp,"%-6d%-6d%-6d%-d",u->score.chinese,u->score.math,u->score.english,u->score.sum); if(u->next != NULL) fprintf(fp,"\n"); } fclose(fp); printf("\n--->成績成功存入C:\\\\data.txt中\(zhòng)n"); } //讀取文件; void Open() { printf("\n請(qǐng)把數(shù)據(jù)放到目錄C:\\\\data.txt中,按任意鍵確認(rèn).\n"); getch(); FILE *fp; //從c盤根目錄下讀取文件; if((fp=fopen("C:\\data.txt","r"))==NULL) { printf("\n--->沒有找到文件!\n"); return ; } char tmp[100]; //讀取65個(gè)菜單頭字符存入tem字符數(shù)組中; fgets(tmp,66,fp); //讀到文件結(jié)尾處跳出循環(huán); while(!feof(fp)) { u = new_node(u); fscanf(fp,"%s%s%s",u->classs,u->number,u->name); fscanf(fp,"%d%d%d%d",&u->score.chinese,&u->score.math,&u->score.english,&u->score.sum); //頭插法建立鏈表; u->next = head->next; head->next = u; } printf("\n--->成績讀入成功!\n"); fclose(fp); } //退出程序 void Exi() { char c; printf("\n確定退出?(Y/N): "); scanf("%*c%c",&c); if(c == 'N') return ; //打印結(jié)束語; system("cls"); printf("\n\n"); printf("\t\t\t %c %c %c %c %c %c %c %c%c\n",4,4,4,4,4,4,4,4,4); printf("\t\t\t %c 謝謝使用%c\n",4,4); printf("\t\t\t %c %c %c %c %c %c %c %c%c\n",4,4,4,4,4,4,4,4,4); printf("\t\t\t Thankyou!\n\n\n"); exit(0); } int main() { //存儲(chǔ)指令的變量 int orz; //設(shè)置系統(tǒng)文本顏色 system("color 0B"); //新建一個(gè)學(xué)生信息頭節(jié)點(diǎn); head = new_node(head); while(1) { //顯示菜單、 Welcome(); //接收用戶命令、 scanf("%d",&orz); //調(diào)用系統(tǒng)函數(shù)清屏; system("cls"); switch(orz) { //根據(jù)指令進(jìn)入相應(yīng)菜單選項(xiàng) case 1:Open();break; case 2:Save();break; case 3:Add();break; case 4:Mod();break; case 5:Del();break; case 6:Que_One();break; case 7:Que_Cla();break; case 8:Que_All();break; case 9:Exi();break; default :printf("\n--->無效的指令!\n"); } printf("\n"); //執(zhí)行系統(tǒng)函數(shù) system("pause"); system("cls"); } return 0; }
新聞名稱:C語言的指針、鏈表的原理及學(xué)生管理系統(tǒng)
文章源于:http://jinyejixie.com/article0/jjigoo.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供品牌網(wǎng)站設(shè)計(jì)、電子商務(wù)、自適應(yīng)網(wǎng)站、做網(wǎng)站、虛擬主機(jī)、關(guān)鍵詞優(yōu)化
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)