CC++程序設計課件第6章 利用指針編程_第1頁
CC++程序設計課件第6章 利用指針編程_第2頁
CC++程序設計課件第6章 利用指針編程_第3頁
CC++程序設計課件第6章 利用指針編程_第4頁
CC++程序設計課件第6章 利用指針編程_第5頁
已閱讀5頁,還剩74頁未讀 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

第6章利用指針編程問題原由指針是在基本數(shù)據(jù)類型基礎上擴展而得到的數(shù)據(jù)類型,是C語言的特色和精華所在,是靈活高效訪問數(shù)據(jù)的手段。怎樣利用指針的特性設計出高效的算法程序?這就是本章所要討論的問題。指針的定義與引用、指針數(shù)組與數(shù)組指針、指針與函數(shù)、動態(tài)內(nèi)存分配與動態(tài)數(shù)組、指針案例程序設計等。

教學重點能力要求掌握:指針的基本概念;

掌握:利用指針進行程序設計的方法;熟悉:動態(tài)內(nèi)存分配與動態(tài)數(shù)組的使用,能利用指針設計出高效的實際應用程序。§6.1指針的定義與引用組§6.4動態(tài)內(nèi)存分配與動態(tài)數(shù)組

§6.3指針與函數(shù)

§6.2指針與數(shù)組本章主要介紹的內(nèi)容§6.5案例程序設計第6章利用指針編程§6.1指針的定義與引用指針是C語言中一種非常重要的數(shù)據(jù)類型,也是C語言的重要特色之一。C語言之所以成為目前執(zhí)行效率最高的高級語言,主要得益于指針功能的強大,它可以直接對內(nèi)存中各種不同的數(shù)據(jù)結構進行快速的處理,并能為函數(shù)之間數(shù)據(jù)的傳遞提供簡捷、便利的方法。由于指針是與計算機系統(tǒng)內(nèi)部密切相關的一種處理形式,所以使用指針可編制出簡潔明快、優(yōu)質(zhì)高效的程序。然而,指針又是C語言中最危險的特性之一,如果指針使用不當,將會導致系統(tǒng)崩潰。因此,熟練地掌握和正確地使用指針是至關重要的

。6.1.1指針概念的引出【問題描述6-1】

抗日戰(zhàn)爭時期的上海,地下工作者007號接到上級指令,前去尋找打開密電碼的密鑰(設密鑰為整數(shù))。007號探知的線索是:密鑰藏在一棟廢棄的小樓中,在一個風雨交加的夜晚,007號潛入了小樓,正當007號一籌莫展時,忽然走廊上的電話鈴聲響起,007號毫不遲疑地抓起聽筒,只聽一個陌生的聲音說:“去打開315號”房間,那里有線索”。007號立即上樓,打開315房間,用電筒一照,只見桌上有一張字條,上面寫了一個數(shù)字:715。007號眼睛一亮,迅速找到715號房間,取出重要密鑰“10111”,完成了任務。6.1.1指針概念的引出一、問題分析

如果我們把小樓看成是一個存儲器,把小樓中的房間看成存儲單元,把房間號看成是存儲單元的地址(簡稱為存儲地址)。那么,存儲地址315的存儲區(qū)存放的內(nèi)容為715,而存儲地址715的存儲區(qū)存放的內(nèi)容為10111。如果用變量p代表存儲地址為315的存儲單元,用變量q代表存儲地址為715的存儲單元,那么變量p保存的內(nèi)容為715,它是變量q對應的存儲單元的地址,在這個存儲單元中保存的內(nèi)容即為10111。這時,我們稱變量p為指針變量,指針變量p和變量q之間的關系如圖6-1所示。二、程序?qū)崿F(xiàn)#include<stdio.h>intmain(void){intkey=10111//變量key存放密鑰int*addr=NULL;//指針變量addr存放內(nèi)存地址addr=&key;//將key的地址賦給addrprintf(“Thekeyis:%d\n”,*addr);printf(“Theaddressofthekey:%d\n”,&key);}[運行程序]Thekeyis:10111Theaddressofthekey:715

6.1.1指針概念的引出6.1.2指針與內(nèi)存地址的關系1、存儲單元與存儲地址存儲器是計算機中的存儲部件,它分為內(nèi)存儲器和外存儲器兩類,內(nèi)存儲器被劃分成許多單元,稱為存儲單元(內(nèi)存單元),每個存儲單元存放一個字節(jié)的數(shù)據(jù)即一個字節(jié)的數(shù)據(jù)在內(nèi)存中存儲時占用一個內(nèi)存單元。為了便于區(qū)分這些存儲單元,必須給每個存儲單元一個編號,這個編號被稱為存儲地址(內(nèi)存地址)。不同類型數(shù)據(jù)所占用的存儲單元數(shù)目不等。例如,整型數(shù)據(jù)占2或者4個單元(16位系統(tǒng)中占2個單元,32位系統(tǒng)中占4個單元),字符數(shù)據(jù)占1個單元,單精度浮點數(shù)據(jù)占用4個單元等(這些內(nèi)容在第2章已有詳細的介紹)。數(shù)據(jù)類型、存儲地址、存儲單元之間的關系如圖6-2所示。圖6-2數(shù)據(jù)類型、存儲地址、存儲單元的關系存儲單元11111111……0011011011010101010101011110011001001001數(shù)據(jù)按照類型存儲字符型C整形數(shù)x所占4個存儲單元的地址號存儲空間存儲地址11111111…… 00000100000000110000001000000001000000006.1.2指針與內(nèi)存地址的關系6.1.2指針與內(nèi)存地址的關系2、存儲地址與變量名對處理大量的數(shù)據(jù)使用有意義的變量來代替內(nèi)存的地址,程序員只需要為待處理的數(shù)據(jù)取一個好記的變量名,這個變量名就代表要處理的數(shù)據(jù)。在內(nèi)存中既沒有形如x,y,z這樣的變量名(對變量的存取都是通過地址進行的),也沒有形如8、9、10這樣的數(shù)據(jù)(二進制數(shù))。例如“printf(“%f”,x);”的執(zhí)行是根據(jù)變量名與地址的對應關系找到變量的存儲地址0012FF02,然后從0012FF02開始的字節(jié)中讀出數(shù)據(jù)(00001011),將它輸出。又如“scanf(“%f”,&x);”的執(zhí)行是根據(jù)&地址操作,把從鍵盤輸入的數(shù)據(jù)送到地址為0012FF02開始的存儲單元中。6.1.2指針與內(nèi)存地址的關系3.C語言與指針

