《C語言程序設計》課件第7章_第1頁
《C語言程序設計》課件第7章_第2頁
《C語言程序設計》課件第7章_第3頁
《C語言程序設計》課件第7章_第4頁
《C語言程序設計》課件第7章_第5頁
已閱讀5頁,還剩61頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

ch7 指針

指針是C語言重要的一種數(shù)據(jù)類型,也是C語言的一個重要特色。程序中通過指針的靈活運用,可以使程序更簡潔、高效。指針可以方便地操作數(shù)組和字符串,也可以直接訪問內存地址,提高程序的運行效率。深入的學習和掌握指針編程對于C語言的學習非常重要。7.1指針與地址

為了理解什么是指針,首先必須弄清楚數(shù)據(jù)在內存中是如何存儲和讀取的。

存儲單元的地址

存儲單元的內容

7.1指針與地址存儲單元的地址和存儲單元的內容是兩個概念,例如:

inta=10;

scanf("%d",&a);變量在定義時,系統(tǒng)已經分配了按整型存儲方式的4個字節(jié)的內存單元供變量a使用,變量名和對應的地址已經一一對應,第一條賦值語句通過變量名找到相應的地址,并將常量10存儲在內存單元中;第二條輸入語句,通過取地址操作符&獲取到a變量的地址,從輸入設備中獲取用戶輸入的數(shù)據(jù)之后保存到這個地址中。通過變量名直接訪問變量的方式稱為“直接訪問”方式,通過變量的地址來訪問變量的方式稱為“間接訪問”方式。

#include<stdio.h>intmain(){ intx=10; charc='A'; printf("x的地址:%X\nc的地址:%X\n",&x,&c);return0;}程序的運行結果如圖所示【例7.1】定義變量并輸出其內存地址。從程序運行結果看出,程序運行時為變量x分配了起始地址為C391AB0C的4個字節(jié)的內存空間,并將整型數(shù)10存儲在該內存空間中,為變量c分配地址為C391AB0B的1個字節(jié)的內存空間,并將字符'A'存儲在該內存單元中。內存示意圖如下圖所示。內存區(qū)內存地址值cADS:C391AB0Bx10DS:C391AB0CDS:C391AB0DDS:C391AB0EDS:C391AB0F

......

tips:變量在分配了內存空間后,可以使用運算符&取得變量的內存地址,這個地址也稱為變量的指針。冒泡排序法7.2.1指針變量的定義①指針:變量的地址被稱為指針。②指針變量:存放地址的變量稱為指針變量,指針變量的值就是地址,也就是指針。現(xiàn)在假設有一個char類型的變量c,它存儲了字符'A'(ASCII碼為十進制數(shù)65),并占用了地址為C160FEFB的內存(地址通常用十六進制表示)。另外有一個指針變量p,它的值為C160FEFB,正好等于變量c的地址,這種情況就簡稱p指向了c,或者說p是指向變量c的指針。指向關系的示意圖如下圖所示。7.2指針變量的定義與引用冒泡排序法(1)指針變量的定義一般形式:數(shù)據(jù)類型*指針變量名1,*指針變量名2,……;例如:int*p;float*fp1,*fp2;語法規(guī)則:①一次可以定義多個指針變量,每個指針變量名前都必須加注“*”號,以區(qū)別于普通變量的定義,其本身不屬于指針變量名;②數(shù)據(jù)類型必須與指針變量所指向變量的類型一致。地址數(shù)據(jù)本身是無類型可言的,但是指針變量所指向的對象一定有確切的數(shù)據(jù)類型,因此通常將指針變量所指向對象的數(shù)據(jù)類型稱為指針變量的數(shù)據(jù)類型;③指針變量只可以用來保存與它同類型的變量的指針,指針的操作是基于“類型”的。7.2指針變量的定義與引用冒泡排序法(2)指針變量的初始化指針變量的初始化有兩種方式:1)定義的同時直接初始化,其初始化的一般形式:數(shù)據(jù)類型*指針變量名=變量地址;例如:intx;int*p=&x;語法規(guī)則:①先定義一般變量,指針變量的值等于這個變量的地址;②指針變量的類型,必須與初始化時變量的類型相同。7.2指針變量的定義與引用冒泡排序法(2)指針變量的初始化指針變量的初始化有兩種方式:2)先定義指針變量,后初始化:例如:int*p1,*p2; //定義了兩個int類型的指針變量p1和p2inti,j;p1=&i; //合法,兩者類型一致。p1指向變量ip2=&j; //合法,兩者類型一致。p2指向變量j語法規(guī)則:先定義指針變量,之后在需要初始化的地方進行初始化。給指針變量賦值時,指針變量名前面沒有'*'。因為如果此時指針變量名前面加'*',該'*'是間接訪問運算符,具有運算功能,而非定義時只起說明作用的'*'。7.2指針變量的定義與引用冒泡排序法注意:一個指針變量在定義時未初始化,那么該指針變量不能進行任何操作!指針變量既然是一個變量,就應該具有變量的特點:其一,在內存中有一個內存單元與之對應;其二,變量值可以被改變。指針變量保存的是指針,其實就是一個內存地址值。指針變量本身都占用8個字節(jié)(64位操作系統(tǒng)8個字節(jié),32位操作系統(tǒng)4個字節(jié))的內存空間。7.2指針變量的定義與引用

