摘 要: 針對指針這一C語言學(xué)習(xí)的難點(diǎn)和重點(diǎn),介紹了變量數(shù)據(jù)類型與變量存儲區(qū)大小的關(guān)系、指針數(shù)據(jù)類型與指針移動量的關(guān)系。以變量的指針、一維數(shù)組指針、行指針、結(jié)構(gòu)變量的指針為例,采用對比的方法,介紹了使用指針存取的步驟和語句,并在此基礎(chǔ)上,給出了一種對指針語法規(guī)則的理解和學(xué)習(xí)使用指針的方法。
關(guān)鍵詞: C語言; 指針; 數(shù)據(jù)類型; 語法規(guī)則
中圖分類號:TP311 文獻(xiàn)標(biāo)志碼:A 文章編號:1006-8228(2012)12-39-02
Discussion on learning of pointer in C language
Xuan Zheng1, Zhao Junxuan2
(1. School of Electrical and Automation Engineering, Hefei University of Technology, Hefei, Anhui 230009, China;
2. School of Engineering, Anhui Agricultural University)
Abstract: Pointer is an emphasis and a difficulty in C language learning. First the relationships between data type of variable and the variable memory size, pointer data type and the pointer movement are introduced. Then taking pointer variable, one-dimensional array pointer, line pointer and structure pointer variable as examples, the usage of pointer access steps and statement is presented by comparative method. A method of individual understanding on pointer syntax rule and using pointer is put forward.
Key words: C language; pointer; date type; syntax rule
0 引言
C語言是功能強(qiáng)大的編程語言,在大一下“C語言程序設(shè)計”課程中,筆者接觸到指針,當(dāng)時覺得指針本事不小,但理解不了其功能和語法規(guī)則,后通過“微機(jī)原理及應(yīng)用”和“單片機(jī)原理及應(yīng)用”等課程的學(xué)習(xí),特別是在掌握了CPU尋址方式后,對指針的使用有了深入的理解。
指針變量(簡稱指針)是一種特殊的變量,是用來存放地址的變量。當(dāng)在程序中定義了
int i,*ip;char c,*cp;float f,*fp;double d,*dp;
計算機(jī)(本文程序運(yùn)行環(huán)境)就會給變量i分配地址連續(xù)的2個字節(jié)單元的存儲區(qū),i存儲區(qū)的起始地址為i;給變量c分配1個字節(jié)單元的存儲區(qū),c存儲區(qū)的起始地址為c;給變量f分配4個地址連續(xù)的字節(jié)單元的存儲區(qū),f存儲區(qū)的起始地址為f;給變量d分配8個地址連續(xù)的字節(jié)單元的存儲區(qū),d存儲區(qū)的起始地址為d。顯然變量的存儲區(qū)大小與定義時的數(shù)據(jù)類型存儲長度相一致。給指針變量ip、cp、fp、dp各分配2個連續(xù)的字節(jié)單元的存儲區(qū)。實(shí)際上,指針的數(shù)據(jù)類型并不控制指針變量存儲區(qū)大小,而是控制指針增1(或減1)操作移動量。如:ip++運(yùn)行時會使指針ip從當(dāng)前的位置朝地址增大的方向移動2個字節(jié);cp++移動1個字節(jié)單元;fp++移動4個字節(jié)單元;dp++移動8個字節(jié)單元。放到數(shù)組中看,即指向下一個數(shù)組元素。
1 變量與變量的指針
變量是用來存放單獨(dú)一個數(shù)據(jù)的。在編程中,一般根據(jù)要存放的數(shù)據(jù)類型來定義同類型的變量。例如:要存放數(shù)據(jù)+1257,安排變量x,則程序可為
例1:
int x=+1257; //定義整型變量x,并賦值
x+=5; //數(shù)據(jù)處理,通過變量名實(shí)現(xiàn)讀寫
換成變量的指針去完成,則程序可為
int x+=1257,*ip; //定義整型變量x和整型指針ip
ip=x; //將x地址送ip,ip成為x的指針
*p+=5; //數(shù)據(jù)處理,通過變量指針實(shí)現(xiàn)讀寫[1]
前者是通過變量名對其存儲區(qū)進(jìn)行讀寫操作,我們理解與CPU直接尋址方式相對應(yīng);后者通過變量x的指針ip對其存儲區(qū)進(jìn)行讀寫,理解為間接尋址方式[2]。由于變量只存放一個數(shù)據(jù),所以我們理解其指針的移動無實(shí)際意義。學(xué)習(xí)中遇到的另一個問題是:變量指針作為函數(shù)的參數(shù),對實(shí)參值的影響。
例2:
int sum1(int a,int b)
{ a=abs(a); b=abs(b); return(a+b);
}
main()
{ int x=+59,y=-67,z1,z2;
z1=sum1(x,y); z2=x+y;
printf(“%d,%d”,z1,z2); //輸出126,-8
}
換成用變量的指針作為函數(shù)參數(shù),程序可為
int sum2(int *ap,int *bp)
{ *ap=abs(*ap); *bp=abs(*bp); return(*ap+*bp);
}
main()
{ int x=+59,y=-67,z1,z2;
z1=sum2(x,y); z2=x+y;
printf(“%d,%d”,z1,z2); //輸出126,126
}
程序中將x、y的地址傳給了函數(shù)sum2形參,在sum2里并沒有改變x、y的存儲區(qū)的位置(地址),而是改變了x、y存儲區(qū)的內(nèi)容。因此我們理解:只要指針作為函數(shù)形參,并在函數(shù)體里又對指針?biāo)傅拇鎯^(qū)有賦值操作,那么將會影響實(shí)參的值[3]。
2 一維數(shù)組與一維數(shù)組的指針
一維數(shù)組用來存放一批同類型數(shù)據(jù)。例如:有10,20,30,40,50這么一批數(shù)據(jù)要存放,計劃用a數(shù)組。程序可為
例3:
int a[]={10,20,30,40,50};
for (int i=0; i<5; i++)
a[i]=a[i]+5; //通過數(shù)組元素下標(biāo)實(shí)現(xiàn)讀寫操作
若換成數(shù)組的指針去完成,程序可為:
int *arrayp; //定義同數(shù)據(jù)類型的指針變量
arrayp=a[0]; //指針賦值
//arrayp成為數(shù)組a的指針,當(dāng)前指向a數(shù)組的0號元素
for (int i=0; i<5; i++)
{ *arrayp=*arrayp+5; //通過指針實(shí)現(xiàn)讀寫操作
arrayp++; } //指針加1操作,指向下一個元素
由于這一批數(shù)據(jù)在內(nèi)存連續(xù)存放,所以指針移動有實(shí)際意義。這里每次循環(huán)都采用*arrayp訪問,但是在不同的循環(huán)次數(shù)中,arrayp指向是不同的。
3 二維數(shù)組與行指針
在C語言中,二維數(shù)組的數(shù)據(jù)按行存放[4]。若以行起始單元作為參考點(diǎn),則該行中的各元素的偏離參考點(diǎn)的字節(jié)數(shù)=所在列號*數(shù)據(jù)類型存儲長度;各元素地址=所在列號*數(shù)據(jù)類型存儲長度+所在行起始單元的地址。因此,使用行指針對每一行各元素的訪問,相當(dāng)于對一維數(shù)組各元素的訪問。
例4:
二維數(shù)組內(nèi)容如圖1所示,現(xiàn)要將各數(shù)據(jù)加上10處理,計劃用arrayb存放。
程序可為:
int arrayb[3][]={{10,20,30,40,50},
{15,25,35,45,55},{16,26,36,46,56}};
int i,j;
for(i=0; i<3; i++)
for(j=0; j++; j<5)
arrayb[i][j]=arrayb[i][j]+10;
換成行指針去完成,程序可為:
int i,j,(*arraybp)[5];
p=arrayb[0]; //指向起始行
for(i=0; i<3; i++)
for(j=0; j++; j<5)
{ *(*arraybp+j)=*(*arraybp+j)+10;
arraybp++; //行指針移動一行
}[5]
我們理解行指針arraybp存儲區(qū)里存放的是行地址,(*arraybp)取出的是該行第一個(0號)元素的地址。
4 結(jié)構(gòu)變量與結(jié)構(gòu)變量的指針
結(jié)構(gòu)變量用來存放若干不同類型的數(shù)據(jù)。因此,結(jié)構(gòu)變量的數(shù)據(jù)類型為用戶定義型,即結(jié)構(gòu)的各成員數(shù)據(jù)類型由用戶根據(jù)實(shí)際情況定義。例如定義的結(jié)構(gòu)類型如下:
struct person
{ int no;
char name[8];
int math;
int power; };
現(xiàn)要存放該類型數(shù)據(jù)09110,王靜靜,85,90,并要對后2個成員數(shù)據(jù)求平均數(shù)。程序可為:
struct person aa={09110,王靜,85,90};
int avg;
avg=(aa.math+aa.power)/2;
換成結(jié)構(gòu)指針去完成,程序可為:
struct person *aap;
aap=aa; //aap成為aa的指針
avg=(aap→math+aap→power)/2;
同樣,我們認(rèn)為aap指針移動無實(shí)際意義。結(jié)構(gòu)變量和結(jié)構(gòu)變量的指針作為函數(shù)參數(shù)意義不一樣。上例結(jié)構(gòu)變量aa(由struct person aa定義)作為實(shí)參傳給形參的是一批數(shù)據(jù)09110,王靜靜,85,9009110;而結(jié)構(gòu)變量指針aap(由struct person *aap定義)作為實(shí)參傳給形參的是存放這一批數(shù)據(jù)09110,王靜靜,85,9009110存儲區(qū)的起始地址。同變量指針作為函數(shù)參數(shù)一樣,在函數(shù)里對指針?biāo)竻^(qū)域有賦值操作,會影響原始數(shù)據(jù)。
5 結(jié)構(gòu)數(shù)組與結(jié)構(gòu)數(shù)組的指針
結(jié)構(gòu)數(shù)組用來存放一批若干不同類型的數(shù)據(jù)。若有一批struct person類型數(shù)據(jù),在程序設(shè)計中可安排該類型數(shù)組存放。
例5:
struct person arrays[]={{09110,王靜靜,85,90},
{09111,張一川,95,97},{09112,石金琳,78,65}};
要將各元素的math成員的值乘以80℅,程序可為:
For (int i=0;i<3;i++)
arrays[i].math=arrays[i]*0.8;
換成結(jié)構(gòu)數(shù)組的指針完成,程序如下:
struct person *sp;
sp=arrays[0]; //sp指向0號元素
for (int i=0; i<3; i++)
{ sp→math=sp→math*0.8;
sp++; } //移動結(jié)構(gòu)指針
注意這里的sp++,其實(shí)際意義是指向下一個數(shù)組元素,而不是指向下一個結(jié)構(gòu)成員。
6 結(jié)束語
采用這種對比方法學(xué)習(xí)指針,能正確建立指針概念,即定義同類型指針,要先給指針賦值確定指針指向,再通過指針對所指的存儲區(qū)進(jìn)行讀寫操作、理解撥動指針的意義等;對指針加1操作可以通過輸出指針當(dāng)前值來幫助理解。此外,還能加深理解數(shù)據(jù)的存放形式,即數(shù)據(jù)是借助于變量、數(shù)組、結(jié)構(gòu)變量、結(jié)構(gòu)數(shù)組的存儲區(qū)存入內(nèi)存。
參考文獻(xiàn):
[1] 孫力.C語言程序設(shè)計[M].中國農(nóng)業(yè)出版社,2008.
[2] 宋振方等.以管理者視角突破C++指針教學(xué)難點(diǎn)[J].現(xiàn)代計算機(jī),
2011.2:66-68
[3] 譚浩強(qiáng).C程序設(shè)計題解與上機(jī)指導(dǎo)[M].清華大學(xué)出版社,1999.
[4] 譚浩強(qiáng).C程序設(shè)計教程(第二版)[M].清華大學(xué)出版社,1999.
[5]付喜梅.淺析C語言中指針與數(shù)組[J].電腦開發(fā)與應(yīng)用,2011.10:
29-32