C語言中使用“指針”來表示“變量的地址”或“存儲單元的地址”。通過編譯系統(tǒng)編譯后,將指針與變量的地址和變量的值形成一一對應關系4、指針與指針變量指針是一個靜態(tài)的概念,一個變量在內(nèi)存中的地址稱為這個變量的指針。例如圖6-3中,變量x的地址0012FF02就是變量x的指針,變量y的地址0012FF04就是變量y的指針5、指針與函數(shù)指針不但可以指示變量在內(nèi)存中的位置,還可以指示數(shù)據(jù)和函數(shù)在內(nèi)存中的位置。6.1.3指針變量的定義與初始化1、指針變量的定義<類型標識符>*<指針變量名1>,*<指針變量名2>

其中,[<類型標識符>表示該指針變量所指向的變量的數(shù)據(jù)類型,稱為指針變量的基類型。例如:int*p1,*p2;2、指針變量的初始化指針變量初始化是給已定義了的指針變量賦初值。

<類型標識符>*<指針變量名>=&變量名,…對指針變量進行賦值主要是通過“&”和“*”兩個運算符來實現(xiàn)的。6.1.4指針變量的引用與運算

1、指針變量的定義定義指針變量的目的是通過指針引用內(nèi)存對象。當定義了指針變量并指向?qū)ο蠛?,便可引用指針變量了?/p>

【實例6-1】輸入兩個整數(shù)x1和x2,利用指針將大的數(shù)放到x1中,小的數(shù)放到x2中,最后按x1、x2的順序輸出。[問題分析]

按題意,可設兩個指針變量p1、p2,將x1、x2的地址分別存入p1、p2,當x1<x2時,利用指針變量p1、p2交換x1、x2的值,然后輸出。[程序?qū)崿F(xiàn)]#include<stdio.h>voidmian(){intx1,x2,*p1,p2,tp1=&x1,p2=&x2;printf(“Pleaseinputtwonumber:”);scan(“%d%d”,p1,p2);//利用指針變量輸入x1,x2的值if(x1<x2){t=*p1;*p1=*p2;*p2=t}//利用指針變量實現(xiàn)x1、x2的交換printf(“x1=%d,x2=%d”,x1,x2);}[運行程序]Pleaseinputtwonumber:1020x1=20,x2=106.1.4指針變量的引用與運算6.1.4指針變量的引用與運算2、指針變量的運算

指針是一種特殊的變量,它的運算實際上是地址的運算,指針變量所允許的運算有3種。⑴賦值運算:主要體現(xiàn)在兩個方面:一是用于指針變量的初始化,其次是進行簡單的自加或自減運算。⑵算術運算:指針的算術運算有兩種,一種是指針和整數(shù)的計算,另一種是指針和指針之間的計算。⑶關系運算:是兩個指針所指的變量在內(nèi)存中的位置關系。在一定條件下,兩個指針可以相比較?!?.2指針與數(shù)組6.2.1一維數(shù)組的指針表示1、使指針指向數(shù)組元素將指針指向一維數(shù)組元素的方法有幾種,可以概括為以下2個步驟:①

說明指針變量和數(shù)組名,其一般形式為:

<類型標識符>*<指針變量名>=<數(shù)組名>[常量表達式];②

使指針指向數(shù)組,其一般表達式為:

<指針變量名>=&數(shù)組名[];/<指針變量名>=<數(shù)組名>

2、利用指針引用數(shù)組元素

數(shù)組名為數(shù)組的首地址常量,用它組成的地址表達式可以表示所有元素的地址。6.2.1一維數(shù)組的指針表示【實例6-2】設有一個整型數(shù)組a,有10個元素,要求輸出數(shù)組中的全部元素。[問題分析]