#include<stdio.h>intmain(){ doubled,*p1=&d;inta,*p2=&a;charc,*p3=&c; printf("p1占用字節(jié)數(shù):%d\np2占用字節(jié)數(shù):%d\np3占用字節(jié)數(shù):%d\n",sizeof(p1),sizeof(p2),sizeof(p3));return0;}程序的運行結果如圖所示【例7.2】定義指針變量,運行程序查看指針變量占用的字節(jié)數(shù)。從程序運行結果看出,程序運行時為變量x分配了起始地址為C391AB0C的4個字節(jié)的內存空間,并將整型數(shù)10存儲在該內存空間中,為變量c分配地址為C391AB0B的1個字節(jié)的內存空間,并將字符'A'存儲在該內存單元中。內存示意圖如下圖所示。內存區(qū)內存地址值cADS:C391AB0Bx10DS:C391AB0CDS:C391AB0DDS:C391AB0EDS:C391AB0F

......

冒泡排序法(3)空指針初始化指針變量時,使用空指針NULL初始化可以避免指針變量指向一個隨機內存位置。NULL為定義在stdio.h頭文件中的符號常量,例如:int*p=NULL;在C語言中,NULL實質是((void*)0)。7.2指針變量的定義與引用冒泡排序法(1)&運算符&運算符稱為地址運算符,變量前加&運算符獲取變量的地址,也就是該變量的指針。(2)*運算符*運算符稱為指針運算符,指針變量前加*,表示該指針變量所指向的內存單元的值。例如:inti,*p=&i;//指針變量p初始化為指向變量i*p=10;//*p代表指針變量p指向的對象,也就是變量i,等價于i=10;7.2.2指針變量的引用※思考1:表達式&*p的含義是什么?該表達式相當于&(*p)。因為“*”和“&”都是單目運算符,優(yōu)先級別相同,按照自右向左的方向結合,因此首先運算*p,結果就是變量c,再進行&運算,即為變量c的地址。※思考2:表達式*&i的含義是什么?該表達式相當于*(&i)。首先進行&i運算,結果是變量i的地址,再進行*運算,指針“降級”為變量,結果就是變量i本身。冒泡排序法(3)直接訪問直接按變量名進行的訪問變量值的方式稱為“直接訪問”。例如有以下代碼段:inti,j;i=3;j=i*2;系統(tǒng)在執(zhí)行i=3;這條賦值語句時,首先找到i變量的地址(假設地址為:60FFD0),然后將整數(shù)3存入從60FFD0開始的4個字節(jié)存儲空間。執(zhí)行語句j=i*2;時,先從i變量的內存單元取出變量i的值3,計算i*2后將結果6存入j變量所對應的存儲空間。(4)間接訪問將變量的地址存放在一個指針變量中,然后通過指針變量來找到指向的變量的地址,從而訪問變量的值,稱為“間接訪問”,例如:inti,*pi; //定義了一個指針變量pi,可以存放地址數(shù)據(jù)i=3;pi=&i; //將變量i的地址賦給指針變量piprintf(“%d”,*pi); //輸出3要取出變量i的值,首先從指針變量pi對應的內存單元中取出i的地址(假設地址為C160FFD0),然后再從C160FFD0內存單元中取出i的值。7.2.2指針變量的引用3……………………

C160FFD0

指針變量pi

變量i

C160FFD0~C160FFD3

……………………

圖7.5變量的直接訪問與間接訪問示意圖

(5)指針的引用【例7.3】使用指針修改指針變量指向的變量的數(shù)值。#include<stdio.h>intmain(){ intdata=19; int*p=&data; *p=20; printf("data=%d\n",*p); printf("data=%d\n",data); return0;}程序的運行結果如圖所示主函數(shù)main中int*p=&data;將整型變量data的地址給指針變量p,也就是p指向了變量data,語句*p=20;通過指針變量修改了指向的變量data的數(shù)值,兩條輸出語句分別采用間接訪問和直接訪問的方式輸出了data的數(shù)值。

【例7.4】使用指針編程。輸入兩個整數(shù)a和b,按照從小到大的順序輸出。#include<stdio.h>intmain(){ inta,b; int*pmin,*pmax,*p; printf("請輸入兩個整數(shù):"); scanf("%d%d",&a,&b); pmin=&a;//指針變量pmin指向變量a pmax=&b;//指針變量pmax指向變量b if(*pmin>*pmax)//若*pmin較大,交換指針pmin和pmax的指向 { p=pmin; pmin=pmax; pmax=p; } printf("a=%d,b=%d\n",a,b); printf("min=%d,max=%d\n",*pmin,*pmax);return0;}程序的運行結果如圖所示分析:使用指針變量pmin和pmax分別指向變量a、變量b,當a>b時交換pmin和pmax的指向。不必交換變量a、b的值。變量a和b取值沒有發(fā)生變化,指針變量pmin和pmax的指向發(fā)生了變化冒泡排序法C語言中,基本數(shù)據(jù)類型實參傳遞給形參,是按值傳遞的,也就是說,函數(shù)中的形參是實參的拷貝份:這種數(shù)據(jù)傳遞是單向的,即從調用者傳遞給被調函數(shù),而被調函數(shù)無法修改傳遞的參數(shù)達到回傳的效果。有時候可以使用函數(shù)的返回值來回傳數(shù)據(jù),在簡單的情況下是可以的,但是如果返回值有其它用途,或者要回傳的數(shù)據(jù)不止一個,返回值就解決不了了。傳遞變量的指針可以輕松解決上述問題,(6)指針作為函數(shù)參數(shù)

傳遞變量的指針#include<stdio.h>voidchange(inta){ a++;}intmain(){ intdata=19; change(data); printf("data=%d\n",data); return0;}程序的運行結果如圖所示

