《C語言程序設(shè)計(jì)項(xiàng)目化教程》課件第3章_第1頁
《C語言程序設(shè)計(jì)項(xiàng)目化教程》課件第3章_第2頁
《C語言程序設(shè)計(jì)項(xiàng)目化教程》課件第3章_第3頁
《C語言程序設(shè)計(jì)項(xiàng)目化教程》課件第3章_第4頁
《C語言程序設(shè)計(jì)項(xiàng)目化教程》課件第3章_第5頁
已閱讀5頁,還剩404頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

項(xiàng)目3學(xué)生成績管理系統(tǒng)的3.1問題情境3.2問題分析3.3項(xiàng)目設(shè)計(jì)與實(shí)施3.4知識拓展3.5應(yīng)用實(shí)踐

本項(xiàng)目要求通過指針和數(shù)組配合使用的方式,完成學(xué)生成績管理系統(tǒng)中的學(xué)生成績錄入、成績查詢、成績修改等操作。將各個操作功能設(shè)計(jì)成獨(dú)立的函數(shù),各函數(shù)間設(shè)計(jì)良好的接口參數(shù),通過數(shù)組存儲學(xué)生的學(xué)號和成績信息,通過指針實(shí)現(xiàn)對學(xué)生學(xué)號和成績信息的錄入、查找和修改等操作。3.1問題情境

項(xiàng)目2通過數(shù)組基本實(shí)現(xiàn)了學(xué)生成績管理系統(tǒng)的常用功能。但是,數(shù)組作為函數(shù)參數(shù)在函數(shù)調(diào)用、參數(shù)傳遞過程中顯得比較繁瑣,而且數(shù)組采用數(shù)組名和下標(biāo)的方式引用數(shù)據(jù)元素對于數(shù)據(jù)元素處理起來也顯得不便。有沒有更為簡便的實(shí)現(xiàn)方法呢?那就是采用指針類型。使用指針類型能夠更為簡便和高效地解決函數(shù)調(diào)用過程中地址的傳遞問題,通過指針還能方便地訪問數(shù)組中的元素。通常在C語言程序設(shè)計(jì)中,指針和數(shù)組配合使用是一種常用的方式。3.2問題分析

根據(jù)本項(xiàng)目的任務(wù)需求,在設(shè)計(jì)思路上,首先,通過自頂向下、逐步求精的結(jié)構(gòu)化設(shè)計(jì)思想對整個程序進(jìn)行功能模塊劃分;其次,根據(jù)各個功能模塊進(jìn)行函數(shù)接口的設(shè)計(jì)和函數(shù)調(diào)度關(guān)系的設(shè)計(jì);最后,在各個函數(shù)功能實(shí)現(xiàn)過程中應(yīng)注意:3.3項(xiàng)目設(shè)計(jì)與實(shí)施

(1)對用戶輸入的可能錯誤檢查是否嚴(yán)格?程序的容錯性如何。(如學(xué)號重復(fù)、成績不符合規(guī)定等。)

(2)如何實(shí)現(xiàn)插入(添加)、刪除、排序等的一般處理功能。

(3)如何實(shí)現(xiàn)多門課程的處理。

(4)如何保存輸入及修改結(jié)果。

(5)菜單如何組織。

【項(xiàng)目分析】

學(xué)生成績管理系統(tǒng)從功能上來講,包含學(xué)生成績的錄入、修改、查詢、輸出等一系列具體任務(wù),因此,本系統(tǒng)在設(shè)計(jì)思路上仍然按照模塊化程序設(shè)計(jì)的基本思想去完成各功能模塊的程序設(shè)計(jì),在數(shù)據(jù)處理上引入了指針,主要通過指針實(shí)現(xiàn)數(shù)據(jù)的傳遞與操作,完成系統(tǒng)各項(xiàng)功能的實(shí)現(xiàn)。

【項(xiàng)目實(shí)施】

程序?qū)崿F(xiàn)所需要的預(yù)處理命令及函數(shù)聲明語句如下:

#include<stdio.h>

#include<stdlib.h>

#include<conio.h> //控制臺相關(guān)函數(shù)定義

#include<windows.h>

#defineMAX_NUM45

voidinput(int*StudentID,int*StudentScore,intMax); //成績輸入

intfindStudentID(intStudentID[],intfindID,intMax); //查找指定學(xué)號的學(xué)生

voidDisplayScore(int*StudentID,int*StudentScore,intMax); //顯示所有記錄

voidDlspMainMenu(); //顯示主菜單

voidDlspQueryMenu(); //顯示查詢子菜單

charchoice(); //獲取用戶在菜單中的選擇

intScoreInput(int*ID,int*Score);

voidQueryScore(int*ID,int*Score,intMax);

voidEditScore(int*ID,int*Score,intMax);

功能模塊1:主菜單設(shè)計(jì)模塊

(1)模塊功能:主菜單操作界面程序設(shè)計(jì)。

(2)接口函數(shù):DispMainMenu()。

(3)程序代碼如下:

voidDispMainMenu()

{

printf("*************學(xué)生成績管理系統(tǒng)V1.0*************\n");

printf("*\t1--成績錄入2--成績修改*\n");

printf("*\t3--成績查詢0--退出*\n");

printf("***********************************************\n");

printf("請選擇(0--3):");/*顯示菜單信息*/

}

程序運(yùn)行結(jié)果如圖3-1所示。圖3-1主菜單顯示程序運(yùn)行結(jié)果功能模塊2:成績錄入模塊

(1)模塊功能:完成錄入學(xué)生學(xué)號及成績的C語言程序設(shè)計(jì)。

(2)接口函數(shù):ScoreInput(int*ID,int*Score),input(int*StudentID,int*StudentScore,intMax)。

(3)程序代碼如下:

voidinput(int*StudentID,int*StudentScore,intMax)

{

inti;

for(i=0;i<Max;i++)

{

printf("\n請輸入第%d個學(xué)生的學(xué)號:\t",i+1);

scanf("%d",StudentID+i);

printf("\t\t成績:\t");

scanf("%d",StudentScore+i);

}

printf("\n您的輸入信息是:\n");

DisplayScore(StudentID,StudentScore,Max);

}

intScoreInput(int*ID,int*Score)

{

intnumber;

printf("\n請輸入本次錄入的學(xué)生人數(shù):");

scanf("%d",&number);

if(number>MAX_NUM)

{

printf("您輸入的人數(shù)太多,大于%d人\n",MAX_NUM);

return(0);

}

input(ID,Score,number);//number是局部變量

return(number);

}圖3-2錄入學(xué)生成績的運(yùn)行圖功能模塊3:成績查詢模塊(查詢所有學(xué)生成績)