引用數(shù)組中各元素的值有3種方法,它們各有其有特點。為了便于進行比較,下面采用3種不同的表示法編程。#include<stdio.h>//*程序1:使用數(shù)組下標法voidmian(){inta[10],i;printf(“請輸入10個數(shù):1234567910\n”);for(i=0;i<10;i++)scanf(“%d”,&a[i]);for(i=0;i<10;i++)printf(“%3d”,a[i]);//數(shù)組元素用數(shù)組名和下標表示printf(“\n”);}/*程序2:使用指針變量法輸出數(shù)組元素*/#include<stdio.h>voidmian(){inta[10],i;printf(“請輸入10個數(shù):1234567910\n”);for(i=0;i<10;i++)scanf(“%d”,&a[i]);for(i=0;i<10;i++)printf(“%3d”,*(a+i));//通過數(shù)組名和元素序號計算元素地址printf(“\n”);}6.2.1一維數(shù)組的指針表示/*程序3:使用地址法輸出數(shù)組元素*/#include<stdio.h>voidmian(){inta[10],i,*p;printf(“請輸入10個數(shù):1234567910\n”);for(i=0;i<10;i++)scanf(“%d”,&a[i]);for(p=a;p<(a+10);p++)printf(“%3d”,*p);//用指針指向當前數(shù)組元素printf(“\n”);}6.2.1一維數(shù)組的指針表示6.2.2二維數(shù)組的指針表示1、二維數(shù)組的地址表示二維數(shù)組是由一維數(shù)組擴展形成的,即一維數(shù)組的每一個元素作為數(shù)組名形成一行數(shù)組,各行數(shù)組的元素個數(shù)相同,是二維數(shù)組的列數(shù)。例如二維數(shù)組inta[3][4],它是由一維數(shù)組inta[3]擴展形成,即以a[0]、a[1]、a[2]為數(shù)組名(首地址)形成3行一維數(shù)組,元素個數(shù)均為列數(shù)4,因此a[0]、a[l]、[2]為一級指針常量,指向各行的首列(列指針)。例如,0行的a[0]=&a[0][0]指向0行0列。0行有4個元素,它們是a[0][0]、a[0][1]、a[0][2]、a[0][3]。同時a[0]、a[1]、a[2]又是數(shù)組名為a的一維數(shù)組的3個元素,首地址a=&a[0]指向的元素為一級指針常量,因此a為二級指針常量,指向0行(行指針)。因此,二維數(shù)組的地址關系如圖6-4所示。圖6-4二維數(shù)組的地址關系數(shù)組a[2][4]數(shù)組a[3]a[2][0] a[2][1] a[2][2] a[2][3] a[0]

a[1]

a[2] a[0][0] a[0][1] a[0][2] a[0][3] 數(shù)組(a[0])[4]a[1][0] a[1][1] a[1][2] a[1][3] 數(shù)組(a[1])[4]數(shù)組(a[2])[4]aa+1a+26.2.2二維數(shù)組的指針表示行指針(二級)列指針(一級)元素A=&a[0]…*a=a[0]=&a[0][0]*a+1=a[0]+1=&a[0][1]…a[0][0]=*a[0]=**aa[0][1]=*(a[0]+1)=*(*a+1)…A+i=&a[i]…*(a+i)=a[i]=&a[i][0]*(a+i)+1=a[i]+1=&a[i][1]…a[i][0]=*a[i]=**(a+i)a[i][1]=*(a[i]+1)=*(*(a+i)+1)…表6-2行指針、列指針與元素的對應關系6.2.2二維數(shù)組的指針表示6.2.2二維數(shù)組的指針表示【實例6-3】輸出二維數(shù)組的地址和元素值,程序代碼如下:#include<stdio.h>voidmain(void){inta[3l[4l={1,2,3,4,5,6,7,8,9,10,11,12};printf(“%u,%u\”,a,*a);//0行首地址和0行0列首地址printf(“%u,%u\”,a+1,*a+1);//1行首地址和0行l(wèi)列首地址printf(“%u,%u\”,a,&a[0]);//0行首地址

printf(“%u,%u,%u,%u\”,*(a+1),a[1],&a[1][0]);//1行0列首地址printf(“%u,%u,%u,%u\”,*(*(a+1)+2),*(a[1]+2),a[1][2]);}[運行程序]

1310544,13105441310560,13105481310544,13105441310560,1310560,13105607,7,76.2.2二維數(shù)組的指針表示2、二維數(shù)組的指針變量

數(shù)組名為數(shù)組的首地址常量,用它組成的地址表達式可以表示所有元素的地址。因此,用這些地址(指針)的指向操作便可表示所有元素。

<類型標識符>(*指針變量名)[長度];

其中:<類型標識符>為所指向數(shù)組的數(shù)據(jù)類型;“*”表示其后的變量是指針類型,兩邊的括號不能省略,缺省則表示為指針數(shù)組(此時意義完全不同,指針數(shù)組在后面介紹);[長度]表示二維數(shù)組分解為多個一維數(shù)組時,一維數(shù)組的長度,也就是二維數(shù)組的列數(shù)。6.2.2二維數(shù)組的指針表示【實例6-4】輸出二維數(shù)組任意行任意列的元素值。

[問題分析]

定義指向一維數(shù)組的指針變量,按照上面的說明表示二維數(shù)組任意行任意列的元素。[程序?qū)崿F(xiàn)]

#include<stdio.h>{inta[3][4]={1,2,3,4,5,6,7,8,9,10,ll,12};int(*p)[4]=a,row,&col;printf(“輸入任意的行列數(shù):”);scanf(“%d,%d”,&row,&col);prrintf(“a[%d][%d]=%d\n”,row,col,*(*(p+row)+col));}[運行程序]

輸入任意的行列號:1,2a[1][2]=76.2.3字符串的指針表示

1、用字符數(shù)組存放一個字符串把字符串的各字符(包括結束標志‘\0’)依次保存在字符數(shù)組中,利用下標變量或數(shù)組名對數(shù)組操作,輸出時用“%s”格式進行整體輸出?!緦嵗?-5】用字符數(shù)組存放一個字符串,然后輸出該字符串。程序代碼如下:#include<stdio.h>main(){charstring[]=“IloveChina!”;printf(“%s\n”,string);}[運行程序]