將函數(shù)change的參數(shù)類型修改為指針之后,#include<stdio.h>voidchange(int*pa){ (*pa)++;}intmain(){ intdata=19; change(&data); printf("data=%d\n",data); return0;}程序的運行結果如圖所示從結果可以看到主函數(shù)中的變量data的數(shù)值在函數(shù)Change調用結束后更改為20。主函數(shù)main中調用Change函數(shù),實參為變量data的地址,在函數(shù)Change中通過指針修改指向變量的數(shù)值。冒泡排序法指針是地址數(shù)據(jù),是內存單元的編號,雖然從形式上看類似一個整數(shù),但它的含義與普通整數(shù)不同,只有當指針指向數(shù)組的前提下,可以對指針進行有限的一些運算。例如:inta[10];int*p=a;首先定義了一個一維整型數(shù)組a,a是數(shù)組名,存儲的是數(shù)組的首地址,通過賦值操作將數(shù)組首地址賦值給指針變量p,也稱作指針變量p指向了一維數(shù)組a。在此前提下,指針可以進行算術運算和關系運算。7.3指針與地址運算冒泡排序法

指針允許參與的算術運算包括:一般地,設指針變量p已指向數(shù)組的某元素的地址,n是正整數(shù),則:①p+n:仍為地址類數(shù)據(jù),指向p當前所指元素之后的第n個元素;②p-n:仍為地址類數(shù)據(jù),指向p當前所指元素之前的第n個元素;③p++:運算時,系統(tǒng)會根據(jù)p的基類型而將其值增加相應的字節(jié)個數(shù)。指針p后移,p本身數(shù)值發(fā)生了變化,指向數(shù)組中下一個元素;④p--:運算時,系統(tǒng)會根據(jù)p的基類型而將其值減少相應的字節(jié)個數(shù)。指針p前移,p本身數(shù)值發(fā)生了變化,指向數(shù)組中前一個元素;⑤p1-p2:兩個指針相減的結果表示兩個指針間隔的元素個數(shù),只有p1和p2都指向同一數(shù)組中的元素時才有意義。7.3.1算術運算冒泡排序法兩個指針可以進行關系運算。進行比較的兩個指針的類型必須相同時才有意義,否則不能進行比較。例如,設p、q是同類型的指針,則:①p==q。判斷p和q保存的地址數(shù)據(jù)是否相同,也就是是否指向同一個變量,若指向同一個變量結果為真(即為1),否則為假(即為0)。②p!=q。判斷p和q保存的地址數(shù)據(jù)是否不相同,也就是是否不指向同一個對象,若不指向同一個變量結果為真(即為1),否則為假(即為0)。③p>q。對p和q保存的地址數(shù)據(jù)進行比較判斷,如果p指向的對象在q指向的對象之后,則結果為真,否則為假。④p<q。對p和q保存的地址數(shù)據(jù)進行比較判斷,如果p指向的對象在q指向的對象之前,則結果為真,否則為假。進行p>q或p<q的關系運算時,只有當p和q都指向同一數(shù)組中的元素時才有意義。7.3.2關系運算冒泡排序法數(shù)組是同類型數(shù)據(jù)單元序列,每個數(shù)組元素所占用的內存單元字節(jié)數(shù)不僅相同而且是依次連續(xù)存儲的。數(shù)組的這個存儲特點與指針的運算相結合,可以通過指針引用數(shù)組元素。7.4一維數(shù)組與指針冒泡排序法有如下定義語句:

inta[5];

int*p=a;當指針指向數(shù)組時,可以用含指針變量的表達式的表示數(shù)組元素的地址和數(shù)組元素的值,具體表示形式如表所示。7.4.1一維數(shù)組元素的兩種等價表示法下標法指針法第i個元素地址&a[i],&p[i]p+i,a+i第i個元素值a[i],p[i]*(p+i),*(a+i)

【例7.5】數(shù)組元素的兩種表示法舉例。#include<stdio.h>intmain(){

inti,arr[3]={1,2,3}; printf("下標形式遍歷數(shù)組元素:\n"); for(i=0;i<3;i++)

printf("地址:%X,arr[%d]=%d\n",&arr[i],i,arr[i]); printf("指針形式遍歷數(shù)組元素:\n"); for(i=0;i<3;i++)

printf("地址:%X,*(arr+%d)=%d\n",arr+i,i,*(arr+i));

return0;}程序的運行結果如圖所示說明:①數(shù)組元素占用從C7104D50開始的連續(xù)12個字節(jié)的內存空間;②元素地址&arr[i]與arr+i等價;③數(shù)組元素arr[i]與*(arr+i)等價,前者稱為下標形式,后者稱為指針形式。冒泡排序法下標法引用數(shù)組元素比較直觀。但程序運行時,下標形式a[i]需要先轉換為指針形式*(a+i),計算出元素地址后再引用數(shù)組元素,所以指針法比下標法運算速度快。應用時要注意指針變量和數(shù)組名的區(qū)別,指針變量值可以改變,而數(shù)組名是地址常量,是數(shù)組的首地址,在程序運行過程中是固定不變的,不能被修改。指針變量存儲的是地址,數(shù)組的存儲空間大小由元素類型和個數(shù)決定,例如如下程序:#include<stdio.h>intmain(){ intarr[3]={1,2,3}; int*p=arr; printf("sizeof(arr)=%d\n",sizeof(arr)); printf("sizeof(p)=%d\n",sizeof(p)); return0;}程序運行結果如圖所示。7.4.2一維數(shù)組與指針的應用

【例7.6】使用指針法的兩種方式實現(xiàn)一維數(shù)組元素的輸入輸出。①

指針在遍歷的過程中數(shù)值沒有變化,始終是數(shù)組的首地址1#include<stdio.h>2intmain()3{ 4

inta[4],*p=a,i;5 for(i=0;i<4;i++)6