(1)模塊功能:顯示所有學(xué)生的成績信息。

(2)接口函數(shù):DispMainMenu(),voidDisplayScore(int*StudentID,int*StudentScore,intMax)。

(3)程序代碼如下:

//查詢菜單設(shè)計(jì)

voidDispQueryMenu()

{

printf("***************請選擇查詢方式*********************\n");

printf("*\tl--按學(xué)號查詢2--查詢?nèi)坑涗?\n");

printf("**************************************************\n");

printf("請選擇(1--2):");//顯示菜單信息

}

/*取用戶對菜單的選擇,返回用戶選擇的對應(yīng)字符鍵ASCII值*/

charchoice()

{

charselect;

while(!kbhit()); //kbhit()等待用戶輸入,非0有擊鍵,適用Microsoft平臺

select=getche(); //取用戶輸入,回顯,getch()則不回顯,適用Microsoft平臺

return(select);

}

/*顯示所有的學(xué)生成績信息*/

voidDisplayScore(int*StudentID,int*StudentScore,intMax)

{

inti;

printf("\n序號\t學(xué)號\t\t成績\n");

for(i=0;i<Max;i++)

printf("%d\t%d\t%d\n",i+1,*(StudentID+i),*(StudentScore+i));

printf("\n");

}

voidQueryScore(int*ID,int*Score,intMax)

{

charselect;

inti,

findID;

DispQueryMenu();

select=choice();

switch(select)

{

case'1':

printf("\n按學(xué)號查詢\n請輸入學(xué)生的學(xué)號:");

scanf("%d",&findID);

if((i=findStudentID(ID,findID,Max))!=-1)

{

printf("\n查找結(jié)果如下:\n");

printf("\t學(xué)號\t\t成績\n");

printf("\t%d\t%d\n",ID[i],Score[i]);

}else //沒有找到

printf("您輸入的學(xué)號不存在!\n");

break;

case'2':

printf("\n查詢?nèi)繉W(xué)生信息!\n");

DisplayScore(ID,Score,Max);

break;

default:

printf("選擇錯誤!\n");

}

}圖3-3所有學(xué)生成績查詢運(yùn)行結(jié)果功能模塊4:成績查詢模塊(按學(xué)號查詢學(xué)生成績)

(1)模塊功能:按照指定的學(xué)生學(xué)號查詢學(xué)生成績信息。

(2)接口函數(shù):intfindStudentID(int*StudentID,intfindID,intMax)。

(3)程序代碼如下:

intfindStudentID(int*StudentID,intfindID,intMax)

{

inti;

for(i=0;i<Max;i++)

if(*(StudentID+i)==findID)break;

if(i<Max)//找到i<Max,說明是執(zhí)行break后結(jié)束循環(huán),即找到指定的學(xué)生

returni;

elsereturn-1;

}圖3-4按學(xué)號查詢程序運(yùn)行結(jié)果功能模塊5:學(xué)生成績修改模塊

(1)模塊功能:按照輸入的學(xué)生學(xué)號,修改指定的學(xué)號所對應(yīng)的成績信息。

(2)接口函數(shù):voidEditScore(int*ID,int*Score,intMax)。

(3)程序代碼如下:

voidEditScore(int*ID,int*Score,intMax)

{

inti,findID; //findID--要查找的學(xué)生的學(xué)號

printf("\n請輸入學(xué)生的學(xué)號:");

scanf("%d",&findID);

if((i=findStudentID(ID,findID,Max))!=-1)

{

printf("原成績:%d\n",*(Score+i));

printf("請輸入新成績:");

scanf("%d",Score+i);

}

elseprintf("您輸入的學(xué)號不存在!\n"); //沒有找到

}

程序運(yùn)行結(jié)果如圖3-5所示。圖3-5修改成績程序運(yùn)行結(jié)果功能模塊6:主函數(shù)模塊

(1)模塊功能:實(shí)現(xiàn)系統(tǒng)變量的初始化和各個子函數(shù)程序模塊的調(diào)度。

(2)接口函數(shù):voidmain(intargc,char*argv[])。

(3)程序代碼如下:

voidmain(intargc,char*argv[])

{

charselect;

intID[MAX_NUM],

Score[MAX_NUM]; //保存學(xué)生學(xué)號及姓名的數(shù)組

intcurrent_number; //number指本程序當(dāng)前正在處理的學(xué)生人數(shù)

charcmdLine[]="winmine.exe";/*WINDOWS應(yīng)用程序名,并在系統(tǒng)的PATH

中能找到,否則要指定路徑,如C:\WINDOWS\System32\winmine.exe*/

select=0;

while(select!='0')

{

system("cls"); //執(zhí)行DOS系統(tǒng)命令,括號內(nèi)參數(shù)是系統(tǒng)命令名

DispMainMenu();

select=choice(); //取用戶輸入

switch(select)

{

case'0':

printf("\n您選擇的是退出測試!\n");//beep(300,400);

continue;

case'1':

printf("\n您選擇的是成績錄入!\n");

current_number=ScoreInput(ID,Score);

break;

case'2':

printf("\n您選擇的是成績修改!\n");

EditScore(ID,Score,current_number);

break;

case'3':

printf("\n您選擇的是成績查詢!\n");

QueryScore(ID,Score,current_number);

break;

default:

printf("\n選擇錯誤!請重新選擇!\n");//小于0,大于4

}

system("PAUSE");//用戶的輸入是<字符>+Enter,清除<Enter>

}

}

選擇“0—退出”,程序運(yùn)行結(jié)果如圖3-6所示。圖3-6退出程序運(yùn)行圖

【項(xiàng)目總結(jié)】

從項(xiàng)目3的程序設(shè)計(jì)可以看出,該項(xiàng)目程序設(shè)計(jì)時(shí)需注意以下幾點(diǎn):

(1)本系統(tǒng)使用模塊化程序設(shè)計(jì)思想。

(2)各個模塊的功能設(shè)計(jì)雖然相互獨(dú)立,但應(yīng)注意各個模塊相互之間的銜接關(guān)系。

(3)指針的概念及在程序設(shè)計(jì)中的靈活應(yīng)用是本系統(tǒng)完成的關(guān)鍵。

【知識總結(jié)】

完成項(xiàng)目3需用到的C語言主要知識點(diǎn)有:

(1)自定義函數(shù)及其調(diào)用規(guī)則。

(2)模塊化程序設(shè)計(jì)的基本思想。

(3)結(jié)構(gòu)體數(shù)據(jù)類型的定義及結(jié)構(gòu)體變量的使用。

(4)分支結(jié)構(gòu)與循環(huán)結(jié)構(gòu)程序設(shè)計(jì)。

(5)指針的概念及基本用法。