IloveChina!2、用字符串指針指向一個字符串用戶可以直接定義指向字符串的指針變量,利用該指針變量對字符串進行操作。3、使用字符串指針變量與字符數(shù)組的區(qū)別【實例6-6】用字符串指針指向一個字符串,程序代碼如下:main()#include<stdio.h>{char*string=“IloveChina!”printf(“%s\n”,string);}[運行程序]IloveChina!6.2.3字符串的指針表示6.2.3字符串的指針表示【實例6-7】為了防止信息被別人輕易竊取,往往把電碼明文通過加密方式變換成秘文。[程序?qū)崿F(xiàn)]

#include<stdio.h>#include<string.h>#defineMAXLINE100voidencrypt(char*)intmain(void){charline[MAXLINE];printf(“Inputthestring:”);gets(line);encrypt(line);printf(“Afterbeenencrypted:%s\n”,line);}voidencrypt(char*s){for(;*s!=’\0’;s++)if(*s==’z’)*s=’a’;else*s=*s+1;}[運行程序]Inputthestring:hellohangzhouAfterbeenencrypted:ifmmp!ibohaipv6.2.3字符串的指針表示6.2.4指針數(shù)組1、指針數(shù)組的定義如果一個數(shù)組的每個元素都是指針變量,這個數(shù)組就是指針數(shù)組。指針數(shù)組的每個元素都指向相同類型的變量,元素的值是所指的變量在內(nèi)存中的地址。在使用指針表示數(shù)組時,必須要聲明。聲明指針數(shù)組的一般形式為:<類型標識符>*<指針數(shù)組名>[下標表達式]

其中:<類型標識符>確定了每個指針指向數(shù)據(jù)的類型;*<指針數(shù)組名>是指針數(shù)組的名稱,同時也是這個數(shù)組的首地址;[下標表達式]給出指針數(shù)組元素的個數(shù)。2、指針數(shù)組的使用針數(shù)組既具有數(shù)組的特點,又具有指針的特點,可以象普通數(shù)組的訪問一樣,通過下標變量來訪問一個指針數(shù)組的元素.【實例6-8】利用指針數(shù)組輸出二維數(shù)組中各元素的值。#include<stdio.h>intmain(){intarr[3][2]={{1,2},{3,4},{5,6}},i,j;int*pa[3];//聲明指針數(shù)組for(i=0;i<3;i++)//A循環(huán)pa[i]=arr[i];for(j=0;j<3;j++)//B循環(huán){for(i=0;i<2;i++,pa[j]++)printf(“arr[=%d,][=%d,]=%d,arr[=%d,][=%d,]=%d\n”,j,i,*pa[j],j,i,*pa[j]);}}[運行程序]arr[0][0]=1arr[0][1]=2arr[1][0]=3arr[1][1]=4arr[2][0]=5arr[2][1]=66.2.4指針數(shù)組【實例6-9】用0~6分別代表星期日至星期六,輸入其中任一數(shù)字時輸出對應的星期名。程序代碼如下:#include<stdio.h>intmain(){intweek;char*weekname[7]={“Sunday”,“Monday”,“Tuesday”,“Wednesday”,“Thursday”,“Friday”,“Saturday”};printf(“PleaseinputweekNo:”);scanf(“%d”,&week);if(week>=0&&week<=7)printf(“WeekNo:%d

%s\n”,week,weekname[week]);elseprintf(“inputerror!!\n”);}[運行程序]Pleaseinputweekno:6↙WeekNo:6—>Saturday6.2.4指針數(shù)組6.2.5多級指針1、多級指針的概念

如果一個指針變量存放的是另一個指針變量的地址,則稱這個指針變量為二級的指針變量,即指向指針的指針,通常把二級以上的指針均稱為多級指針二級指針的一般形式為:

<類型標識符>**<指針變量名>;其中:<類型標識符>為二級指針所指向的變量類型;**<指針變量名>是二級指針的名稱。二級的說明形式與一般指針說明形式相似,只是說明一個二級時需要使用兩個星號。在多級指針的使用中,必須嚴格按照多級指針的含義給指針賦值。一級指針只能普通數(shù)據(jù)的存儲地址,二級指針只能保存一級指針變量的地址,三級指針只能保存二級指針變量的地址。2.多級指針的間接引用【實例6-10】二級指針的使用,程序代碼如下:#include<stdio.h>voidmain(){int*p1,*q1,**p2,i;p1=&i;*p1=100;printf(“%d,”,i);q1=&i;//q1指向變量ip2=&q1;//p2指向一級指針q1,使p2通過p1與i建立聯(lián)系**p2=200;//二級指針的間接訪問,給變量i所在內(nèi)存單元賦值200printf(“%d\n”,i);}[運行程序]100,2006.2.5多級指針§6.3指針與函數(shù)在C語言中,指針與函數(shù)的關系極為密切,在第4章介紹的函數(shù)參數(shù)傳遞和返回值都是簡單數(shù)據(jù)類型。在實際程序設計實踐中經(jīng)常會遇到復雜的參數(shù)傳遞等問題,這樣一些問題都需要指針的支持。利用函數(shù)指針傳遞參數(shù)有多種方式:指針作為函數(shù)的參數(shù)、指針作為函數(shù)的返回值、指向函數(shù)的指針、指針數(shù)組作為函數(shù)的參數(shù)、指針數(shù)組作為函數(shù)main的形參。這一節(jié)討論5個方面的問題:

指針作為函數(shù)的參數(shù)字符串指針作為函數(shù)參數(shù)指針作為函數(shù)的返回值指向函數(shù)的指針帶指針參數(shù)的main函數(shù)6.3.1指針作為函數(shù)的參數(shù)【實例6-11】交換兩個變量的值,用傳地址方式調(diào)用。#include<stdio.h>voidswap(int*a,int*b)//將形式參數(shù)a,b說明為整型指針{int=temp;temp=*a;*a=*b;*b=temp;//間接尋址修改調(diào)用函數(shù)中變量的值prinyf(“*a=%d,*b=%d\n”,*a,*b);}voidmain(){intx=10,y=20;swap(&x,&y);//將主函數(shù)中的x,y的地址傳遞給函數(shù)swapprintf(“x=%d,y=%d\n”,x,y);}[運行程序]*a=20,*b=10x=10,y=206.3.2字符串指針作為函數(shù)參數(shù)【實例6-12】編寫函數(shù)cpystr,用指針方法將字符串2復制到字符串1。主函數(shù)調(diào)用cpystr()實現(xiàn)復制。[問題分析]

將一個字符串從一個函數(shù)傳遞到另一個函數(shù),可以用地址傳遞的方法,即用字符數(shù)組名作為參數(shù)或用指向字符串的指針作為參數(shù)。在被調(diào)函數(shù)中可以改變字符串的內(nèi)容,在主調(diào)函數(shù)中可以得到改變了的字符串。[程序?qū)崿F(xiàn)]#include<stdio.h>voidcpystr(char*sl,char*s2){while(*s2!=‘\o’)*s1++=*s2++*s1=‘\0’;}6.3.2字符串指針作為函數(shù)參數(shù)voidmain(void){charstrl[20],str2[20];printf(“輸入字符串2:\n”);gets(str2);cpystr(strl,str2);printf(“字符串1是:%s\n”,strl);}[運行程序]輸入字符串2:CLanguage字符串1是:CLanguage6.3.3指針作為函數(shù)的返回值函數(shù)的參數(shù)可以是普通變量、數(shù)組,還可以是指針變量。同樣,函數(shù)的返回值可以是一個整型值、字符值、實型值,還可以是指針值。這種返回指針值的函數(shù),一般定義形式為:

<類型標識符>*<函數(shù)名>(形參列表){函數(shù)體}

其中:函數(shù)名之前加了一個“*”號,表明這是一個指針類型函數(shù),即返回值是一個指針;<類型標識符>表示返回的指針值所指向的數(shù)據(jù)類型。例如:int*fun(intx,inty){…//函數(shù)體}6.3.3指針作為函數(shù)的返回值【實例6-13】利用指針函數(shù)求兩個數(shù)中的最大值,程序如下:#include<stdio.h>int*max(int,int);int*maxp(int*,int*);//函數(shù)聲明,注意形參類型的區(qū)別voidmain(){intx,y,*p;scanf(“%d%d”,&x,ay);p=max(x,y);printf(“\nmax=%d”,*p);p=maxp(&x,&y);printf(“\nmaxp=%d”,*p);}6.3.3指針作為函數(shù)的返回值int*max(inta,intb){if(a>b)return&a;elsereturn&b;}int*maxp(int*a,int*b){return*a>*b>?a:b}[運行程序]56↙max=6maxp=66.3.3指針作為函數(shù)的返回值【實例6-14】指針作為函數(shù)的返回值示例,解密床頭詩。

[問題分析]

所謂藏頭詩,就是將一首詩每一句的第一個字連起來,所組成的內(nèi)容就是該詩的真正含義。[程序?qū)崿F(xiàn)]#include<stdio.h>char*change(chars[][20],chart[]);intmain(void){chars[4][20],t[10],*p;inti;printf(“請輸入藏頭詩:\n”);for(i=0;i<4;i++)scanf(“%3”,s[i]);p=change(s,t);

6.3.3指針作為函數(shù)的返回值printf(“%s\n”,p);}char*change(chars[][20],chart[]);{inti;for(i=0;i<4;i++){t[2*i]=s[i][0];t(2*i+1)=s[i][1];}t[2*i]=’\0’;returnt;}[運行程序]請輸入藏頭詩:一葉輕舟向東流,↙帆稍輕握楊柳手,↙風纖碧波微起舞,↙順水任從雅客悠。↙一帆風順6.3.4指向函數(shù)的指針

x0x1x2x3圖6-7數(shù)值積分示意圖

[問題分析]