scanf("%d",p+i);7

for(i=0;i<4;i++)8

printf("%d\t",*(p+i));9

printf("\n");10

return0;11}

【例7.6】使用指針法的兩種方式實現(xiàn)一維數(shù)組元素的輸入輸出。②用移動指針變量的方法遍歷數(shù)組元素,程序代碼如下:1#include<stdio.h>2intmain()3{4inta[4],*p,i;5p=a; 6

for(i=0;i<4;i++)7

scanf("%d",p++);8p=a;9for(i=0;i<4;i++)10printf("%d\t",*p++);11

printf("\n");12return0;13}1#include<stdio.h>2intmain()3{4inta[4],*p,i;5p=a;6

for(i=0;i<4;i++)7

scanf("%d",p++);8p=a;9for(i=0;i<4;i++,p++)10printf("%d\t",*p);11

printf("\n");12return0;13}#include<stdio.h>intmain(){inta[4],*p=a;for(;p-a<4;p++)scanf("%d",p);p=a;for(;p-a<4;p++)printf("%d\t",*p);printf("\n");return0;}方法一方法二方法三注意:數(shù)組名是數(shù)組首地址值,是一個指針常量,在程序運行過程中是固定不變的。如下代碼中的a++是錯誤的。#include<stdio.h>intmain(){ inta[4],i;for(i=0;i<4;i++)

scanf("%d",a+i);for(i=0;i<4;i++)printf("%d\t",*a++);return0;}

【例7.7】從鍵盤輸入一組整數(shù)(數(shù)量不超過100),統(tǒng)計其中偶數(shù)個數(shù)與奇數(shù)個數(shù)。使用指針法。#include<stdio.h>intmain(){/*,*/ inta[100],i,nCount;//nCount為輸入整數(shù)的個數(shù)

intouCount=0;//ouCount統(tǒng)計偶數(shù)個數(shù)

intjiCount=0;//iCount統(tǒng)計奇數(shù)個數(shù) int*p=a; printf("請輸入數(shù)字的個數(shù):"); scanf("%d",&nCount); printf("請輸入%d個整數(shù):",nCount); for(i=0;i<nCount;i++) scanf("%d",p+i); for(i=0;i<nCount;i++,p++) { if(*p%2==0) ouCount++; else jiCount++; } printf("有%d個偶數(shù),%d個奇數(shù).\n",ouCount,jiCount); return0;}程序的運行結果如圖所示主函數(shù)main中,語句scanf("%d",p+i);使用指針法進行數(shù)據(jù)的輸入,指針變量p的數(shù)值沒有改變;在for循環(huán)中語句p++;通過指針變量p的移動訪問數(shù)組的每個元素。冒泡排序法多維數(shù)組是連續(xù)的內存單元序列,可以看作是一維數(shù)組的延伸。C語言處理數(shù)組時,在實現(xiàn)方法上只有一維數(shù)組的概念,多維數(shù)組是被當成一維數(shù)組處理的。下面以inta[3][4];這個二維數(shù)組為例說明這個概念。7.5二維數(shù)組與指針

7.5.1二維數(shù)組的處理方法與指針表示

【例7.8】使用下標法和指針法輸出二維數(shù)組元素及其內存地址。#include<stdio.h>intmain(){inta[3][4]={1,2,3,4,5,6,7,8,9,10,11,12};inti,j;printf("a=%X\n",a);for(i=0;i<3;i++)printf("a+%d=%X,a[%d]=%X,&a[%d]=%X,*(a+%d)=%X\n",i,a+i,i,a[i],i,&a[i],i,*(a+i));for(i=0;i<3;i++)for(j=0;j<4;j++)printf("a[%d]+%d=%X,*(a+%d)+%d=%X,&a[%d][%d]=%X\n",i,j,a[i]+j,i,j,*(a+i)+j,i,j,&a[i][j]);for(i=0;i<3;i++)for(j=0;j<4;j++)printf("*(a[%d]+%d)=%d,*(*(a+%d)+%d)=%d,a[%d][%d]=%d\n",i,j,*(a[i]+j),i,j,*(*(a+i)+j),i,j,a[i][j]);return0;}

【例7.8】使用下標法和指針法輸出二維數(shù)組元素及其內存地址。程序運行結果如圖所示。

【例7.8】使用下標法和指針法輸出二維數(shù)組元素及其內存地址。以上說明總結如下表7.2(a)和表7.2(b)所示。

冒泡排序法(1)行指針指向一維數(shù)組的指針簡稱為數(shù)組的指針(或稱為行指針)。定義行指針的一般定義形式:數(shù)據(jù)類型(*指針變量名)[一維數(shù)組長度];例如:

inta[3][4],(*p)[4]=a;語法規(guī)則:①圓括號不能省略,否則[]的運算級別高于*的運算級別,p將首先與[]結合為int*p[4]。②p是行指針可以接收行地址,可以對p進行以下方式的賦值:

p=a;

p=a+1;

p=&a[1];③行指針p作加法時的內存偏移量為“一行”。p的增值是以一維數(shù)組的長度為單位的,所以p+1指向a[1],p+2指向a[2],即*(p+i)等價于a[i]。④*(p+i)+j表示地址&a[i][j],*(*(p+i)+j)表示元素a[i][j]。7.5.2指向一維數(shù)組的指針