本項(xiàng)目相關(guān)知識總結(jié)如下。3.3.1指針的概念

1.指針和指針變量的概念

1)指針的基本概念

計(jì)算機(jī)中的所有數(shù)據(jù)都是順序存放在存儲器中的。一般把存儲器中的一個字節(jié)稱為一個內(nèi)存單元(亦稱存儲單元),不同數(shù)據(jù)類型的值所占用的內(nèi)存單元數(shù)亦不同。為了正確地訪問這些內(nèi)存單元,必須為每個內(nèi)存單元編上號。根據(jù)一個內(nèi)存單元的編號即可準(zhǔn)確地找到該內(nèi)存單元。內(nèi)存單元的編號也叫做地址,通常把這個地址稱為指針。內(nèi)存單元的指針和內(nèi)存單元的內(nèi)容是兩個不同的概念??梢杂靡粋€通俗的例子來說明它們之間的關(guān)系。我們到銀行去存(或取)款時(shí),銀行工作人員將根據(jù)我們的帳號去查找存款單,找到之后在存單上寫入存(或取)款的金額。在這里,帳號就是存單的指針,存款數(shù)是存單的內(nèi)容。

2)指針變量的基本概念

對于一個內(nèi)存單元來說,單元的地址即為指針,其中存放的數(shù)據(jù)是該單元的內(nèi)容。在C語言中,允許用一個變量來存放指針,這種變量稱為指針變量。因此,一個指針變量的值就是某個內(nèi)存單元的地址,或稱為指向某內(nèi)存單元的指針。圖3-7指向變量C的指針變量P如圖3-7所示,設(shè)有字符變量C,其內(nèi)容為字符‘K’(ASCII碼為十進(jìn)制數(shù)75),C占用了0110H號存儲單元(地址用十六進(jìn)制表示)。設(shè)有指針變量P,內(nèi)容為0110H。這種情況下,我們稱為“P指向變量C”或者“P是指向變量C的指針”。

嚴(yán)格地說,一個指針是一個地址,是一個常量,而一個指針變量卻可以被賦予不同的指針值,是變量。但通常把指針變量簡稱為“指針”。為了避免混淆,我們約定:“指針”是指地址,是常量;“指針變量”是指取值為地址的變量。定義指針的目的是為了通過指針去訪問內(nèi)存單元。

既然指針變量的值是一個地址,那么這個地址不僅可以是變量的地址,也可以是其他數(shù)據(jù)結(jié)構(gòu)。在一個指針變量中存放一個數(shù)組或一個函數(shù)的首地址有何意義呢?因?yàn)閿?shù)組或函數(shù)在內(nèi)存中都是連續(xù)存放的,通過訪問指針變量取得了數(shù)組或函數(shù)的首地址,也就找到了該數(shù)組或函數(shù)。這樣一來,凡是出現(xiàn)數(shù)組、函數(shù)的地方都可以用一個指針變量來表示,只要該指針變量中賦予數(shù)組或函數(shù)的首地址即可。這樣做,將會使程序的概念十分清楚,程序本身也精練、高效。在C語言中,一種數(shù)據(jù)類型或數(shù)據(jù)結(jié)構(gòu)往往都占有一組連續(xù)的內(nèi)存單元。用“地址”這個概念并不能很好地描述一種數(shù)據(jù)類型或數(shù)據(jù)結(jié)構(gòu),而“指針”雖然實(shí)際上也是一個地址,但它卻是一個數(shù)據(jù)結(jié)構(gòu)的首地址,它是“指向”一個數(shù)據(jù)結(jié)構(gòu)的,因而概念更為清楚,表示更為明確。這也是引入“指針”概念的一個重要原因。

2.指針變量的定義與應(yīng)用

1)指針變量的定義

指針變量定義的一般形式為

類型說明符*指針變量名;

其中:*為說明符,表示這是一個指針變量;指針變量名為用戶自定義標(biāo)識符;類型說明符表示該指針變量所指向的變量的數(shù)據(jù)類型。例如:

int*p1;該定義表示p1是一個指針變量,它的值是某個整型變量的地址,或者說p1指向一個整型變量。至于p1究竟指向哪一個整型變量,應(yīng)由向p1賦予的地址來決定。

例如:

staicint*p1; /*p1是指向靜態(tài)整型變量的指針變量*/

float*p2; /*p2是指向浮點(diǎn)變量的指針變量*/

char*p3; /*p3是指向字符變量的指針變量*/

應(yīng)該注意的是,一個指針變量只能指向同類型的變量,如p2只能指向浮點(diǎn)變量,不能時(shí)而指向一個浮點(diǎn)變量,時(shí)而又指向一個字符變量。

2)指針變量的賦值

指針變量同普通變量一樣,使用之前不僅要定義說明,而且必須賦予具體的值。未經(jīng)賦值的指針變量不能使用,否則將造成系統(tǒng)混亂,甚至死機(jī)。同時(shí),指針變量的賦值只能賦予地址,決不能賦予任何其他數(shù)據(jù),否則將引起錯誤。

在C語言中,所有初始變量的地址都是由編譯系統(tǒng)自動和隨機(jī)分配的,對用戶完全透明,用戶不知道變量的具體地址。

C語言中提供了取地址運(yùn)算符&來表示變量的地址,其一般形式為

&變量名

如&a變示變量a的地址,&b表示變量b的地址。變量本身必須預(yù)先說明或定義。

設(shè)有指向整型變量的指針變量p,如要把變量a的地址賦予p,可以有以下兩種實(shí)現(xiàn)

方法:

(1)指針變量初始化的方法。即在初始定義指針變量的同時(shí)賦予其初值,如:

inta;

int*p=&a;

(2)賦值語句的方法。即在指針變量定義后,利用賦值語句形式完成對指針變量的賦值操作,如:

inta;

int*p;

p=&a;

不允許把一個數(shù)值直接賦予指針變量,如下面的賦值是錯誤的:

int*p;

p=1000;

被賦值的指針變量前不能再加“*”說明符。如寫為

*p=&a也是錯誤的。

3)指針變量的運(yùn)算

指針變量可以進(jìn)行某些運(yùn)算,但其運(yùn)算的種類是有限的,它只能進(jìn)行賦值運(yùn)算和部分算術(shù)及關(guān)系運(yùn)算。

(1)取地址運(yùn)算符“&”。

取地址運(yùn)算符“&”是單目運(yùn)算符,其結(jié)合性為自右至左,其功能是取變量的地址。在scanf()函數(shù)及前面介紹指針變量賦值中,我們已經(jīng)了解并使用了“&”運(yùn)算符。

(2)取內(nèi)容運(yùn)算符“*”。