對這樣的定積分問題,可將整個求積區(qū)間[a,b]分成n個均勻的小區(qū)間[xi,xi+1](i=1,2,3,…,n),每個小區(qū)間看成一個梯形,用梯形求面積公式計算每個小梯形面積。然后將n個小梯形的面積相加即得到定積分的值,如圖6-7所示?!締栴}描述6-2】編寫一個函數(shù),求下面的幾個定積分的值。6.3.4指向函數(shù)的指針[程序?qū)崿F(xiàn)]#include<stdio.h>#include<math.h>doubleintegral(double(*funp)(),doublea,doubleb)//定義工作函數(shù){doubles,h,y;intn,i;s=((*funp)(a)+(*funp)(b))/2.0;//[(a)+f(b)]/2作為求和的初始值n=1.0;b=(b-a)/n;for(i=1;i<n;i++)s=s+(*funp)(a+i*h);y=s*h;return(y);}doublef(doublex){return(sqrt(4.0-x*x));}//自定義被積函數(shù)voidmain(void){doubles1,s2,s3;s1=integral(sin,0.0,3.1415926/2);s2=integral(cos,0.0,3.1415926/2);s3=integral(f,0.0,3.1415926/2);printf(“s1=%f,s2=%f,s3=%f\n”,s1,s2,s3);}[運行程序]s1=0.999979,s2=0.999979,s3=3.1404176.3.4指向函數(shù)的指針6.3.5帶指針參數(shù)的main函數(shù)main函數(shù)可以帶參數(shù),這個參數(shù)可以認為是main函數(shù)的形式參數(shù)。這個參數(shù)可以認為是main函數(shù)的形式參數(shù)。main函數(shù)的參數(shù)只能有兩個,習慣上將這兩個參數(shù)寫為argc和argv?!緦嵗?-16】main函數(shù)帶參數(shù),程序代碼如下:#include<stdio.h>voidmain(intargc,char*argv[]){while(argc>1)printf(“%s\n”,*++argv);}[運行程序]BASICFoxproFORTRAN§6.4動態(tài)內(nèi)存分配與動態(tài)數(shù)組在C語言程序設計中,變量采用先定義后使用的原則,變量一旦被定義,其內(nèi)存地址及存儲的數(shù)據(jù)類型就確定了。例如整型、實型、指針類型以及數(shù)組類型的變量均在編譯時判斷所需空間的大小并進行存儲空間的分配,運行時不能改變其類型和空間大小,這種方式稱為靜態(tài)內(nèi)存分配。但是在實際的編程中,往往會發(fā)生這種情況,所需的內(nèi)存空間取決于實際輸入的數(shù)據(jù),而無法預先確定。例如一個字處理程序,很難預測用戶到底要輸入多少個字符;在這種情況下,用一般的變量或數(shù)組無法處理。為了解決上述問題,C語言提供了一組內(nèi)存管理函數(shù),這些內(nèi)存管理函數(shù)可根據(jù)需要動態(tài)地分配內(nèi)存空間并且可把不再使用的空間回收待用,為有效地利用內(nèi)存資源提供了手段。數(shù)據(jù)區(qū)棧區(qū)代碼區(qū)堆區(qū)圖6-9程序4種存儲空間示意圖6.4.1動態(tài)內(nèi)存分配計算機的內(nèi)存包括4個部分,分別稱為程序代碼區(qū)、全程數(shù)據(jù)區(qū)、棧區(qū)和堆區(qū),其邏輯結構如圖6-9所示。

數(shù)據(jù)區(qū):存放程序全局或靜態(tài)局部變量,具有最長的生命期。

棧區(qū):存放程序中局部變量或函數(shù)的形式參數(shù)。采用函數(shù)被調(diào)用時自動建立變量,調(diào)用結束時自動刪除變量的管理方式。

代碼區(qū):存放程序可執(zhí)行語句編譯成的機器指令代碼。

堆區(qū):用于動態(tài)數(shù)據(jù)空間的分配,是所有變量都可以自由申請使用的存儲區(qū)域。

C語言對內(nèi)存的動態(tài)分配是通過系統(tǒng)提供的庫函數(shù)malloc、calloc、free和realloc這4個函數(shù)管理實現(xiàn)的。6.4.1動態(tài)內(nèi)存分配1、malloc()函數(shù)

malloc()函數(shù)是在堆區(qū)中(在內(nèi)存的動態(tài)存儲區(qū)中)分配一塊長度為size字節(jié)的連續(xù)區(qū)域。形參size的類型定義為無符號整型數(shù)(不允許為負數(shù))。其一般調(diào)用形式為:

void*malloc(unsignedintsize)

2、calloc()函數(shù)calloc()函數(shù)也用于分配內(nèi)存空間,即在內(nèi)存動態(tài)存儲區(qū)中分配n塊長度為size字節(jié)的連續(xù)區(qū)域。void*calloc(unsignedintnum,unsignedintsize)

3、realloc()函數(shù)如果已經(jīng)通過malloc()或calloc()函數(shù)獲得了動態(tài)空間,需要改變其大小時,可用realloc()函數(shù)重新分配動態(tài)存儲空間。

voidrealloc(void*p,unsignedintsize)6.4.1動態(tài)內(nèi)存分配4、free()函數(shù)用free()函數(shù)釋放p所指向的一塊內(nèi)存空間,p是一個任意類型的指針變量,它指向被釋放區(qū)域的首地址,通常與malloc()函數(shù)配對使用,釋放malloc()函數(shù)申請的動態(tài)內(nèi)存。voidfree(void*p)

【實例6-17】內(nèi)存的動態(tài)分配和釋放,程序代碼如下:#include<stdio.h>#include<stdlib.h>voidmain(void){int*p=NULL;p=(int*)malloc(sizeof(int));*p=100;printf(“%d\n”,*p);free(p);}6.5.2舞伴的搭配4、程序?qū)崿F(xiàn)#include<stdio.h>#definemaxn1000intboy[maxn+1],girl[maxn+1],m,n,c,ans;voidsort(int*a,intsize)//排序過程{inti,j,t;for(i=1;i<=size-1;i++)for(j=i+1;j<=size;j++)if(a[i]>a[j]){t=a[i];a[i]=a[j];a[j]=t;}}6.4.2void類型指針void是ANSI新標準增加的一種特殊的指針類型,可用來定義一個指針變量,但不指定它是指向哪一種具體的類型數(shù)據(jù),只表示指向一個抽象的類型的數(shù)據(jù),即僅提供一個純地址,而不能指向任何具體的對象。

1、void類型指針的定義格式

void*<指針變量名>[=(初始值)]

2、void類型指針的特點

①常用于動態(tài)內(nèi)存分配。

