摘要:指針在C語言中具有重要的地位,也是初學者最不容易掌握的內容。本文首先介紹了計算機的存儲機制,在此基礎上介紹了指針的概念,并給出了幾個典型的指針應用的例子,說明了指針的方法。
關鍵詞:C語言;指針;教學探索
中圖分類號:G642.0 ?搖文獻標志碼:A 文章編號:1674-9324(2014)06-0233-03
指針在C語言中具有重要的地位,也是C語言教學中學生最難掌握的內容,一個學生是否學會了C語言,從他是否掌握了指針就可以大體上做出評判。本文重點探討一下C語言在指針教學中的要點和體會。
一、計算機的存貯機制
在教學中我們發現,一些學習過計算機原理、匯編的同學,對指針的概念比較容易理解,掌握的也比較快,即便遇到一些比較復雜的指針關系,也往往能夠通過自己的思考,給出正確的解釋。究其原因,就是因為這些同學對計算機的存儲機制比較了解,可以將指針與存儲對應起來。為此,我們先簡要介紹一下計算機的存儲機制。在計算機中,數據以二進制的形式存儲在內存中,內存的基本單位是字節,一個字節由8位二進制組成,一個數可以由一個字節表示,也可以由多個字節組合在一起表示,與具體的數值類型有關。比如,一般來說一個字符用一個字節表示就可以了,而一個整數則一般由多個字節表示,比如2個字節或4個字節等。具體由幾個字節表示,與具體的C語言編譯器有關。為了敘述方便,在以下的討論中我們假定字符是一個字節,而整數是兩個字節。
內存中每個字節都有一個編號,通常稱為該字節的地址,用于指定該字節。就好比我們通常用號碼對賓館的房間進行編號一樣。地址的長度也是與編譯器有關的,在這里我們假定地址的長度為4個字節。圖1給出了一個內存存儲的示意圖。同樣為了敘述方便,無論是地址還是數據我們都使用的是十進制或者直接使用字符,而實際上應該是二進制的。在圖1中,左邊的表示地址,右邊的表示存儲的內容。在1000~1001這兩個地址中,存儲的分別是字符a、b,每個各種一個字節。1002和1004開始的兩個字節,存儲的分別是123和456兩個整數。2010、2014和2018開始的4個字節,分別存儲了1003、1000和2010,其含義我們在后面再介紹。在C語言中,一個變量是與一個地址所對應的,比如,如果定義了變量:int n,m;則編譯器會自動為n、m分別分配一個地址,變量n、m的值就分別存儲在它們所對應的地址中。
二、指針的基本概念
什么是指針?簡單地說指針就是其值為地址的變量。一個指針變量的值是某個地址,該變量所指向的內容,則是該地址中所存儲的內容。如同整型變量一樣,指針變量也是一個變量,只不過整型變量的值是整數,而指針變量的值是一個指針,也就是說是一個地址,通過該地址可以找到指針所指向的內容。下面討論中,指針變量我們簡稱為指針。我們先通過一個類比的例子來說明指針的概念。假設某賓館有101、102……等房間,這些房間中,有些是住人的,比如101房間住的是張三,102房間住的是李四,則可以認為101房間的值是張三,102房間的值是李四。這個賓館有些奇怪,除了住人的房間外,還有一些房間并不住人,里面只是有一個牌子,上面寫著某個房間號。比如說,105這個房間,里面的牌子上寫著102。那么105房間就可以認為對應一個指針變量,其值是一個地址102,該指針所指向的值,就是102房間的李四。這里要區分出指針自己的值以及指針所指向的值。在該例子中,105房間(指針)自己的值是102,其指向的值是李四。結合圖1的例子,我們假設有以下定義:int *p1;char *p2;假設編譯器為p1、p2分別分配的地址是圖1中的2010和2014,則p1的值是1002,是一個地址,而p1所指向的內容,即*p1的值為地址1002中所存儲的內容,即整數123。同樣,p2的值是1000,也是一個地址,p2所指向的內容,即*p2的值為字符a。有了以上指針的基本概念后,再復雜的指針,也可以一步推導出具體的含義。比如如下的指針的指針的定義:int **p;還是假定編譯器為p分配的地址是圖1中的2018。則p的值是2010,是一個地址。P所指向的內容,也就是*p的值是地址2010中的內容1002,還是一個地址。P所指向的內容的內容,即**p就是存貯在1002中的整數123。C語言中,操作符“&”可以得到一個變量的地址,比如:int n,*p;就可以通過p=&n得到變量n的地址,并賦值給指針p。
三、指針的應用
在C語言中,指針的應用比較多,有些情況是用指針會比較方便,有些情況是必須用指針。下面給出幾個有關指針使用的例子。
1.交換兩個變量的數據,編寫一個函數,實現兩個變量數據的交換,初學者很可能給出這樣的定義:
void swap(int a,int b)
{
int t=a;
a=b;
b=t;
}
當為了交換兩個變量的數值時,則這樣調用:
main()
{
int x=10,y=20;
printf(“%d %d/n”,x,y);
swap(x,y);
printf(“%d %d/n”,x,y);
}
但是,當你運行該程序時,卻驚奇的發現結果并不正確。這是為什么呢?這與C語言中參數的傳遞機制有關。在調用swap函數時,x、y的值傳遞給了參數a、b,在函數內部交換的實際上是a、b的值,而不是x、y的值。那么如何解決這個問題呢?在C語言中就需要用到指針了。正確的swap函數的定義及調用如下:
void swap(int *a,int *b)
{
int t=*a;endprint
*a=*b;
*b=t;
}
main()
{
int x=10,y=20;
printf(“%d %d/n”,x,y);
swap(&x,&y);
printf(“%d %d/n”,x,y);
}
這樣為什么就是正確的呢?因為通過取地址操作&分別得到了x、y的地址,在函數調用時,作為參數x、y的地址傳遞給了a、b,在swap內部,交換的是a、b所指向的內容,而a、b所指向的內容,實際上就是x、y的值,從而達到了交換x、y值的目的。假設x、y的地址分別是1000和1002,而在調用swap時,分配給a、b的地址分別是2000和2004。由于x、y均為整數,這里假定整數占用兩個字節;而a、b均為指針,假定占用4個字節,如圖2所示。通過取地址操作分別得到x、y的地址1000和1002,并作為參數傳遞給了a和b,在swap內部交換a、b所指向的內容,實際上交換的就是內存地址1000和1002的內容,也就是x和y的內容。所以,通過指針操作,達到了交換x、y的值的目的。
2.鏈表。鏈表的功能與數組有些類似,但是鏈表的長度不固定,可以根據需要動態的調整,可長可短。而且鏈表最大的好處是插入、刪除比較方便。比如說,用鏈表記錄某一門課的成績,選修的學生人數少的可能有十幾人,多的可能有幾百人。如果用數組,則可能需要定義一個最大值,無論學生多少,都需要定義這么大的數組。而如果用鏈表的話,則可以根據學生的多少,動態的變化。再比如,如果某個學生中途退選了這門課程,需要刪除該學生的有關信息,如果是數組的話,特別是當需要刪除的學生排在第一位時,則需要在數組中移動所有學生的信息。而鏈表,則可以比較容易地刪除一個學生的信息。插入一個學生信息也是如此。特別當這種插入、刪除操作頻繁發生時,使用鏈表的效率就會比較高。所謂的鏈表,就是一些通過指針鏈接在一起的數據單元。一個數據單元由兩部分組成,一部分為數據域,用于存放與該數據單元有關的數據,一部分為指針域,用于存放鏈表的下一個單元的地址。鏈表的示意圖如圖3所示。
其中Di表示數據,數據不一定是一個,可能是一組相關聯的數據。鏈表最后一個單元的指針是空指針NULL,表示鏈表結束,這里用“^”表示。在C語言中,鏈表的單元可以用結構定義。比如,我們要實現一個記錄某個課程成績的鏈表,一個單元記錄一個學生的信息,包括學號、姓名、成績等。則該單元可以定義如下:
struct NODE
{
?搖int number;
?搖double grade;
?搖struct NODE *next;
};
這里用nunber表示學號,grade表示成績,next是指向下一個單元的指針。那么如何建立一個鏈表呢?可以通過每次向一個鏈表插入一個單元的辦法建立一個鏈表。要插入一個單元,首先要為一個單元分配一個空間,這可以通過C語言的函數malloc來實現,其輸入參數是單元的大小,其返回值是指向該單元的指針。比如本例中,以下調用就為一個單元分配了空間,并在p中得到了指向該單元的指針:
strunct NODE *p;p=malloc(sizeof(struct NODE));假設list是指向學生成績鏈表的指針,如果向該鏈表插入一個單元,其實很簡單,只要令該單元的next等于list,然后再將list指向該單元就可以了。下面給出向學生成績鏈表中插入一個單元的函數,其中輸入參數分別是指向成績鏈表的指針、學號、姓名和成績,返回值是指向插入了一個單元后的成績鏈表的指針。這里假定開始時,成績鏈表為空,即list的值為NULL。
struct NODE *insert(struct NODE *list,int number,double grade)
{
?搖struct NODE *p;
?搖p = malloc(sizeof(struct NODE));
?搖p->number = number;
?搖p->grade = grade;
?搖p->next = list;
?搖return p;
}
比如從鍵盤輸入學生學號和成績建立成績鏈表,當學號為0時表示輸入結束,則程序如下:
struct NODE *list = NULL; //初始的成績鏈表為一個空表
mail()
{
?搖int number = 1;
?搖double grade;
?搖while (1)
?搖{
?搖?搖printf(“請輸入學號、成績:”);
?搖?搖scanf(“%d %f”, &number, &grade);
?搖?搖if (number == 0) break;
?搖?搖list = insert(list, number, grade);?搖}
}
為了輸出成績單,可以用以下的函數實現,其原理就是先輸出成績鏈表的第一個同學的成績,然后再通過指針找到下一個同學,以此類推,直到下一個同學為NULL為止。該函數的輸入參數為指向成績鏈表的指針。
Printlist(strunct NODE *list)
{
while (list)
?搖{
?搖?搖printf(“學號:%d 成績:%f\n”,list->number, list->grade);endprint
?搖?搖list = list->next;?搖}
}
3.樹結構。樹結構簡稱為樹,比如當表示一個家族關系時,就需要用到樹結構。樹結構也可以用指針實現。比如某家族情況如下:
A為祖父,B是他的妻子,C、D、E是他們的孩子,其中C、D為男孩,E為女孩,F是C的妻子,G、H是C的孩子。如何表示這樣的一種結構呢?我們可以設計這樣的一種結構:
struct TREE
{
char xingming[10];
strunct TREE *peiou;//指向配偶
strunct TREE *xiongmei;//指向自己的一個兄弟姐妹
strunct TREE *haizi;//指向自己的孩子鏈表
strunct TREE *fuqin;//指向自己的父親
}
這里,配偶、父親都是唯一的,用指針指向他們就可以了。由于一個人的兄弟姐妹人數是不確定的,有的人多有的人少,所以兄弟姐妹之間用上節介紹的鏈表表示,也就是說,同屬于一個父親的兄弟姐妹之間,形成一個鏈表。父親的haizi(孩子)指針,指向該鏈表的第一個單元,通過該指針,就可以得到一個人的所有的孩子。示意圖如下:
而這里的父親、妻子、孩子等,也都與張三具有同樣的結構,比如“妻子”,也有指向她父親的指針,她的配偶指針則指向張三,而她的孩子指針,也同張三一樣,指向孩子鏈表。有了這樣的結構和鏈接關系,就可以很方便地從家族樹中提取出想要的關系。假設p是指向張三這個結構的指針,則有:輸出張三的父親:printf(“%s”,p->fuqin->xingming);輸出張三的母親,由于這里并沒有直接的“母親”信息,可以通過父親的配偶關系得到:Printf(“%s”,p->fuqin->peiou->xingming;當然,也可以在結構中增加一個muqin指針,直接指向自己的母親,這完全根據實際需要設計。比如,如果頻繁的查找某些人母親信息,則可以考慮添加一個muqin指針,以提高效率。輸出張三的所有孩子:q=p->haizi;
while (q)
{
?搖printf(“%s “,q->xingming);
?搖q=q->xiongmei;}
在C語言中,指針是比較重要的概念,也是學生在學習過程中難于理解且遇到的比較多的問題。通過在C語言教學過程中的實踐,整理了一些針對指針教學的問題,通過這些問題的講解和分析,學生往往會加深對指針的理解,希望對有關C語言的教與學能起到一定的幫助。
參考文獻:
[1]薛勝軍.計算機組成原理[M].武漢:華中科技大學出版社,2000.
[2]王誠,劉衛東,宋佳興.計算機組成與設計[M].3版.北京:清華大學出版社,2008.
[3]嚴蔚敏,吳偉民.數據結構(C語言版)[M].北京:清華大學出版社,2006.
[4]譚浩強.C程序設計M].北京:清華大學出版社,2006.
[5]David J.Kruglinski.Visual.C++技術內幕[M].4版.北京:清華大學出版社,2001.
[6]H.M.Deitel,P.J.Deitel.C程序設計教程[M].北京:機械工業出版社,2001.
[7]黃宇.C語言教學中幾個常見的問題[J].計算機教育,2009,(10).endprint
?搖?搖list = list->next;?搖}
}
3.樹結構。樹結構簡稱為樹,比如當表示一個家族關系時,就需要用到樹結構。樹結構也可以用指針實現。比如某家族情況如下:
A為祖父,B是他的妻子,C、D、E是他們的孩子,其中C、D為男孩,E為女孩,F是C的妻子,G、H是C的孩子。如何表示這樣的一種結構呢?我們可以設計這樣的一種結構:
struct TREE
{
char xingming[10];
strunct TREE *peiou;//指向配偶
strunct TREE *xiongmei;//指向自己的一個兄弟姐妹
strunct TREE *haizi;//指向自己的孩子鏈表
strunct TREE *fuqin;//指向自己的父親
}
這里,配偶、父親都是唯一的,用指針指向他們就可以了。由于一個人的兄弟姐妹人數是不確定的,有的人多有的人少,所以兄弟姐妹之間用上節介紹的鏈表表示,也就是說,同屬于一個父親的兄弟姐妹之間,形成一個鏈表。父親的haizi(孩子)指針,指向該鏈表的第一個單元,通過該指針,就可以得到一個人的所有的孩子。示意圖如下:
而這里的父親、妻子、孩子等,也都與張三具有同樣的結構,比如“妻子”,也有指向她父親的指針,她的配偶指針則指向張三,而她的孩子指針,也同張三一樣,指向孩子鏈表。有了這樣的結構和鏈接關系,就可以很方便地從家族樹中提取出想要的關系。假設p是指向張三這個結構的指針,則有:輸出張三的父親:printf(“%s”,p->fuqin->xingming);輸出張三的母親,由于這里并沒有直接的“母親”信息,可以通過父親的配偶關系得到:Printf(“%s”,p->fuqin->peiou->xingming;當然,也可以在結構中增加一個muqin指針,直接指向自己的母親,這完全根據實際需要設計。比如,如果頻繁的查找某些人母親信息,則可以考慮添加一個muqin指針,以提高效率。輸出張三的所有孩子:q=p->haizi;
while (q)
{
?搖printf(“%s “,q->xingming);
?搖q=q->xiongmei;}
在C語言中,指針是比較重要的概念,也是學生在學習過程中難于理解且遇到的比較多的問題。通過在C語言教學過程中的實踐,整理了一些針對指針教學的問題,通過這些問題的講解和分析,學生往往會加深對指針的理解,希望對有關C語言的教與學能起到一定的幫助。
參考文獻:
[1]薛勝軍.計算機組成原理[M].武漢:華中科技大學出版社,2000.
[2]王誠,劉衛東,宋佳興.計算機組成與設計[M].3版.北京:清華大學出版社,2008.
[3]嚴蔚敏,吳偉民.數據結構(C語言版)[M].北京:清華大學出版社,2006.
[4]譚浩強.C程序設計M].北京:清華大學出版社,2006.
[5]David J.Kruglinski.Visual.C++技術內幕[M].4版.北京:清華大學出版社,2001.
[6]H.M.Deitel,P.J.Deitel.C程序設計教程[M].北京:機械工業出版社,2001.
[7]黃宇.C語言教學中幾個常見的問題[J].計算機教育,2009,(10).endprint
?搖?搖list = list->next;?搖}
}
3.樹結構。樹結構簡稱為樹,比如當表示一個家族關系時,就需要用到樹結構。樹結構也可以用指針實現。比如某家族情況如下:
A為祖父,B是他的妻子,C、D、E是他們的孩子,其中C、D為男孩,E為女孩,F是C的妻子,G、H是C的孩子。如何表示這樣的一種結構呢?我們可以設計這樣的一種結構:
struct TREE
{
char xingming[10];
strunct TREE *peiou;//指向配偶
strunct TREE *xiongmei;//指向自己的一個兄弟姐妹
strunct TREE *haizi;//指向自己的孩子鏈表
strunct TREE *fuqin;//指向自己的父親
}
這里,配偶、父親都是唯一的,用指針指向他們就可以了。由于一個人的兄弟姐妹人數是不確定的,有的人多有的人少,所以兄弟姐妹之間用上節介紹的鏈表表示,也就是說,同屬于一個父親的兄弟姐妹之間,形成一個鏈表。父親的haizi(孩子)指針,指向該鏈表的第一個單元,通過該指針,就可以得到一個人的所有的孩子。示意圖如下:
而這里的父親、妻子、孩子等,也都與張三具有同樣的結構,比如“妻子”,也有指向她父親的指針,她的配偶指針則指向張三,而她的孩子指針,也同張三一樣,指向孩子鏈表。有了這樣的結構和鏈接關系,就可以很方便地從家族樹中提取出想要的關系。假設p是指向張三這個結構的指針,則有:輸出張三的父親:printf(“%s”,p->fuqin->xingming);輸出張三的母親,由于這里并沒有直接的“母親”信息,可以通過父親的配偶關系得到:Printf(“%s”,p->fuqin->peiou->xingming;當然,也可以在結構中增加一個muqin指針,直接指向自己的母親,這完全根據實際需要設計。比如,如果頻繁的查找某些人母親信息,則可以考慮添加一個muqin指針,以提高效率。輸出張三的所有孩子:q=p->haizi;
while (q)
{
?搖printf(“%s “,q->xingming);
?搖q=q->xiongmei;}
在C語言中,指針是比較重要的概念,也是學生在學習過程中難于理解且遇到的比較多的問題。通過在C語言教學過程中的實踐,整理了一些針對指針教學的問題,通過這些問題的講解和分析,學生往往會加深對指針的理解,希望對有關C語言的教與學能起到一定的幫助。
參考文獻:
[1]薛勝軍.計算機組成原理[M].武漢:華中科技大學出版社,2000.
[2]王誠,劉衛東,宋佳興.計算機組成與設計[M].3版.北京:清華大學出版社,2008.
[3]嚴蔚敏,吳偉民.數據結構(C語言版)[M].北京:清華大學出版社,2006.
[4]譚浩強.C程序設計M].北京:清華大學出版社,2006.
[5]David J.Kruglinski.Visual.C++技術內幕[M].4版.北京:清華大學出版社,2001.
[6]H.M.Deitel,P.J.Deitel.C程序設計教程[M].北京:機械工業出版社,2001.
[7]黃宇.C語言教學中幾個常見的問題[J].計算機教育,2009,(10).endprint