取內(nèi)容運(yùn)算符“*”是單目運(yùn)算符,其結(jié)合性為自右至左,用來表示指針變量所指的變量。在“*”運(yùn)算符之后必須跟指針變量。

需要注意的是,指針運(yùn)算符“*”和指針變量說明中的指針說明符“*”不是一回事。在指針變量說明中,“*”是類型說明符,表示其后的變量是指針類型;而表達(dá)式中出現(xiàn)的“*”則是一個運(yùn)算符,用以表示指針變量所指的變量。

【例3.1】指針運(yùn)算符*和&的使用。

程序如下:

/*程序功能:通過指針變量的定義、賦值及簡單應(yīng)用說明指針運(yùn)算符*和&的使用*/

#include<stdio.h>

voidmain()

{inta=5,*p; /*定義整型變量a和指針變量p*/

p=&a; /*利用&取得變量a的地址并給指針變量p賦值*/

printf("%d\n",*p); /*利用*取得指針變量所指向變量的內(nèi)容*/

}

程序運(yùn)行結(jié)果如下:

5

程序說明:在定義了指針變量p后,利用指針變量p取得整型變量a的地址,并在最后輸出中,利用指針變量取得變量a的值進(jìn)行輸出。

賦值運(yùn)算:指針變量的賦值運(yùn)算有以下幾種形式:

①指針變量初始化賦值。例如:

inta=5,*p1=&a;②把一個變量的地址賦予指向相同數(shù)據(jù)類型的指針變量。例如:

inta,*pa;

pa=&a;/*把整型變量a的地址賦予整型指針變量pa*/

③把一個指針變量的值賦予指向相同類型變量的另一個指針變量。例如:

inta,*pa=&a,*pb;

pb=pa;/*把指針變量pa實(shí)際存儲的地址賦予指針變量pb*/由于pa、pb均為指向整型變量的指針變量,因此可以相互賦值,并且賦值后,指針變量pa、pb均指向整形變量a。

④利用指針形式引用其所指變量。例如:

intn1=0,n2,*p=&n2,*q=&n1;

*p=*q;/*等價(jià)于n2=n1;*/

⑤把數(shù)組的首地址賦予指向數(shù)組的指針變量。例如:

inta[5],*pa;

pa=a;/*數(shù)組名表示數(shù)組的首地址,故可直接賦予指向數(shù)組的指針變量pa*/也可寫為

pa=&a[0];/*數(shù)組第一個元素的地址也是整個數(shù)組的首地址,也可賦予pa*/

當(dāng)然也可采取初始化賦值的方法:

inta[5],*pa=a;

⑥把字符串的首地址賦予指向字符類型的指針變量。例如:

char*pStr;

pStr="cLanguage";或用初始化賦值的方法寫為

char*pc="CLanguage";

這里需要說明的是,指針指向字符串,并不是把整個字符串裝入指針變量,而是把存放該字符串的字符數(shù)組的首地址裝入指針變量。在后面還將詳細(xì)介紹。

⑦把函數(shù)的入口地址賦予指向函數(shù)的指針變量。例如:

int(*pf)();

pf=f;/*其中f為函數(shù)名*/

加減算術(shù)運(yùn)算:對于指向數(shù)組的指針變量,可以進(jìn)行整數(shù)類型的加減法運(yùn)算。設(shè)pa是指向數(shù)組a的指針變量,則pa+n、pa-n、pa++、++pa、pa--、--pa運(yùn)算都是合法的。當(dāng)然,參與加減算術(shù)運(yùn)算的變量n只能為整型。

指針變量加或減一個整數(shù)n的意義是把指針指向的當(dāng)前位置(指向某個數(shù)組元素)向前或向后移動n個位置。應(yīng)當(dāng)注意,數(shù)組指針變量向前或向后移動一個位置和地址值加1或減1在概念上是完全不同的。如果指針變量加1,表示指針變量移動1個位置指向下一個數(shù)據(jù)元素的地址,而不是在原地址值的基礎(chǔ)上真實(shí)地加整型數(shù)值1。例如:

inta[5],*pa;

pa=a; /*pa指向數(shù)組a,也是指向數(shù)組元素a[0]*/

pa=pa+2; /*pa指向數(shù)組元素a[2],即pa的值為&pa[2]*/指針變量的加減運(yùn)算只適用于指向數(shù)組的指針變量,對指向其他類型變量的指針變量作加減運(yùn)算是毫無意義的,并容易導(dǎo)致災(zāi)難性的后果。

兩個指針變量之間的運(yùn)算:只有指向同一數(shù)組的兩個指針變量之間才能進(jìn)行運(yùn)算,否則運(yùn)算也毫無意義。

①兩個指針變量相減。兩個指針變量相減所得之差是兩個指針?biāo)笖?shù)組元素之間相差的元素個數(shù)。

例如,pf1和pf2是指向同一浮點(diǎn)數(shù)組的兩個指針變量,設(shè)pf1的值為2010H,pf2的值為2000H。由于浮點(diǎn)數(shù)組每個元素各占用4個字節(jié),所以pf1-pf2的結(jié)果為(2010H-2000H)/4=4,表示pf1和pf2所指數(shù)組元素之間相差4個元素。兩個指針變量不能進(jìn)行加法運(yùn)算。例如,pf1+pf2就毫無實(shí)際意義。

②兩個指針變量進(jìn)行關(guān)系運(yùn)算。指向同一數(shù)組的兩個指針變量進(jìn)行關(guān)系運(yùn)算可表示它們所指數(shù)組元素之間的關(guān)系。例如:

pf1==pf2表示pf1和pf2指向同一數(shù)組元素

pf1>pf2表示pf1處于高地址位置

pf1<pf2表示pf2處于高地址位置

指針變量還可以與0比較。設(shè)p為指針變量,則p==0表明p是空指針,它不指向任何變量;p!=0表示p不是空指針。空指針是由對指針變量賦予0值而得到的。例如:

#defineNULL0

int*p=NULL;

對指針變量賦0值和不賦值是不同的。指針變量未賦值時(shí),其初始化結(jié)果可能是任意值,是不能使用的,否則將造成意外錯誤。而指針變量賦0值后,則可以使用,只是它不指向具體的變量而已。

4)指針變量應(yīng)用示例

以下C程序示例用以增強(qiáng)對本節(jié)內(nèi)容的理解及鞏固。通讀這些程序,并編譯運(yùn)行它們,以掌握指針變量的基礎(chǔ)應(yīng)用。

【例3.2】指針變量的應(yīng)用。

/*程序功能:熟悉指針變量的基礎(chǔ)應(yīng)用*/

#include<stdio.h>

voidmain()