②void指針賦值給其它指針類型的變量前需要類型轉(zhuǎn)換,使之適合于被賦值的變量的類型。③如果一個函數(shù)的形式參數(shù)被定義為無類型指針,則在用實際參數(shù)調(diào)用該函數(shù)時,不需要對實際參數(shù)進行強制轉(zhuǎn)換。④當把void指針賦值給不同基類型的指針變量時,編譯系統(tǒng)會自動進行轉(zhuǎn)換,不必用戶自己進行強制轉(zhuǎn)換。6.4.3動態(tài)數(shù)組C語言允許變量所需的存儲空間在運行時才分配,這種分配方式稱為動態(tài)內(nèi)存分配。靜態(tài)空間可以通過變量名來使用,也可以通過指針變量來使用。如果是動態(tài)空間,則只能通過指針變量來使用,而且動態(tài)分配的空間可以是簡單的單元,如整型單元等,還可以是數(shù)組的空間,利用指針變量同樣可以對動態(tài)數(shù)組空間進行使用。動態(tài)數(shù)組的定義分為3步:①首先定義動態(tài)數(shù)組名為一個指針變量。②利用動態(tài)內(nèi)存分配函數(shù)為該變量分配足夠的數(shù)組成員空間。③使用完后利用動態(tài)內(nèi)存釋放函數(shù)釋放回收空間。6.4.3動態(tài)數(shù)組【實例6-18】

建立動態(tài)數(shù)組,輸入5個學生的成績,另外用一個函數(shù)check檢查其中有無低于60分的;輸出不合格的成績。通過這個簡單程序初步了解怎樣建立內(nèi)存動態(tài)分配區(qū)和使用void指針。[問題分析]

用malloc函數(shù)開辟一個動態(tài)自由區(qū)域,用來存5個學生的成績會得到這個動態(tài)域第1個字節(jié)的地址,它的基類型是void型,用一個基類型為int的指針變量p來指向動態(tài)數(shù)組的各元素,并輸出它們的值。但必須先把malloc函數(shù)返回的void指針轉(zhuǎn)換為整型指針,然后賦給p1。[程序?qū)崿F(xiàn)]#include<stdio.h>#include<stdlib.h>//程序中用了malloc函數(shù),應包含stdlib.hintmain(){voidcheck(int*);//函數(shù)聲明int*p1,i;//pi是int型指針p1=(int*)malloc(5*sizeof(int))for(i=0;i<5;i++)scanf(“%d”,pl+i);//輸入5個學生的成績check(p1);//調(diào)用check函數(shù)}6.4.3動態(tài)數(shù)組voidcheck(int*p)//定義check函數(shù),形參是int*指針{inti;printf(“Theyarefail:”);for(i=0;i<5;i++)if(p[i]<60)printf(“%d”,p[i]);//輸出不合格的成績printf(“\n”);}[運行程序]6798597857Theyarefail:59576.4.3動態(tài)數(shù)組§6.5案例程序設計6.5.1貍貓換太子1、案例描述

傳說中的包公最輝煌的功績是審出了發(fā)生在宮中的一件大案—貍貓換太子案,替宋仁宗皇帝找回了自己的親生母親。那是宋真宗第一個皇后死后的事情。當時,劉妃和李妃都懷了孕。很顯然,誰生了兒子,誰就有可能立為正宮。劉妃久懷嫉妒之心,唯恐李妃生了兒子被立為皇后,于是與宮中總管都堂郭槐定計,在接生婆尤氏的配合下,乘李妃分娩時由于暈血而人事不知之機,將一貍貓剝?nèi)テっ?,換走了剛出世的太子。真宗看到被剝了皮的貍貓,以為李妃產(chǎn)下了一個妖物,將其貶入冷宮。貍貓換太子與指針有什么聯(lián)系呢?將李妃的兒子與貍貓看成是欲交換的內(nèi)容,而其擁有者李妃與貍貓的主人看成指針。6.5.1貍貓換太子2、案例分析如何利用指針完成貍貓換太子?下面的例子傳遞兩個整型指針作函數(shù)參數(shù),實現(xiàn)對所指向的內(nèi)容的交換。3、算法描述

本題不存在算法上的復雜問題,而是通過改變存儲地址來改變變量的值。即temp=*pa;*pa=*pb;*pb=temp4、程序?qū)崿F(xiàn)#include<stdio.h>voidswapl(int*pa,int*pb)voidmain(){inta=10,b=20;printf(“addressofa=%x\taddressofb=%x\b”,&1,&b);printf(“a=%d\tb=%d\n”,a,b);swapl(&a,&b);printf(“a=%d\tb=%d\n”,a,b);}voidswapl(int*pa,int*pb){inttemp;printf(“pa=%=\tpb=%x\n”,pa,pb);printf(“addressofpa=%x\taddressofpb=%x\n”,&pa,&pb);printf(“*pa=%d\t*pb=%d\n”,*pa,*pb);temp=*pa;*pa=*pb;*pb=temp;//*指向的內(nèi)容的交換printf(“pa=%d\t*pb=d\n”,*pa,*pb);}6.5.1貍貓換太子6.5.1貍貓換太子[運行程序]addressofa=12ff7caddressofb=12ff78a=10b=20pa=12ff7cpb=12ff78addressofpa=12ff24addressofpb=12ff28*pa=10*pb=20*pa=20*pb=10a=20b=10