【例7.9】使用行指針編程,實現(xiàn)二維數(shù)組元素的輸入輸出。#include<stdio.h>intmain(){ inta[3][4],(*p)[4]; inti,j; p=a; printf("請輸入數(shù)組數(shù)據(jù)(3x4):\n"); for(i=0;i<3;i++) for(j=0;j<4;j++) scanf("%d",*(p+i)+j); printf("輸出數(shù)組(3*4):\n"); for(i=0;i<3;i++) { for(j=0;j<4;j++) printf("%5d",*(*(p+i)+j)); printf("\n"); } return0;}語句p=a;表示行指針變量p接收行地址,指向了二維數(shù)組第0行,語句scanf("%d",*(p+i)+j);和printf("%5d",*(*(p+i)+j));通過行指針對二維數(shù)組元素進行訪問,指針變量p在訪問期間沒有移動。冒泡排序法(2)列指針列指針是指向多維數(shù)組列元素的指針,列指針的一般定義形式:數(shù)據(jù)類型*指針變量名;例如:

inta[3][4];

int*p=*a;語法規(guī)則:①列指針指向的是列元素,也就是多維數(shù)組中的單個元素,所以將指向二維整型數(shù)組a的列指針定義為整型指針類型;②p是列指針可以接收列地址,可以對p進行以下方式的賦值:

p=*a;

p=&a[0][0];

p=a[0];7.5.2指向一維數(shù)組的指針

【例7.10】使用列指針編程,實現(xiàn)二維數(shù)組元素的輸入輸出。1#include<stdio.h>2intmain()3{4 inta[3][4],*p;5 inti,j;6 p=*a;7 printf("inputarray(3x4):\n");8 for(i=0;i<3*4;i++)9

scanf("%d",p++);10 p=&a[0][0];11 printf("\noutputarray(3*4):\n");12 for(i=0;i<3;i++)13 {14

for(j=0;j<4;j++)15 printf("%5d",*(p+i*4+j));16

printf("\n");17 }18 return0;19}冒泡排序法字符指針定義的一般形式如下:

char*指針變量名;字符指針可以用字符變量和字符串進行初始化。(1)字符指針指向字符變量例如:charc='a’;char*pc=&c;語法規(guī)則:先定義了一個字符變量c和一個字符指針變量pc,通過將變量c的地址賦值給pc,從而指針變量pc指向了c。這種方式應用很少,程序中對于字符的操作主要集中在字符串的處理上。7.6.1字符指針的定義和初始化冒泡排序法(2)字符指針指向字符串字符串可以通過字符數(shù)組存放,數(shù)組名就是其首地址;字符串常量存儲在常量池中,這兩種存儲方式都可以通過字符指針調用。1)字符指針指向字符串常量例如:

char*p="hello";語法規(guī)則:①先定義char型指針變量p;②系統(tǒng)在常量池中取出字符串常量"hello"的首地址;③將首地址賦給指針變量p,使p指向該字符串常量。注意:該語句不能理解為:將字符串賦給了指針變量p,而是將字符串的首地址賦給指針變量,即字符串的首個字符的地址。7.6.1字符指針的定義和初始化使用字符指針指向字符串常量要注意,所指向的是常量,其內容不可以修改,下面的程序段是不合法的,請思考為什么。冒泡排序法7.6.1字符指針的定義和初始化使用字符指針指向字符串常量要注意,所指向的是常量,其內容不可以修改,下面的程序段是不合法的,請思考為什么。#include<stdio.h>#include<string.h>intmain(){char*p="hello";scanf("%s",p);//錯誤,p所指向的是常量,不能修改常量內容puts(p);

return0;}程序中字符指針變量p所指向的是字符串常量,常量的數(shù)值不能修改,所以scanf("%s",p);的操作是不合法的。在字符指針變量的使用中還需要注意一定要初始化之后才可以使用,這在7.2.1節(jié)中已經說明。冒泡排序法2)字符指針指向字符數(shù)組例如:

charstr[]="hello";

char*p=str;語法規(guī)則:將數(shù)組的首地址通過數(shù)組名賦值給指針變量p,使字符指針變量p指向該字符數(shù)組。注意:因為指針指向的是數(shù)組的首地址,可以通過指針訪問數(shù)組,修改其數(shù)值或者其中元素的值。下面的程序當指針變量p指向字符數(shù)組時,程序就是合法的。#include<stdio.h>#include<string.h>intmain(){

charstr[]="hello",*p=str;

scanf("%s",p);

puts(p); return0;}7.6.1字符指針的定義和初始化

【例7.11】輸入兩個字符串比較它們的大小,輸出相應的信息,不使用strcmp()函數(shù)。1#include<stdio.h>2#defineSIZE203intmain()4{5

charstr1[SIZE],str2[SIZE],*ps1,*ps2;6

intn; 7 ps1=str1; //ps1指向字符數(shù)組str18 ps2=str2; //ps2指向字符數(shù)組str29 printf("請輸入兩個字符串:\n");10 scanf(("%s",ps1);getchar();11 scanf(("%s",ps2);12 for(;*ps1==*ps2&&*ps1!='\0'&&*ps2!='\0';)13 {

//ps1和ps2同時向后移動,準備比較下一對字符14 ps1++;15 ps2++;16

}17

n=*ps1-*ps2;18 if(n>0)19 printf("%s>%s\n",str1,str2);20 elseif(n<0)21 printf("%s<%s\n",str1,str2);22 else23

printf("%s==%s\n",str1,str2);24

return0;25}定義字符數(shù)組str1、str2分別存放輸入的兩個字符串,定義字符指針變量ps1和ps2分別指向它們。利用循環(huán)掃描兩個字符串,逐個字符進行比較,直到找到第一對兒不相等的字符即可。程序第12行開始的循環(huán)比較,是通過移動指針的位置訪問字符數(shù)組中的元素,循環(huán)條件中字符串遍歷是直到遇到字符串結束標志'\0'后使循環(huán)終止,同時移動兩個指針掃描字符串,直到出現(xiàn)不相同字符。