{

intnNumber; /*定義普通整型變量*/

int*pPointer; /*定義指向整型變量的指針變量pPointer*/

nNumber=15;

pPointer=&nNumber; /*給指針變量賦值*/

printf("nNumberisequalto:%d\n",nNumber); /*輸出變量nNumber的值*/

*pPointer=25; /*通過指針改變nNumber的值*/

printf("Now,nNumberisequalto:%d",nNumber);/*證明nNumber值已被改變*/

}程序運(yùn)行結(jié)果如下:

nNumberisequalto:15

Now,nNumberisequalto:25

【例3.3】指針變量的應(yīng)用。

/*程序功能:熟悉指針變量的基礎(chǔ)應(yīng)用*/

#include<stdio.h>

voidmain()

{

inta=10,b=20,s,t,*pa,*pb;

pa=&a;pb=&b;

s=*pa+*pb;/*對于指針變量所指內(nèi)容的引用*/

t=*pa**pb; /*指針運(yùn)算符優(yōu)先級高于算術(shù)運(yùn)算符*/

printf("a=%d\nb=%d\na+b=%d\na*b=%d\n",a,b,a+b,a*b);

printf("s=%d\nt=%d\n",s,t);/*兩種算式運(yùn)算結(jié)果相同*/

}程序運(yùn)行結(jié)果如下:

a=10

b=20

a+b=30

a*b=200

s=30

t=200

【例3.4】輸出三個任意輸入整型數(shù)值的最大數(shù)和最小數(shù)。

/*程序功能:輸出三個任意輸入整型數(shù)值的最大數(shù)和最小數(shù)*/

#include<stdio.h>

voidmain()

{

inta,b,c,*pmax,*pmin;

printf("inputthreeintnumbers:");

scanf("%d%d%d",&a,&b,&c); /*任意輸入三個整型數(shù)值*/

if(a>b)

{pmax=&a;pmin=&b;} /*比較a和b*/

else

{pmax=&b;pmin=&a;}

if(c>*pmax)pmax=&c; /*比較c和a、b的最大值*/

if(c<*pmin)pmin=&c; /*比較c和a、b的最小值*/

printf("max=%d\nmin=%d\n",*pmax,*pmin);

}程序運(yùn)行結(jié)果如下:

inputthreeintnumbers:234567↙

max=67

min=233.3.2指針變量作函數(shù)參數(shù)

在函數(shù)應(yīng)用中,函數(shù)的參數(shù)不僅可以是整型、實(shí)型、字符型、數(shù)組等數(shù)據(jù),也可以是指針類型,以實(shí)現(xiàn)將地址傳送到另一函數(shù)中參與操作

【例3.5】指針的應(yīng)用。

/*程序功能:利用AddFive()函數(shù)實(shí)現(xiàn)對所傳遞變量加5的操作*/

#include"stdio.h"

AddFive(intN) /*定義函數(shù)AddFive()*/

{N=N+5;

}

main()

{intv=20;

printf("Myoriginalvalueis%d\n",v);

AddFive(v); /*調(diào)用函數(shù)AddFive()實(shí)現(xiàn)對變量v加5的操作*/

printf("Mynewvalueis%d",v);

}程序運(yùn)行結(jié)果如下:

Myoriginalvalueis20

Mynewvalueis20

在這里應(yīng)說明的是,本例并沒有得到預(yù)想的結(jié)果25。問題出在哪兒?其實(shí)本例程描述了一個函數(shù)調(diào)用中的“值傳遞”,因此,AddFive()函數(shù)中“N=N+5”這一行雖改變了N值,但原始的變量v在主函數(shù)main()里依然沒變,所以,程序輸出顯示主函數(shù)中的變量v的實(shí)際值前后并沒有發(fā)生變化。如果要實(shí)現(xiàn)正確的程序功能,可以通過傳遞指針到函數(shù)來達(dá)到目的。下面就是修改過的程序,在AddFive()函數(shù)形參說明要加*號,函數(shù)調(diào)用時(shí)要用&號,以表示傳遞的是指針。

#include"stdio.h"

AddFive(int*N) /*定義函數(shù)AddFive()*/

{*N=*N+5; /*實(shí)現(xiàn)對指針?biāo)傅淖兞考?*/

}

main()

{intv=20;

printf("Myoriginalvalueis%d\n",v);

AddFive(&v); /*注意變量前加&,表示傳遞的是變量v的指針*/

printf("Mynewvalueis%d",v);

}

程序運(yùn)行結(jié)果如下:

Myoriginalvalueis20

Mynewvalueis25

注意:本例程序是把指針?biāo)傅淖兞考?,而并不是指針自己加5。

【例3.6】指針變量作函數(shù)參數(shù)參與應(yīng)用。

/*程序功能:指針變量作為函數(shù)的參數(shù)參與傳遞*/

#include<stdio.h>

outval(int*p1,float*p2) /*函數(shù)形參為指針類型*/

{printf("Theintvalueis%d\n",*p1);

printf("Thefloatvalueis%f\n",*p2);

}

voidmain()

{inta=5,*p_int;

floatb=4.5,*p_float;

p_int=&a;

p_float=&b;

outval(p_int,p_float); /*實(shí)參傳遞的是指針類型的值*/

}

程序運(yùn)行結(jié)果如下:

Theintvalueis5

Thefloatvalueis4.500000說明:

(1)本例利用指針變量p_int和p_float作為實(shí)參對函數(shù)outval()進(jìn)行調(diào)用。

(2)在函數(shù)outval()的定義中,必須使用相同類型、相同個數(shù)的形式參數(shù)和實(shí)際參數(shù)相對應(yīng)。

(3)在函數(shù)outval()調(diào)用開始時(shí),實(shí)參變量p_int和p_float利用“值傳遞”的方式將它們的值(分別指向變量a和b的地址)傳送給形參變量p1和p2。

(4)在函數(shù)outval()調(diào)用開始后,可利用形參變量p1和p2所指向的變量內(nèi)容參與各種運(yùn)算。本例中只是對其指向的內(nèi)容進(jìn)行輸出顯示。

(5)在函數(shù)outval()調(diào)用結(jié)束后,形參變量p1和p2將被釋放,實(shí)參變量p_int和p_float保留原指向。

(6)如果在函數(shù)outval()中,利用指針對變量a和b的值進(jìn)行了變化,函數(shù)調(diào)用結(jié)束后該變化將會影響至主函數(shù)。

【例3.7】指針變量作函數(shù)參數(shù)參與應(yīng)用。

/*程序功能:指針變量作為函數(shù)參數(shù)參與傳遞,并對主函數(shù)的變量值產(chǎn)生影響*/

#include<stdio.h>

outval(int*p1,float*p2) /*函數(shù)形參為指針類型*/

{*p1=*p1*10;

*p2=*p2*10; /*對指針?biāo)缸兞窟M(jìn)行運(yùn)算變化*/

}