那么,是否只要傳遞地址就一定能完成“貍貓換太子”呢?并不一定,關鍵是看函數(shù)內(nèi)的使用,只有地址的交換改變了變量值的交換,才能使“貍貓換太子”成功。6.5.2舞伴的搭配1、案例描述學校將要舉行一年一度的文藝匯演,張明所在年級決定排練一個舞蹈。為選擇表演者,老師給定如下規(guī)則:為了舞蹈的美觀,當且僅當一男一女的身高之差不超過給定的整數(shù)c時,這兩個人可以成為舞伴進行演出。張明所在年級共有m名男生和n名女生,給定每個人身高(身高是160到190厘米之間的整數(shù)),問最多能有多少對舞蹈者進行演出,要求用指針編程。6.5.2舞伴的搭配2、案例分析在有限的人群中搭配多對舞伴是一組最優(yōu)解,這是一個簡單的貪心思想。例如,有3名女生和3名男生,女生的身高分別為160厘米、170厘米、180厘米,男生的身高分別為170厘米、175厘米、185厘米,c=7厘米。那么最多有2對舞蹈者:可以是女2和男1一組,女3和男2一組,共2組(女1不能和任何男生成為一組),所以在這種情況下2將成為最后的答案。

3、算法描述

用boy[i]表示第i個男生的身高,用girl[i]表示第i個女生的身高。把男生和女生分別按身高從低到高排序:boy[1]≤boy[2]≤…≤boy[m],girl[1]≤girl[2]≤…≤girl[n]6.5.2舞伴的搭配

如果boy[1]比girl[l]矮c以上,就可以不去考慮boy[1],而去考慮boy[2]…boy[m]與girl[1]…girl[n]的搭配情況。同理,如果girl[1]比boy[1]]矮c以上,那么就只需考慮boy[1]…boy[m]與girl[2]…girl[n]的搭配情況。此外,boy[1]與girl[1]身高相差不超過c時,可以證明boy[1]與girl[1]在一起跳舞可以形成一組最優(yōu)解。于是,就有了一個簡單的貪心思想:能配搭時就組成舞伴,否則,將boy或girl的下標后移。6.5.2舞伴的搭配4、程序?qū)崿F(xiàn)#include<stdio.h>#definemaxn1000intboy[maxn+1],girl[maxn+1],m,n,c,ans;voidsort(int*a,intsize)//排序過程{inti,j,t;for(i=1;i<=size-1;i++)for(j=i+1;j<=size;j++)if(a[i]>a[j]){t=a[i];a[i]=a[j];a[j]=t;}}6.5.2舞伴的搭配voidinit(){inti;scanf("%d%d%d",&m,&n,&c);for(i=1;i<=m;i++)scanf("%d",&boy[i]);for(i=1;i<=n;i++)scanf("%d",&girl[i]);sort(boy,m);//將男孩按身高排序sort(girl,n);//將女孩按身高排序}6.5.2舞伴的搭配voidprocess(){inti=1,j=1;while(i<=m&&j<=n){if(abs(boy[i]-girl[j])<=c){ans++;i++;j++;}else//身高不滿足要求,就要換一個比較對象{if(boy[i]<girl[j])i++;elsej++;}}printf("%d",ans);}6.5.2舞伴的搭配main(){init();process();return0;}

[運行程序]輸入信息?輸出信息?請讀者分析和思考。6.5.3猴子選大王1、案例描述山上有50只猴子要選大王,選舉辦法如下:所有猴子從1到50進行編號坐一圈,從第一號開始按順序1,2,…,n連續(xù)報數(shù),凡是報n號的猴子都退出到圈外,照此循環(huán)報數(shù),直到圈內(nèi)只剩下一只猴子時,這只猴子就是大王,輸出大王的編號。要求用指針編程。2、案例分析

該問題使用數(shù)組比較方便,將數(shù)組元素按1到50賦值。出局的猴子賦0值,方便下一次計數(shù)。6.5.3猴子選大王3、算法描述

此題不涉及復雜算法問題,編程的關鍵是數(shù)組的指針表示方法。例如,*(p+i)是p+i所指向的數(shù)據(jù)元素,即p[i];*(p+6)就是p[6]。

4、程序?qū)崿F(xiàn)#include<stdio.h>#include<stdlib.h>#defineN50voidmain(){inti,k,m,n,num[N],*p;system(“cls”);printf(“\n報n號的猴子退出,輸入n=”);6.5.3猴子選大王scanf(“%d”,&n);p=num;for(i=0;i<N;i++)*(p+i)=i+1;i=0;k=0;m=0;while(m<N—1){if(*(p+i)!=0)k++;if(k==n){*(p+i)=0;k=0;m++;}i++;if(i==N)i=0;}while(*p==0)p++;printf(“ThelastoneisNO:%d\n”,*p);}6.5.4約瑟夫問題1、案例描述

已知n個人(編號分別為1,2,3,…,n)按順時針方向圍坐一圈,每人手中持有一個密碼。開始時任選一個正整數(shù)作為報數(shù)的上限m,從編號為1的人開始報數(shù),數(shù)到m的那個人出列,并將他手中的密碼作為新的報數(shù)上限m。此時,他的下一個人又從1開始報數(shù),數(shù)到m的那個人又出列;依此規(guī)律重復下去,求最后剩下的那個人的的最初編號是多少?要求用指針鏈表編程。2、案例分析

約瑟夫環(huán)問題類似于單向鏈環(huán),因此,可建立一個環(huán)形的鏈表結構來解決這個問題。第一個結點的數(shù)值域存放編號1,圍繞一圈,至尾結點的數(shù)值域存放編號n。6.5.4約瑟夫問題從head結點開始

溫馨提示

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

評論

0/150

提交評論