【例7.12】使用字符指針編程。從鍵盤輸入一行字符,分別統(tǒng)計其中控制字符、數(shù)字、26個英文字母(不區(qū)分大小寫)和其他字符的個數(shù)。#include<stdio.h>intmain(){ charstr[80],*ps=str; intkzsum,szsum,zfsum,othersum;

kzsum=szsum=zfsum=othersum=0;

printf("請輸入字符串:");

fgets(ps,80,stdin);

for(;*ps!='\0';ps++)

{

if(*ps<=31)

kzsum++;

elseif(*ps>='0'&&*ps<='9')

szsum++;

elseif((*ps>='a'&&*ps<='z')||(*ps>='A'&&*ps<='Z'))

zfsum++;

else

othersum++;

}

printf("控制字符:%d個,數(shù)字字符:%d個\n",kzsum,szsum);

printf("字母:%d個,其他:%d個\n",zfsum,othersum);

return0;}冒泡排序法字符串作為參數(shù)傳遞到函數(shù)中,是用的地址傳遞的方式,可以用數(shù)組名或者字符指針變量作為實參,在被調用的函數(shù)中可以改變字符串的內容,在主調函數(shù)中引用修改后的內容。7.6.2字符指針作函數(shù)參數(shù)

【例7.13】從鍵盤輸入一行字符串s,刪除其中所有的指定字符c。#include<stdio.h>voiddeleteChar(char*p,charc);intmain(){charstr[80],c;printf("請輸入字符串:");fgets(str,80,stdin);printf("請輸入要刪除的字符:");c=getchar();deleteChar(str,c);puts("刪除后的字符串為:");puts(str);return0;}voiddeleteChar(char*p,charc){char*p1=p,*p2=p;while(*p2!='\0'){if(*p2==c)p2++;else*p1++=*p2++;}*p1='\0';}分析:①通過兩個指針完成同一個字符串的遍歷,p1和p2初始值都指向字符串首地址。②p2完成整個字符數(shù)組的遍歷,p1只在出現(xiàn)非刪除字符時接收字符。③整個字符串遍歷后,通過p1指針保留了所有非刪除字符。冒泡排序法指針數(shù)組就是元素都是指針類型數(shù)據(jù)的數(shù)組,數(shù)組中的每一個元素都存放一個地址,相當于一個指針變量。定義一維指針數(shù)組的一般形式:數(shù)據(jù)類型*數(shù)組名[數(shù)組長度];例如:

int*p[5];語法規(guī)則:①[]是下標運算符,優(yōu)先級高于單目運算符*。②int*p[4]與int(*p)[4]是兩種不同類型的指針定義形式。前者定義的是長度為4的指針數(shù)組,后者定義的是指向長度為4的一維數(shù)組的指針變量。指針數(shù)組更適合處理多個字符串的問題,通過指針數(shù)組使處理更靈活。7.7指針數(shù)組

7.7.1指針數(shù)組的概念冒泡排序法char*p[4]={"GreatWall","BeiJing","Java","C"};charstr[][10]={"GreatWall","BeiJing","Java","C"};使用一維字符指針數(shù)組存儲方式中,系統(tǒng)在常量池中將對應字符串的首地址賦值給數(shù)組元素,即"GreatWall"的字符串首地址賦值給p[0]。系統(tǒng)根據(jù)實際需要,給字符串分配大小不同的存儲空間,因此,使用字符型指針數(shù)組表示多個字符串,相當于每行是可變長的二維數(shù)組。二維數(shù)組的存儲方式只能按照多個字符串中最大長度申請空間,相比之下字符型指針數(shù)組不會造成存儲空間浪費。

7.7.1指針數(shù)組的概念冒泡排序法經常用的main函數(shù)都是不帶參數(shù)的,實際上main函數(shù)可以帶參數(shù),這個參數(shù)可以認為是main函數(shù)的形式參數(shù)。C語言規(guī)定main函數(shù)的參數(shù)只能有兩個,其一般形式如下:函數(shù)原型:intmain(intargc,char*argv[]);函數(shù)參數(shù):參數(shù)argc表示接收的形參個數(shù),參數(shù)*argv是字符指針數(shù)組,用來接收從操作系統(tǒng)命令行傳來的每個字符串中首字符的地址;函數(shù)返回值:運行其程序的狀態(tài)碼,通常程序正常執(zhí)行結束則返回0;函數(shù)功能:執(zhí)行系統(tǒng)調用的命令,是程序執(zhí)行的入口,并可在執(zhí)行命令的同時,接收命令行的參數(shù)。7.7.2帶參數(shù)的main函數(shù)冒泡排序法main函數(shù)是操作系統(tǒng)調用的,作系統(tǒng)調用執(zhí)行的命令,其實就是C源代碼文件經過編譯鏈接之后生成的可執(zhí)行文件。命令行的一般形式如下:命令名參數(shù)1參數(shù)2...命令名和各參數(shù)之間用空格分隔。命令名是可執(zhí)行文件名,假設可執(zhí)行文件名為demo(linux下文件可能無擴展名,windows下可執(zhí)行文件的擴展名為.exe),想傳遞兩個字符串"China"和"World"作為main函數(shù)的參數(shù),命令行可以寫成如下形式:demoChinaWorlddemo為可執(zhí)行文件名,China和World是系統(tǒng)調用main函數(shù)時的參數(shù)。main函數(shù)中參數(shù)argc是指命令行中參數(shù)的個數(shù),其中命令名也作為一個參數(shù),上面的例子中argc的值為3,也就是有三個命令行參數(shù):demo、China和World。第二個參數(shù)argv是一個字符指針數(shù)組,數(shù)組中的每個元素指向一個命令行參數(shù),在上面的例子中有三個字符串,argv數(shù)組中的三個元素argv[0],argv[1],argv[2]分別指向字符串:"demo"、"China"和"World"。7.7.2帶參數(shù)的main函數(shù)通常操作系統(tǒng)通過調用main函數(shù)來調用程序中其它函數(shù)從而完成程序的功能,那么在什么情況下main函數(shù)需要參數(shù)呢?冒泡排序法例如,在一個名為demo.c的文件中,包含以下程序:#include<stdio.h>intmain(intargc,char*argv[]){while(argc>1){puts(*++argv);argc--;}return0;}程序運行結果如圖所示:7.7.2帶參數(shù)的main函數(shù)程序開始時*argv指向字符串"./demo",argc的值為3,循環(huán)條件argc>1是控制程序只輸出參數(shù)的內容,也就是字符串"China"和"World"。參數(shù)之間是以空格為間隔的,若參數(shù)本身就必須包含空格,需要將參數(shù)用雙引號引起來。向程序傳送參數(shù)時,一般各參數(shù)的長度都不相同,參數(shù)的個數(shù)也是任意的,使用字符指針數(shù)組作為main函數(shù)的形參類型,可以很好的滿足main函數(shù)使用的要求。