voidmain()

{inta=5,*p_int;

floatb=4.5,*p_float;

p_int=&a;

p_float=&b;

printf("The1thoutput__beforeuseoutval()function\n");

printf("Theintvalueis%d\n",*p_int);

printf("Thefloatvalueis%f\n",*p_float);

outval(p_int,p_float);

printf("The2thoutput__afteruseoutval()function\n");

printf("Theintvalueis%d\n",*p_int);

printf("Thefloatvalueis%f\n",*p_float);

}程序運(yùn)行結(jié)果如下:

The1thoutput__beforeuseoutval()function

Theintvalueis5

Thefloatvalueis4.500000

The2thoutput__afteruseoutval()function

Theintvalueis50

Thefloatvalueis45.000000

可見,當(dāng)利用指針變量作為實(shí)參對函數(shù)進(jìn)行調(diào)用的過程中,如果函數(shù)對指針?biāo)缸兞康闹颠M(jìn)行了變化,函數(shù)運(yùn)行結(jié)束后,該變化將會影響主函數(shù)中實(shí)參的值。3.3.3指針與數(shù)組

1.概述

指針和數(shù)組有著密切的關(guān)系,任何能由數(shù)組下標(biāo)完成的操作也都可用指針來實(shí)現(xiàn),但程序中使用指針可使編程代碼更緊湊、更靈活。

一個數(shù)組是由連續(xù)的一塊內(nèi)存單元組成的,數(shù)組名就是這塊連續(xù)內(nèi)存單元的首地址。一個數(shù)組也是由各個數(shù)組元素(下標(biāo)變量)組成的,每個數(shù)組元素按數(shù)據(jù)類型的不同占有幾個連續(xù)的內(nèi)存單元。一個指針變量既可以指向一個數(shù)組,也可以指向一個數(shù)組元素。如果要使一個指針變量指向一個數(shù)組,可把數(shù)組名或數(shù)組第一個元素的地址賦予它;如果要使指針變量指向某個數(shù)組的第n個元素,可以把該數(shù)組第n個元素的地址賦予它或把數(shù)組名加n賦予它。例如

charstr[80],*pl;

pl=str;這里,將數(shù)組名str賦予指針變量pl。在C程序中,不帶下標(biāo)的數(shù)組名為數(shù)組的起始地址。因此,數(shù)組名也是指向數(shù)組的指針。

語句“pl=str;”還可以這樣表示為pl=&str[0];,即把數(shù)組str的第一個元素的地址賦予指針變量pl。如果希望訪問str中的第5個元素,可以這樣寫:

str[4]

或*(pl+4)兩種表示形式都將返回第5個元素的值。因?yàn)閿?shù)組下標(biāo)是從0開始的,所以要訪問數(shù)組的第5個元素,str的下標(biāo)應(yīng)為4。還可以將指針pl加4,以存取第5個元素。例如:

#include<stdio.h>

voidmain()

{inta[10]={1,2,3,4,5,6,7,8,9,10},*p=&a[3],*q=p+2;

/*指針變量p指向a[3],指針變量q指向a[5]*/

printf("%d,%d\n",*p,*q);

}程序運(yùn)行結(jié)果如下:

4,6

2.通過指針引用數(shù)組元素

數(shù)組指針變量說明的一般形式為

類型說明符*指針變量名;

其中,類型說明符表示該指針?biāo)笖?shù)組的類型。從一般形式可以看出,指向數(shù)組的指針變量和指向普通變量的指針變量的說明是相同的。

設(shè)有數(shù)組a,指向a的同類型指針變量為pa,則通過對指針概念的理解就存在以下關(guān)系:

pa、a、&a[0]均指向同一單元。它們都是數(shù)組a的首地址,也是數(shù)組元素a[0]的地址。

pa+1、a+1、&a[1]均指向數(shù)組元素a[1]。類似可知pa+i、a+i、&a[i]指向數(shù)組元素a[i]。

應(yīng)該說明的是,指針pa是變量,而a、&a[i]都是常量(程序運(yùn)行中,數(shù)組所分配的內(nèi)存單元地址固定不變),在編程時(shí)應(yīng)予以注意。

引入指針變量后,就可以使用兩種方法來訪問數(shù)組元素了。

1)下標(biāo)法

下標(biāo)法是用a[i]或*(a+i)形式訪問數(shù)組元素,在前面介紹數(shù)組時(shí)都是采用這種方法。

例如:

#include<stdio.h>

voidmain()

{

inta[5],i;

for(i=0;i<5;i++)

{

a[i]=i; /*給數(shù)組元素賦值*/

printf("a[%d]=%d\n",i,*(a+i)); /*輸出數(shù)組元素*/

}

printf("\n");

}

程序運(yùn)行結(jié)果如下:

a[0]=0

a[1]=1

a[2]=2

a[3]=3

a[4]=4

2)指針法

指針法是采用

*(pa+i)或pa[i]形式,用間接訪問的方法來訪問數(shù)組元素。

【例3.8】指針變量訪問數(shù)組元素。

/*程序功能:利用指針變量訪問數(shù)組各個元素,并輸出所有數(shù)組元素值*/

#include<stdio.h>

voidmain()

{

inta[5],i,*pa;

pa=a; /*指針變量指向數(shù)組a首地址*/

for(i=0;i<5;i++)

{*pa=i+1; /*給數(shù)組元素賦值*/

pa++; /*指針指向下一個元素*/

}

pa=a; /*重新使pa指向數(shù)組a首地址*/

for(i=0;i<5;i++)

{printf("a[%d]=%d\n",i,*(pa+i)); /*順序輸出各數(shù)組元素的值*/

}

}說明:

(1)程序中有兩個語句pa=a;。因?yàn)樵谥骱瘮?shù)中,當(dāng)?shù)谝粋€循環(huán)結(jié)束后,指針pa已指向a[5],而后面需要重新對數(shù)組a進(jìn)行引用,所以須重新使指針變量指向數(shù)組首地址。

(2)在實(shí)現(xiàn)數(shù)組內(nèi)容輸出時(shí),也可采用下面的實(shí)現(xiàn)方法:

for(i=0;i<5;i++)

{

printf("a[%d]=%d\n",i,*pa);

pa++;

}

甚至,整個程序更可簡寫為例3.9所示。

【例3.9】指針變量訪問數(shù)組元素。

/*程序功能:利用指針變量訪問數(shù)組各個元素,并對內(nèi)容進(jìn)行輸出*/

#include<stdio.h>

voidmain()

{

inta[5],i,*pa=a;

for(i=0;i<5;)

{*pa=i;

printf("a[%d]=%d\n",i++,*pa++);/*注意++運(yùn)算符的合理使用*/

}

}

程序運(yùn)行情況同例3.8。

使用下標(biāo)法的程序執(zhí)行速度比使用指針法的慢。原因是利用下標(biāo)操作數(shù)組元素所使用的時(shí)間比使用指針操作數(shù)組元素所花費(fèi)的時(shí)間長。尤其在順序訪問數(shù)組的過程中,使用指針來引用數(shù)組元素的程序段效率會更高。但如果是隨機(jī)訪問數(shù)組,則采用下標(biāo)法引用更好,因?yàn)樗ǔJ桥c計(jì)算一個復(fù)雜的指針表達(dá)式一樣快,而且易于編碼和理解。

下面程序段是較為典型的數(shù)組元素運(yùn)算操作,分析程序段的輸出結(jié)果是什么?

#include<stdio.h>

voidmain()

{

inta[]={2,4,6,8,10},y=0,x,*p;

p=&a[1]; /*注意:指針p指向數(shù)組第二個元素*/

for(x=1;x<3;x++) /*循環(huán)段*/

y+=p[x]; /*累計(jì)求和:p[x]等價(jià)于*(p+x)*/

printf("%d\n",y);

}綜上所述,若有定義“inta[10],*pa=a;”,則利用指針給出數(shù)組元素地址和內(nèi)容的表示形式主要包括:

(1)

pa+i和a+i均表示a[i]的地址,它們均指向數(shù)組a的第i個元素,即指向a[i]。

(2)

*(pa+i)和*(a+i)都表示pa+i和a+i所指對象的內(nèi)容,即為a[i]。

(3)指向數(shù)組元素的指針,也可以表示成數(shù)組的形式。如pa[i]與*(pa+i)等價(jià),a[i]與*(a+i)等價(jià)。也就是說,它允許指針變量帶下標(biāo)。假若pa=a+5;,則pa[2]就相當(dāng)于

*(pa+2),由于pa指向a[5],所以pa[2]就相當(dāng)于a[7]。而pa[-3]就相當(dāng)于*(pa-3),它表示a[2]。

3.指向數(shù)組的指針變量作函數(shù)參數(shù)

前面已經(jīng)介紹了利用指針變量引用數(shù)組元素,下面介紹指向數(shù)組的指針變量作為函數(shù)參數(shù)的使用,具體如下例所示。

【例3.10】鍵盤輸入5門功課成績,自定義函數(shù)完成平均分的計(jì)算。

/*程序功能:指向數(shù)組的指針變量作為函數(shù)參數(shù)的使用*/

#include<stdio.h>

floataver(float*pa)

{

inti;

floatave,s=0;

for(i=0;i<5;i++)

s=s+*pa++; /*利用指針引用數(shù)組元素,求和*/

ave=s/5;

returnave; /*返回平均值*/

}

voidmain()

{

floatscore[5],ave,*sp;

inti;

sp=score; /*指針指向數(shù)組score的首地址*/

printf("\input5scores:\n");

for(i=0;i<5;i++)

scanf("%f",&score[i]);

ave=aver(sp); /*將數(shù)組首地址傳遞到函數(shù)aver()*/

printf("averagescoreis%5.2f",ave);

}程序運(yùn)行結(jié)果如下:

input5scores:

8687969776↙

averagescoreis88.40

說明:

(1)例3.10主函數(shù)中,指針sp指向數(shù)組score的首地址,并在調(diào)用函數(shù)aver()時(shí),對指向數(shù)組的指針變量sp進(jìn)行了引用,表示傳遞給函數(shù)aver()的是一個地址值。自定義函數(shù)aver()形參說明也是一個指針類型的變量,以接收主函數(shù)傳遞過來的指針值。在程序設(shè)計(jì)中,為了保證函數(shù)的正確調(diào)用,應(yīng)保證形參、實(shí)參數(shù)據(jù)類型的一致性。在這里,實(shí)參、形參都是指向符點(diǎn)類型的指針變量。

(2)函數(shù)aver()中,由于利用指針變量pa接收了sp所指地址值,且sp指向主函數(shù)數(shù)組score的首地址,所以,指針變量pa也指向主函數(shù)數(shù)組score的首地址。

(3)程序行“s=s+*pa++;”中,由于運(yùn)算符

*

++

運(yùn)算符優(yōu)先級高,所以就等同于“s=s+*pa;pa++;”,即先引用指針pa所指對象求和,而后使指針pa指向下一個元素。

下面程序段將在自定義函數(shù)sum()中,利用指針變量接收主函數(shù)傳遞過來的一個數(shù)組元素的地址,并利用指針對數(shù)組元素進(jìn)行相關(guān)操作。

#include<stdio.h>

sum(int*p)

{p[0]=p[-1]+p[1]; /*利用指針形式引用數(shù)組元素并進(jìn)行操作*/

}

voidmain()

{

inta[10]={1,2,3,4,5,6,7,8,9,10};

sum(&a[2]); /*調(diào)用函數(shù)sum()*/

printf("%d",a[2]);

}程序運(yùn)行結(jié)果如下:

6

說明:主函數(shù)調(diào)用sum()函數(shù)時(shí),傳遞的實(shí)參為a[2]的地址,所以,在函數(shù)sum()中,指針變量p指向數(shù)組元素a[2]。函數(shù)sum()中的語句“p[0]=p[-1]+p[1];”是以指針變量引用數(shù)組元素,該語句等同于語句“*p=*(p-1)+*(p+1);”或“a[2]=a[1]+a[3];”,其結(jié)果對數(shù)組元素a[2]的值產(chǎn)生了影響。

“值傳遞”與“地址傳遞”有何區(qū)別呢?如下例所示。

#include<stdio.h>

swap1(intc0[],intc1[]) /*數(shù)組名形參*/

{intt;

t=c0[0];c0[0]=c1[0];c1[0]=t; /*交換結(jié)果影響到主函數(shù)*/

}

swap2(int*c0,int*c1) /*指針形參*/

{intt;

t=*c0;*c0=*c1;*c1=t; /*交換結(jié)果影響到主函數(shù)*/

}

swap3(intc0,intc1) /*普通變量形參*/

{intt;

t=c0;c0=c1;c1=t; /*交換結(jié)果不影響到主函數(shù)*/

}

voidmain()

{inta[2]={3,5},b[2]={3,5},c[2]={3,5};

swap1(a,a+1); /*以數(shù)組名形式傳遞地址*/

swap2(&b[0],&b[1]); /*利用&運(yùn)算符取址傳遞*/

swap3(c[0],c[1]); /*數(shù)組元素值傳遞*/

printf("%d%d\n%d%d\n%d%d",a[0],a[1],b[0],b[1],c[0],c[1]);

}