【例7.14】intmain(intargc,char*argv[]){intx=0;inty=0;intret=0;if(argc!=4){printf("請檢查參數(shù)個數(shù)");return0;}x=atoi(argv[2]);//atoi()函數(shù),把字符串轉換成整數(shù)y=atoi(argv[3]); //判斷/a/s/m/d中的哪一種switch(*(argv[1]+1))//*(argv[1]+1)為了去掉/{case'a':ret=addition(x,y);break;case's':ret=subtraction(x,y);break;case'm':ret=multiplication(x,y);break;case'd':ret=division(x,y);break;default:printf("參數(shù)有誤\n");break;}printf("%d\n",ret);return0;}使用main函數(shù)的參數(shù),實現(xiàn)一個整數(shù)計算器,程序可以接受三個參數(shù),第一個參數(shù)“/a”選項執(zhí)行加法,“/s”選項執(zhí)行減法,“/m”選項執(zhí)行乘法,“/d”選項執(zhí)行除法,后面兩個參數(shù)為操作數(shù)。如若文件名為calculator,那么命令行calculator/a35表示求3+5的結果。

7.7.3指針數(shù)組的應用 【例7.15】#include<string.h>#include<stdio.h>intmain(){ inti,j; char*city[5]={"beijing","shanghai","shenzhen","guangzhou","dalian"}; char*c; for(i=0;i<5-1;i++) for(j=0;j<5-1-i;j++) if(strcmp(city[j],city[j+1])>0) { c=city[j]; city[j]=city[j+1]; city[j+1]=c; } for(i=0;i<5;i++) printf("%s\n",city[i]);

return0;}定義一個長度為5的指針數(shù)組city,此時指針數(shù)組里存放的是未排序的5個字符串常量的首地址。采用冒泡法排序。冒泡法排序中,有時需要把待排序的對象進行交換,通過交換指向它們的指針,也就是交換指針變量存儲的地址,使得較小下標的指針指向的字符串也較小。這樣,排序后的指針數(shù)組如果用循環(huán)依次輸出字符串,結果就是排序后的多個字符串。字符指針變量指向字符串常量雖然可以靈活方便的進行交換,但是因為指向字符串常量,所以并不能通過字符指針修改指向的常量的數(shù)值,這時字符指針數(shù)組要配合字符數(shù)組使用。

【例7.16】用戶輸入5個地名,按照字典順序排序。使用指針數(shù)組編程實現(xiàn)。#include<stdio.h>#include<string.h>#defineN5voidsort(char*city[]){char*p;inti,j;for(i=0;i<N-1;i++)for(j=0;j<N-i-1;j++)if(strcmp(city[j],city[j+1])>0){p=city[j];city[j]=city[j+1];city[j+1]=p;}}定義一個長度為5的指針數(shù)組city,必須讓數(shù)組中的每個指針變量指向一個可存儲的區(qū)域,所以需要定義一個二維字符數(shù)組。在接收用戶輸入的同時讓字符指針數(shù)組中的每個元素指向二維數(shù)組中對應的一行首地址。冒泡法排序中,在發(fā)生交換時,并不是交換二維數(shù)組中的兩行字符串,而是交換了指向它們的指針變量的值,也就是交換指針變量存儲的地址,使得在字符指針數(shù)組中較小下標的指針指向的字符串也較小。這樣,排序后的指針數(shù)組如果用循環(huán)依次輸出字符串,結果就是排序后的多個字符串。但是原二維字符數(shù)組中的元素并沒有發(fā)生變化。intmain(){charstr[N][80],*city[N];inti;printf("請輸入5個城市名:\n");for(i=0;i<N;i++){city[i]=str[i];fgets(str[i],80,stdin);str[i][strlen(str[i])-1]='\0';}sort(city);printf("--排序后--\n\n");for(i=0;i<N;i++)puts(city[i]);return0;}冒泡排序法一級指針是指向變量的指針,指針變量的值雖然是地址,但是這個指針變量本身也需要存儲空間,存放一級指針變量存儲空間地址的變量,這就是二級指針,也成為“指針的指針”。指針的指針所存儲的地址是另外一個指針變量的地址,那么指針的指針就是提供了對于內存地址的讀取和修改。指針的指針可分為指向指針變量的指針,和指向指針數(shù)組的指針。7.8指針的指針冒泡排序法定義一個指針的指針一般格式如下:

變量類型**變量名;例如:

inta=100;

int*p1=&a;

int**p2=&p1;a,p1,p2三者的關系如圖7.29所示:圖7.29二級指針、一級指針和變量之間的指向關系示意圖一級指針變量p1指向變量a,二級指針p2指向指針p1。根據(jù)運算符的結合性,“*”運算符是從右向左結合,所以指針的指針p2的定義等價于:int*(*p2)=&p1;7.8.1指向指針變量的指針

【例7.17】1#include<stdio.h>2intmain()3{4inta=39;5int*p1=&a; //p1為指向a的指針6int**p2=&p1; //p2為指向p1的指針,即指針的指針7printf("變量a的值:a=%d\n",a);8printf("使用指針p1訪問變量a:*p1=%d\n",*p1);9printf("使用指針p2訪問變量a:**p2=%d\n",**p2);10printf("變量a的值=%d,變量a的地址=%#X\n",a,&a);11printf("指針p1的值=%#X,指針p1的地址=%#X\n",p1,&p1);12printf("指針p2的值=%#X,指針p2的地址=%#X\n",p2,&p2);13return0;14}定義一個整型變量,并定義指向變量的指針,以及指向指針的二級指針,輸出它們的數(shù)值以及地址。程序中第7~9行通過三種方式輸出的變量a的值,第10~12行輸出了三個變量的值以及地址,從結果看p1的值為變量a的地址,p2的值為變量p1的地址,p2指向了p1。冒泡排序法下方定義了指向指針數(shù)組的指針:

char*s[3]={"hello","world","!"};

char**p=s;該語句中定義的p是指向指針數(shù)組的指針變量,初始時指向指針數(shù)組s的首元素s[0],s[0]為一個字符型指針變量,p初始值為指針變量s[0]的地址。7.8.2指向指針數(shù)組的指針

【例7.18】用指針的指針方法遍歷指針數(shù)組data,并輸出數(shù)組的內容。#include<stdio.h>#defineN5//data數(shù)組長度intmain(){char*data[]={"Apple","Banana","Orange","Grape","Pineapple"};char**p;p=data;printf("data數(shù)組內的內容為:\n");for(inti=0;i<N;i++,p++)printf("%s\n",*p);return0;}for循環(huán)語句通過指針的指針p移動的方式遍歷指針數(shù)組,語句printf("%s\n",*p);通過指針的指針輸出數(shù)組data中的內容。冒泡排序法在程序中定義一個函數(shù),系統(tǒng)在編譯時就會為函數(shù)的源代碼分配一段存儲空間,這段存儲空間的起始地址是函數(shù)的入口地址,每次通過函數(shù)名調用函數(shù)時,從函數(shù)名得到函數(shù)的起始地址,從而調用函數(shù)代碼。函數(shù)的入口地址就是函數(shù)的指針,可以定義一個指向函數(shù)的指針變量,通過函數(shù)的指針來調用函數(shù)。7.9指向函數(shù)的指針冒泡排序法(1)函數(shù)指針的定義函數(shù)指針的定義一般格式如下:函數(shù)指針類型(*變量名)(形參列表)語法規(guī)則:①函數(shù)指針的類型應與指針所指函數(shù)的返回值類型相同;②“*”表示這是一個指針變量,形參列表與所指向的函數(shù)的形參列表相同;③因為“*”的優(yōu)先級較高,所以需要將“*變量名”用小括號括起來。例如:定義如下一個函數(shù)指針變量:int(*p)(int,int);假設有一函數(shù)聲明為:intfunc(intx,inty);則可以使用函數(shù)指針變量p指向該函數(shù):7.9指向函數(shù)的指針冒泡排序法(2)函數(shù)指針的使用:1)函數(shù)指針變量初始化一般格式:

指針名=函數(shù)名;例如:p=func;函數(shù)func的函數(shù)名保存了函數(shù)的首地址,通過賦值語句賦值給函數(shù)指針變量p,通過指針p調用函數(shù)執(zhí)行。2)利用函數(shù)指針的語法格式:(*指針名)(實參列表);例如:intz=(*p)(3,7);語法規(guī)則:①函數(shù)指針變量初始化時,賦值運算符的右側只寫函數(shù)名,即函數(shù)名就是函數(shù)的入口地址;②利用函數(shù)指針調用函數(shù)時,只需使用“(*指針名)”來代替函數(shù)名即可。7.9指向函數(shù)的指針

【例7.19】編寫函數(shù)求兩個整數(shù)a,b的和。方法一:通過函數(shù)名調用函數(shù)。#include<stdio.h>intsum(int,int);intmain(){ inta,b,c; printf("請輸入整數(shù)a和b,計算兩數(shù)之和:"); scanf("%d%d",&a,&b); c=sum(a,b); printf("%d+%d=%d\n",a,b,c); return0;}intsum(inta,intb){ returna+b;}程序中中語句int(*p)(int,int);定義了一個函數(shù)指針變量p,語句p=sum;將sum()函數(shù)首地址賦值給p,語句c=(*p)(a,b);通過函數(shù)指針調用sum()函數(shù)并傳遞參數(shù)、獲取返回值,實現(xiàn)函數(shù)的調用。既然可以利用函數(shù)名調用函數(shù),為什么還需要函數(shù)指針?方法二:通過函數(shù)指針調用函數(shù)。#include<stdio.h>intsum(int,int);intmain(){ int(*p)(int,int); inta,b,c; p=sum; printf("請輸入整數(shù)a和b,計算

溫馨提示

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

評論

0/150

提交評論