程序運(yùn)行結(jié)果如下:

53

53

35說明:函數(shù)swap1()、swap2()都是“地址傳遞”,利用指針接收主函數(shù)傳遞過來的數(shù)組元素地址(注意函數(shù)形參類型說明,以及函數(shù)調(diào)用時(shí)傳遞的地址形式),所以,在函數(shù)內(nèi)部進(jìn)行所指向數(shù)組元素值的交換后,其結(jié)果對主函數(shù)產(chǎn)生了影響。而swap3()函數(shù)是“值傳遞”,在主函數(shù)調(diào)用開始后,變量c0和c1分別取得主函數(shù)c[0]和c[1]的值,雖然swap3()函數(shù)對c0和c1的值進(jìn)行了交換,但函數(shù)運(yùn)行結(jié)束后,由于變量c0、c1、t會被釋放,其交換并未對主函數(shù)數(shù)組c的兩個元素產(chǎn)生影響。另外,不能企圖通過改變指針形參的地址值,而使指針實(shí)參的值也改變。例如:

#include<stdio.h>

swap(int*p1,int*p2)

{int*p;

p=p1;p1=p2;p2=p;

}

voidmain()

{inta,b;

scanf("%d,%d",&a,&b);

swap(&a,&b);

printf("%d%d\n",a,b);

}

程序運(yùn)行結(jié)果如下:

10,20↙

1020/*swap()函數(shù)交換結(jié)果不影響a和b的值*/

3.4.1宏定義

在C語言源程序中,允許用一個標(biāo)識符來表示一個字符串,稱為“宏”。被定義為“宏”的標(biāo)識符稱為“宏名”。在編譯預(yù)處理時(shí),對程序中所有出現(xiàn)的“宏名”,都用宏定義中的字符串去代換,這稱為“宏代換”或“宏展開”。宏定義是由源程序中的宏定義命令完成的。宏代換是由預(yù)處理程序自動完成的。3.4知識拓展宏提供了一種詞法符號替換機(jī)制,它們可以帶也可以不帶類似函數(shù)中的形式參數(shù)。所以,宏定義也分為無參宏定義和帶參宏定義兩種。

1.無參宏定義

無參宏的宏名后不帶參數(shù)。其定義的一般形式為

#define標(biāo)識符字符串

其中的“#”表示這是一條預(yù)處理命令,凡是以“#”開頭的均為預(yù)處理命令;define為宏定義命令;標(biāo)識符為所定義的宏名;字符串可以是常量、表達(dá)式、格式串等。

在前面經(jīng)常使用過的符號常量的定義就是一種無參宏定義。

【例3.11】利用無參宏定義形式定義各種類型符號常量并輸出。本例通過定義各種數(shù)值及字符串,完成一個給定半徑情況下圓面積的計(jì)算輸出。

程序如下:

#include"stdio.h"

#definePI3.14159 /*定義π值*/

#defineR4 /*定義半徑值*/

#defineINFO"Theareais:" /*定義面積輸出提示*/

main()

{printf("%s%f\n",INFO,PI*R*R); /*以給定提示字符串輸出面積值*/

}

程序運(yùn)行結(jié)果如下:

Theareais:50.265440說明:

(1)根據(jù)一般C語言程序中變量的命名規(guī)則,符號常量的定義一般習(xí)慣使用大寫字母表示,主要是因?yàn)橥ǔT谝话阕兞康亩x中常使用小寫字母的形式。當(dāng)然,符號常量也可以以小寫字母命名。

(2)宏定義是用宏名來表示一個字符串,在宏展開時(shí)又以該字符串取代宏名,屬于一種簡單的代換。其中,所表示的字符串可含任意字符,可以是常數(shù),也可以是表達(dá)式,預(yù)處理程序?qū)λ蛔魅魏螜z查。如有錯誤,只能在編譯已被宏展開源程序的過程中發(fā)現(xiàn)問題。

(3)宏定義常用于程序中反復(fù)使用的常量或表達(dá)式。例如,利用符號常量M表示表達(dá)式(y*y+3*y)。在編寫源程序時(shí),所有使用到表達(dá)式(y*y+3*y)的地方都可由M代替,而對源程序作編譯時(shí),將先由預(yù)處理程序進(jìn)行宏代換,即用(y*y+3*y)表達(dá)式去置換所有的宏名M,然后再進(jìn)行編譯。

(4)宏定義不是說明或語句,在行末不必加分號,如加上分號則連分號也一起置換。

【例3.12】宏名表示一個表達(dá)式的應(yīng)用。

程序如下:

#include"stdio.h"

#defineM(y*y+3*y)/*定義宏名M表示指定表達(dá)式*/

voidmain()

{

ints,y;

printf("inputanumber:");

scanf("%d",&y);

s=3*M+4*M+5*M;/*M在預(yù)處理過程中被替換為所表示的表達(dá)式*/

printf("s=%d\n",s);

}

程序運(yùn)行結(jié)果如下:

inputanumber:12↙

s=2160本例中首先進(jìn)行宏定義,定義M表示表達(dá)式(y*y+3*y),在語句“s=3*M+4*M+5*M;”處作了宏調(diào)用。在預(yù)處理時(shí),經(jīng)宏展開后該語句變?yōu)?/p>

s=3*(y*y+3*y)+4*(y*y+3*y)+5*(y*y+3*y);

需要注意的是,在宏調(diào)用中,表達(dá)式(y*y+3*y)兩邊的括號不能省略,否則會發(fā)生錯誤。如果在例3.12中,將M的宏定義變?yōu)?/p>

#difineMy*y+3*y

則在宏展開時(shí)將得到下述語句:

s=3*y*y+3*y+4*y*y+3*y+5*y*y+3*y;

當(dāng)輸入y值12后,程序運(yùn)行結(jié)果為s=1836。

此結(jié)果顯然與加有括號的原題計(jì)算結(jié)果差異很大。因此,在作宏定義時(shí)必須十分注意,應(yīng)保證在宏代換之后不發(fā)生錯誤。

【例3.13】宏名所表示表達(dá)式末尾帶分號的實(shí)際使用。

/*程序功能:程序設(shè)計(jì)中宏名所表示表達(dá)式末尾帶分號的實(shí)際使用情況*/

#include"stdio.h"

#defineAAA500+1000;

voidmain()

{

inti;

i=AAA/*注意該命令行未加;*/

printf("i=%d\n",i);

}

程序運(yùn)行結(jié)果如下:

i=1500

本例所定義宏名AAA在實(shí)際宏代換過程中,將表達(dá)式500+1000連同所帶分號一起置換。在命令行i=AAA中,因所替換表達(dá)式已帶有分號,所以現(xiàn)命令行無須再增加末尾

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論