版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
1、第八章 指針指針是C語言里最強(qiáng)大的工具之一,但也是最容易令人困惑的主題。 4本章主要內(nèi)容123什么是指針指針變量的聲明和初始化指針的基本運(yùn)算指針與const限定符5一維數(shù)組與指針6返回值為指針的函數(shù)7指針與字符串8用指針實(shí)現(xiàn)動(dòng)態(tài)內(nèi)存分配8.1 什么是指針程序中: int i=5; float k=10; 內(nèi)存中每個(gè)字節(jié)有一個(gè)編號(hào)-地址.FF70FF74FF7C內(nèi)存0ik 編譯或函數(shù)調(diào)用時(shí)為其分配內(nèi)存單元變量就是一個(gè)用來保存具體值的內(nèi)存塊的名字。 510地址8.1 什么是指針FF70FF74FF8C整型變量i10變量pFF70 變量i的地址:&i有時(shí)候需要獲取并使用程序運(yùn)行中某個(gè)變量的內(nèi)存地址,
2、如何獲取這個(gè)地址、如何存儲(chǔ)這個(gè)地址?將i的地址存入另一個(gè)變量p中可以存儲(chǔ)地址的變量稱為指針變量。 .指針看起來就是地址,但不僅僅是地址信息,還包含類型信息。.指針指針變量內(nèi)存?iFF70i的地址?int i, *p;p = &i ;一個(gè)地址、指針指針變量p 指向變量 i指針變量:存放地址的變量8. 2 指針變量的聲明和初始化pFF70取地址符&指針變量所指向的變量的類型int *pn; pn 是整型指針,指向整型變量float *pa; pa 是浮點(diǎn)型指針,指向浮點(diǎn)型變量char *pc; pc 是字符型指針,指向字符型變量類型名 * 指針變量名指針聲明符聲明指針變量指針變量名是p,不是*p*
3、 是指針聲明符如果聲明指針變量時(shí)不能確定它的指向,可以初始化為NULL。聲明并初始化指針變量int i, *p = &i; int *p = NULL; int i;int *p = &i;等價(jià)于:int i, *p;p = &i;等價(jià)于:最好在聲明指針時(shí)就對(duì)它進(jìn)行初始化。一個(gè)指向不確定的指針是很危險(xiǎn)的,因?yàn)橥ㄟ^指針可以訪問其指向的內(nèi)存區(qū)域,會(huì)造成意外覆蓋內(nèi)存。值為NULL的指針稱為空指針,這意味著,指針并不指向任何地址。在頭文件 stdio.h 中,NULL 定義為常量0。聲明并初始化p指針概念總結(jié)a3&apa3&ap5b&b(1)指針變量也是一個(gè)變量,只不過該變量中存儲(chǔ)的是另一個(gè)對(duì)象的內(nèi)存
4、地址 int a; int *p = &a; p中存的是a的地址(1)指針變量也是一個(gè)變量,只不過該變量中存儲(chǔ)的是另一個(gè)對(duì)象的內(nèi)存地址(2)如果一個(gè)變量存儲(chǔ)另一個(gè)對(duì)象的地址,則稱該變量指向這個(gè)對(duì)象(3)由于指針值是數(shù)據(jù),指針變量可以賦值,所以一個(gè)指針的指向在程序執(zhí)行中可以改變。指針p 在執(zhí)行中某時(shí)刻指向變量a,在另一時(shí)刻也可以指向變量b8. 3 間接訪問運(yùn)算符int n = 100, *pn;pn = &n;*pn=15; 間接運(yùn)算符100nFF7C pn指針FF7C15*直接訪問n:通過變量名訪問,如 n = 15;間接訪問n:通過另一個(gè)變量來訪問,pn中存儲(chǔ)了n的地址,通過pn可以間接訪問
5、n,*pn就是對(duì)n的引用/程序8-1:/觀察并理解如下程序的輸出結(jié)果 int a = 3, *p = NULL; printf(a的地址:%pn, &a); printf(a的值:%dn, a); p = &a; /讓指針變量p指向a printf(np的地址:%pn, &p); printf(p的值:%pn, p); printf(*p的值:%dn, *p); *p=10; /等價(jià)于a=10; printf(na=%d, *p=%dn, a, *p); 試試看:使用指針 a3&ap*p0012FF800012FF7C用格式符%p以十六進(jìn)制格式輸出內(nèi)存地址。變量p也需系統(tǒng)分配內(nèi)存地址,也有內(nèi)存
6、地址 。指針變量p指向a, *p是通過a的地址間接訪問a/分析以下程序的輸出結(jié)果#includeint main() int a = 1, x, y, *p; p = &a; x = (*p)+; y=*p; printf(x=%d,y=%dn,x,y);課堂練習(xí)1:x = (*p)+; +運(yùn)算的對(duì)象是*p,而不是p+后置,先使用再增值,等價(jià)于:x=*p; (*p)+;將 p 所指向的變量值加1/即x=a+; 先使用再增1,即x=a; a+;yxa1FF7Cp*pFF7C1228.4 指針作為函數(shù)的參數(shù) 有了指針的概念,重新思考以下問題: 如何在被調(diào)函數(shù)中改變主調(diào)函數(shù)的局部變量? C語言中,參
7、數(shù)傳遞是“傳值”方式,形參是實(shí)參的副本,因而在被調(diào)函數(shù)中,對(duì)形參的修改不影響實(shí)參變量的值。 為達(dá)到改變變量的目的,需用指針變量作為函數(shù)的形參,將實(shí)參變量的指針傳給形參。此時(shí),在函數(shù)執(zhí)行過程中,通過形參指針,間接訪問被調(diào)函數(shù)中的變量。/以下程序不能實(shí)現(xiàn)a、b值的互換void swap(int x, int y)int t;t = x;x = y;y = t;int main()int a = 3, b = 5;swap( a, b );printf(%d %dn,a,b); return 0;運(yùn)行結(jié)果:3 5a35bx35y53試試看:形參的改變不影響實(shí)參形參變量值的改變不會(huì)影響實(shí)參可以打個(gè)比方
8、,main用傳真方式把a(bǔ)和b的內(nèi)容傳給了swap,swap接到傳真,打印到x和y上,x和y是a和b的副本,x和y的改變不會(huì)影響a和b的內(nèi)容。void swap( int *pa, int *pb) int t; t = *pa; *pa = *pb; *pb=t;int main()int a = 3, b = 5;swap(&a, &b);printf(%d %dn,a,b); return 0;運(yùn)行結(jié)果:5 3a35bpa&a&bpb53t*pa*pb*pa是對(duì)a的引用*pb是對(duì)b的引用通過形參指針變量pa和pb間接訪問并改變了a和b的值打個(gè)比方,是main給swap打電話,告訴他a和b這
9、兩個(gè)原件就在檔案柜的第315(存入pa)、316號(hào)抽屜(存入pb) ,swap直接去315和316號(hào)抽屜,直接訪問和修改的是原件a和b試試看:用指針解決問題#includevoid swap( int *pa, int *pb) int *t; t = pa; pa = pb; pb = t;int main() int a = 3, b = 5; swap(&a, &b); printf(%d %dn, a, b); return 0;運(yùn)行結(jié)果:3 5a35bpa&a&bpb&b&a試試看:為何不能實(shí)現(xiàn)互換函數(shù)調(diào)用結(jié)束時(shí),pa,pb被釋放形參指針變量值的改變不會(huì)影響實(shí)參如何訪問主調(diào)函數(shù)中的變
10、量要通過函數(shù)調(diào)用來改變主調(diào)函數(shù)中某個(gè)變量的值:(1) 在主調(diào)函數(shù)中,將該變量的地址或者指向該變量的指針作為實(shí)參(2) 在被調(diào)函數(shù)中,用指針類型形參接受該變量的指針 (3) 在被調(diào)函數(shù)中,用形參指針間接訪問主調(diào)函數(shù)中的變量。解決問題:計(jì)算日期 輸入年和天數(shù),輸出對(duì)應(yīng)的年、月、日。例如:輸入2000和61,輸出2000-3-1。要求調(diào)用一個(gè)函數(shù)month_day()計(jì)算出月份和日期,并在main()中輸出。問題分析:(1)函數(shù)名只能帶回一個(gè)函數(shù)值(2)一般變量做參數(shù),形參的改變不會(huì)改變實(shí)參main()函數(shù)調(diào)用month_day()需要得到兩個(gè)值,如何實(shí)現(xiàn)?解決方法1:使用全局變量 不推薦解決方法2
11、:使用指針做參數(shù),將main()中兩個(gè)變量的指針傳遞給month_day(), month_day()函數(shù)可以更新main()中的這兩個(gè)變量。/程序8-2void month_day(int year, yearday, *pmonth, *pday);int main () int day, month, year, yearday; scanf (%d%d, &year, &yearday ); month_day (year, yearday, &month, &day ); printf (%d-%d-%d n, year, month, day ); return 0; 程序8-12
12、:計(jì)算日期void month_day ( int year, int yearday, int *pmonth, int *pday) int k, leap; int tab 213 = 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 , 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ; /* 建立閏年判別條件leap */ leap = (year%4 = 0 & year%100 != 0) | year%400 = 0; for ( k = 1; yearday tableapk
13、; k+) /*k中存月份*/ yearday =yearday- tab leapk; /* yearday中存日期 */ *pmonth = k; *pday = yearday;input year and yearday: 2000 61 2000-3-1 monthdaypmonthpday31*pmonth、*pday是對(duì)main()中month和day的引用模仿練習(xí)定義一個(gè)函數(shù)LargestTow(),求數(shù)組a的最大的兩個(gè)值,分別存入形參指針pfirst和psecond所指存儲(chǔ)單元,函數(shù)原型如下:void LargestTow(int a,int n,int *pfirst,in
14、t *psecond)在主函數(shù)中讀入n和n個(gè)整數(shù),調(diào)用上述函數(shù),輸出最大的兩個(gè)值Main()中調(diào)用LargestTow(a, n, &max1, &max2);劉汝佳 算法競(jìng)賽入門經(jīng)典李文新 程序設(shè)計(jì)導(dǎo)引及在線實(shí)踐8.5 指針與const限定符 const限定符的作用是告訴編譯器這個(gè)被const限定的變量的值是不可改寫的。可以使用const限定符來實(shí)現(xiàn)“最小權(quán)限原則”。即給函數(shù)足夠的權(quán)限,使其可以訪問形參中的數(shù)據(jù),以完成特定的功能,但不要給太多的權(quán)限。 const不僅可以限定變量(包括指針變量)不可以改寫,也可限定指針變量所指對(duì)象不可改寫。const與指針變量有多種結(jié)合方式:1指向可變數(shù)據(jù)的可
15、變指針2指向常量數(shù)據(jù)的可變指針3指向可變數(shù)據(jù)的指針常量4指向常量數(shù)據(jù)的指針常量1指向可變數(shù)據(jù)的可變指針/程序8-3: 使用一個(gè)指向可變數(shù)據(jù)的指針變量#includeint main(void) int x = 3, y = 5; /聲明prt是一個(gè)指向可變數(shù)據(jù)的指針變量 int *ptr = &x; *ptr = 10; /合法,ptr指向可變數(shù)據(jù) ptr = &y; /合法,ptr是一個(gè)指針變量,可以改變指向 return 0;2指向常量數(shù)據(jù)的可變指針/*程序8-4: 一個(gè)指向常量數(shù)據(jù)的指針變量 */#includeint main(void) int x = 3, y = 5; /聲明pr
16、t是一個(gè)指向常量數(shù)據(jù)的指針變量 const int *ptr = &x; *ptr = 10; /非法,因已限定ptr指向?qū)ο鬄槌A?x = 10; /合法 ptr = &y; /合法,ptr是一個(gè)指針變量,可以改變指向 return 0; const int *ptr ; 將ptr聲明為const int *類型,該聲明從右向左念做“ptr是一個(gè)指針,指向int常量”。該指針可以改變指向,但不能改變其所指向的對(duì)象的值。3指向可變數(shù)據(jù)的指針常量/*程序8-5: 一個(gè)指向可變數(shù)據(jù)的指針常量 */#includeint main(void) int x = 3, y = 5; /聲明prt是一個(gè)指
17、向常量數(shù)據(jù)的指針變量 int *const ptr = &x; *ptr = 10; /合法, const限定ptr,沒有限定其所指對(duì)象 ptr = &y; /非法,const限定ptr是一個(gè)常量,不可改變指向 return 0; int *const ptr = &x ; 將ptr聲明為int *const類型,該聲明從右向左念做“ptr是一個(gè)指針常量,指向一個(gè)int數(shù)據(jù)”。Const限定該指針的值,但沒有限定其所指對(duì)象。4指向常量數(shù)據(jù)的指針常量/*程序8-6: 一個(gè)指向常量數(shù)據(jù)的指針常量 */#includeint main(void) int x = 3, y = 5; /聲明prt是一
18、個(gè)指向常量數(shù)據(jù)的指針變量 const int *const ptr = &x; *ptr = 10; /非法, const限定*ptr,不可改變 ptr = &y; /非法,const限定ptr是,不可改變指向 return 0; const int *const ptr = &x ; 這個(gè)定義從右向左讀作“ptr是一個(gè)指針常量、指向一個(gè)整型常量”。8.6 指針與數(shù)組在語言中,指針和數(shù)組有著緊密的聯(lián)系,凡是由數(shù)組下標(biāo)完成的操作皆可用指針來實(shí)現(xiàn)。與指針有關(guān)的算術(shù)運(yùn)算 指針與數(shù)組的關(guān)系數(shù)組作為函數(shù)參數(shù)的本質(zhì)a3&ap1&ap2*p1 *p2int a = 3, *p1, *p2;p1 = &a;
19、p1 指向 ap2 = p1; p2 也指向 a相同類型的指針才能相互賦值8.6.1 指針的算術(shù)運(yùn)算和關(guān)系運(yùn)算賦值運(yùn)算指針的運(yùn)算就是地址的運(yùn)算。由于這一特點(diǎn),指針運(yùn)算不同于普通變量,它只允許有限的幾種運(yùn)算。 試試看:讓指針加1 double arr4 = 1.5, 2, 3, 4; double *p; p = &arr0; printf(p中存儲(chǔ)的值:%pn, p); printf(p所指變量的值:%.1fnn, *p); p = p + 1; printf(p自增1后:n); printf(“p中存儲(chǔ)的值:%pn, p); printf(p所指變量的值:%.1fn, *p); p所指變量的
20、值:2 p中的值:0012FF78arr0.1.52 p中的值:0012FF70 p所指變量的值:1.5arr1 p p程序8-7:分析如下程序的輸出結(jié)果一個(gè)指針p加上一個(gè)整數(shù)j:將指向p所指元素后的第j個(gè)該類型的元素。若有:p=&arri; 則指針p+j將指向ai+j,指針p-j將指向ai-j, 。分析上例: p 的值:0012FF70,是a0的地址p+1的值:0012FF78,是a1的地址為什么指針加1,地址加8?因?yàn)閜是指向?qū)嵭蛿?shù)據(jù)的指針,一個(gè)元素占8個(gè)字節(jié)。編譯器知道,給指針加1就表示要訪問該類型的下一個(gè)元素。這就是為什么聲明指針時(shí)必須指定指針指向的變量類型。指針加/減一個(gè)整數(shù)試試看:
21、指針相減# include int main () double a2, *p, *q; p = &a0; q = p + 1; printf (%dn, (int) q - (int) p); printf (%dn, q - p); printf(“%dn”, (int*)q (int *)p); return 0; 程序8-8:分析以下程序的輸出結(jié)果8 1a0.1.52a1 p q當(dāng)兩個(gè)指針相減,結(jié)果為兩個(gè)指針之間的距離(用元素個(gè)數(shù)來度量,而不是用字節(jié)來度量)指針p和q之間元素的個(gè)數(shù)兩個(gè)地址之間的字節(jié)數(shù)地址值試試看:指針比較程序8.9: 觀察并分析如下程序的輸出結(jié)果 int a5=2,4
22、,6,8,10, *p, *q; p = &a0; q = &a4; for( ; p= p; q-) printf (%d , *q); *運(yùn)算與+運(yùn)算的結(jié)合for( ; p=q; p+) printf (%d , *p); 還可以寫成如下形式while(p=q) printf (%d , *p+ ); (1) *p+; +運(yùn)算結(jié)合優(yōu)先級(jí)高,等價(jià)于 *(p+); (2) +運(yùn)算的對(duì)象是p(3) +后置,p先參與運(yùn)算,即輸出*p的值,最后p自增1以下程序的輸出結(jié)果#includeint main() int a = 1, x, y, *p; p = &a; x = *p+; /x=*(p+);
23、/x= *p; p+; y = *p; printf(x=%d,y=%dn, x, y);課堂練習(xí)2:如果寫成 x = (*p)+; +運(yùn)算對(duì)象是(*p), 是(*p)自增1*p+,即*(p+)先使用*p,然后p自增1 pFF7CFF78FF74FF70 y x aFF801?FF7C*p1FF80? 8.2.2 指針與數(shù)組的關(guān)系 int a100;系統(tǒng)分配可以存放100個(gè)整數(shù)的內(nèi)存空間,并標(biāo)示為aa0a12864 a通過數(shù)組名可以知道該內(nèi)存空間的大小。 printf (%u , sizeof(a); 將輸出400。數(shù)組名代表一個(gè)地址數(shù)組首元素的地址數(shù)組名a是指向a0的指針。*a是對(duì)a0的引用
24、,printf (“%d ”, *a);將輸出a0的值。1. 下標(biāo)運(yùn)算與指針運(yùn)算for(i=0 ; i100; i+) printf (%d , *(a+i) );a0a12864 aint a100;a是指向首元素(下標(biāo)為0)的指針。a+i則是指向下標(biāo)為i的元素的指針*(a+i)是下標(biāo)為i的元素的引用為簡化書寫,將*(a+i)簡記為ai。ai在編譯時(shí)總是被編譯器改寫為*(a+i)的形式,所以將ai寫成ia也沒錯(cuò) 任何由數(shù)組下標(biāo)來實(shí)現(xiàn)的操作都能用指針來完成 a+1 a+2/源程序8-5# include int main() int i, n, a10, sum = 0; scanf (%d,
25、 &n); for(i = 0; i =0; i-) printf(%d , *(a+i) ); printf(n); return 0; 試試看:不用下標(biāo)實(shí)現(xiàn)數(shù)組操作 輸入: 51 2 3 4 5輸出:5 4 3 2 1輸入n和n個(gè)整數(shù),逆序輸出這n個(gè)整數(shù)。不用下標(biāo)來實(shí)現(xiàn)數(shù)組操作。a+i即ai的地址*(a+i)即對(duì)ai的引用2. 移動(dòng)指針實(shí)現(xiàn)數(shù)組操作int a100, *p;通過移動(dòng)指針p遍歷數(shù)組元素sum = 0;for(p = a; p =a+99; p+) sum = sum + *p; p2884198 a a+1 a+i a+99結(jié)束循環(huán)&a99數(shù)組元素的訪問方法 int a100
26、, *p;p = a; /或p = &a0;關(guān)于第i個(gè)元素的指針,以下寫法等價(jià):a+ip+i&ai&pi 關(guān)于對(duì)第i個(gè)元素的引用,以下寫法等價(jià):*(a+i)*(p+i)aipi 甚至ia也對(duì)無論是下標(biāo)法,還是指針法,盡管表現(xiàn)形式不同,可本質(zhì)都是: *(首址+ 偏移量)/源程序8-10# include int main() int i, n, a10, sum = 0; int *p; scanf (“%d”, &n); / 讀入元素個(gè)數(shù)n /讀入n個(gè)整數(shù) for(i = 0; i = 0; i-) printf (%d , a i); printf (n); /*數(shù)組名/偏移量法*/ for
27、(i = n-1; i = 0; i-) printf (%d , *(a + i); printf (n); /*指針/偏移量法*/ for(i = n-1; i = 0; i-) printf (“%d ”, *(ptr+ i) ); printf (n); 用多種方法訪問數(shù)組元素 /*指針下標(biāo)法*/ for(i = n-1; i = 0; i-) printf (“%d ”, ptr i); printf (n); /*移動(dòng)指針法*/ for(ptr = a+n-1; ptr = a; ptr-) printf (%d , *ptr); printf (n); return 0; 3.
28、數(shù)組名與指針變量的區(qū)別int a100, *p;p = a;a是數(shù)組名,p是指針變量數(shù)組名a中包含數(shù)組的長度信息printf(%dn, sizeof(a) ); /輸出400printf(%dn, sizeof(p) ); /輸出4數(shù)組名a是常量,其值不可改變p = a; /正確a = p; /錯(cuò)誤,數(shù)組名a是常量,不可改變數(shù)組名做為實(shí)參時(shí),因數(shù)組名是指針常量,形參應(yīng)該是指針變量,與實(shí)參類型相同。復(fù)習(xí):函數(shù)實(shí)現(xiàn)數(shù)組求和8.6.3 數(shù)組作函數(shù)參數(shù)的本質(zhì)int sum (int arr , int n) int i, s = 0; for(i=0; in; i+) s += arri; retur
29、n(s); /程序8-7int main() int i; int b5 = 1, 4, 5, 7, 9; printf(%dn, sum(b, 5) ); return 0; 看起來像數(shù)組,本質(zhì)上是指針int *arr形參數(shù)組本質(zhì)上是指針/數(shù)組名b是常量int main(void ) int *rear; int b5 = 1, 4, 5, 7, 9; rear = b + 4; for( ; b = rear; b+) sum = sum + (*b); printf(%dn, sum ); return 0; /形參數(shù)組arr在本質(zhì)上是指針int sum (int arr , int n
30、) int i, s = 0; int *rear = arr+n-1; for( ; arr = rear; arr+) s = s + (*arr); return(s); 正確,形參arr本質(zhì)上是變量,可做循環(huán)變量編譯錯(cuò)誤,數(shù)組名b是常量,其值不可改變數(shù)組名作函數(shù)的實(shí)參,實(shí)參的值就是首元素的地址,調(diào)用時(shí)傳給形參(指針變量),因此,形參也指向?qū)崊?shù)組的首元素。如果改變形參所指向單元的值,就是改變實(shí)參數(shù)組元素的值。或:形參數(shù)組和實(shí)參數(shù)組共用同一段存貯空間數(shù)組做參數(shù)的本質(zhì)17549 a arrFF70FF70int sum (int *arr, int n) int i, s = 0; for
31、(i=0; in; i+) s += arri; return(s);int main(void ) int i; int b5 = 1, 4, 5, 7, 9; printf(%dn, sum(b, 5) ); return 0;b b0b5arrsum(b, 5)b0+b1+.+b4sum(b, 3)b0+b1+b2sum(b+1, 3)b1+b2+b3sum(&b2, 3)b2+b3+b4繼續(xù)了解數(shù)組做參數(shù)的本質(zhì)#include int main(void) int i, a10,n; void reverse(int p , int n); scanf(%d, &n); for(i =
32、 0; i n; i+) scanf(%d, &ai); reverse(a, n); for(i = 0; i n; i+) printf(%dt, ai);return 0; 試試看:將數(shù)組元素逆序存放void reverse(int p , int n) int i, j, t; for(i=0, j=n-1; ij; i+, j-) t = pi; pi = pj; pj = t; 輸入:109 8 7 6 5 4 3 2 1輸出:1 2 3 4 5 6 7 8 9 10指針實(shí)現(xiàn)逆置函數(shù)a0 p 數(shù)組元素 內(nèi)容 指針a1 a9 pj void reverse(int *p, int n
33、) int *pj, t; for(pj = p+n-1; ppj; p+, pj-) t = *p; *p = *pj; *pj = t; int p 加密字符串,輸入一個(gè)由小寫字母組成的字符串,實(shí)現(xiàn)加密,加密方法:a變?yōu)閎、b變?yōu)閏z變?yōu)閍 void encrypt(char *s);int main (void) char line 100; gets(line); encrypt (line); puts(line); return 0;void encrypt ( char *s) for ( ; *s != 0; s+) if (*s = z) *s = a; else *s =
34、*s+1; Input the string:helloAfter being encrypted: ifmmp解決問題:加密字符串8.7 返回值為指針的函數(shù)返回值為指針的函數(shù)是相對(duì)普遍的,尤其在關(guān)于字符串的處理中。返回值為指針的函數(shù),聲明格式如下: 類型 *函數(shù)名(形參聲明列表);例如: int *fun(形參表)該函數(shù)將返回一個(gè)指向int數(shù)據(jù)的指針值試試看:去掉整數(shù)的前導(dǎo)0去掉前導(dǎo)0:輸入一個(gè)不超過100位的整數(shù),去掉其前導(dǎo)0后輸出,如果輸入所有位均為0,則輸出0。要求定義函數(shù)DelLeading0(),該函數(shù)返回去掉前導(dǎo)0后的字符串。DelLeading0()函數(shù)原型如下: char *
35、DelLeading0(char *sptr);該函數(shù)返回指向第一個(gè)非0字符的指針p,即可得到所求字符串。程序8-11: 刪除前導(dǎo)0int main(void) char strN, *ptr; gets(str); ptr = DelLeading0(str); /返回指向第一個(gè)非0字符指針 if(*ptr = 0) /若刪除后為空串,則輸出0 puts(0); else /否則,輸出刪除前導(dǎo)0后的字符串 puts( ptr) ; return 0;#include#define N 110char *DelLeading0(char *sptr);程序8-11: 刪除前導(dǎo)0/*返回指向第一
36、個(gè)非0字符的指針,即去掉前導(dǎo)0后的新字符串*/char *DelLeading0(char *sptr) while(*sptr = 0 ) sptr+; return sptr;若要限定字符串不會(huì)被意外修改,可以用const限定sptr所指對(duì)象的值不可以修改。char *DelLeading0(const char *sptr)8.8 指針與字符串字符串是一種特殊的一維數(shù)組,所以上節(jié)中介紹的方法同樣適用于對(duì)字符串的訪問。字符串的特殊性在于: 字符串的末尾是結(jié)束標(biāo)志 0,所以訪問字符串時(shí)常用結(jié)束標(biāo)志進(jìn)行判斷。char s = abcde; abcdd0s s0 s1 s2 s3 s4 s5字符
37、串知識(shí)回顧(1)C語言沒有字符串?dāng)?shù)據(jù)類型,C語言使用char類型的數(shù)組存儲(chǔ)字符串。(2)字符串的輸入輸出函數(shù) scanf()、printf()、gets()、puts()(3)字符串處理函數(shù) strlen()、strcpy()、strcmp()、strrev()等(4)字符串結(jié)束標(biāo)志0的重要性。8.8.1 字符串的存儲(chǔ)方法字符串在C語言中的存儲(chǔ)方式是從指定地址(如數(shù)組名str)開始, 順序向后一個(gè)字符一個(gè)字符的存儲(chǔ),在字符串最后一個(gè)元素的下一個(gè)元素置為0,表示字符串結(jié)束,之前的內(nèi)容就是字符串的內(nèi)容,這就是字符串的存儲(chǔ)方式. char str = ”abcdefg”; 字符串結(jié)束標(biāo)志0很重要,因
38、為C語言函數(shù)庫中的函數(shù)假定字符串都是以0結(jié)束。字符串常量的存儲(chǔ)方法思考問題:如下函數(shù)printf( max=%dn, max);第一個(gè)參數(shù)是字符串常量max=%dn ,進(jìn)行參數(shù)傳遞時(shí)傳遞的什么?所有字符?太低效了!傳遞的是一個(gè)內(nèi)存地址。你需要明白字符串常量是如何存入的。從本質(zhì)而言,C語言把字符串常量作為字符數(shù)組來處理。編譯器會(huì)為字符串常量分配足夠的內(nèi)存空間來存儲(chǔ)字符串中的字符和額外的一個(gè)0 。這樣,一個(gè)字符串常量在編譯器看來就是一個(gè)char*類型的指針。認(rèn)識(shí)字符串常量#includeint main() printf(%dn, abcd); printf(%dn, abcdefg); retu
39、rn 0;#includeint main() printf(%sn, abcd); printf(%sn, abcde+2); return 0;可見編譯器為這兩個(gè)字符串常量都分配了內(nèi)存。并把一個(gè)字符串常量看做一個(gè)char*類型的指針。在內(nèi)存中由起始地址和0來識(shí)別管理。第一個(gè)printf輸出abcd;第二個(gè)printf輸出cde輸出兩個(gè)不同的內(nèi)存地址例8.12:進(jìn)制轉(zhuǎn)換分析: stdlib.h中的函數(shù)itoa()可完成實(shí)現(xiàn)進(jìn)制轉(zhuǎn)換。 char *itoa(int value, char *string, int radix)將int整型數(shù)轉(zhuǎn)化為radix進(jìn)制一個(gè)字符串,并將值保存在數(shù)組str
40、ing中, radix范圍為2-36 #include#includeint main() int n, r; char str30; scanf(%d%d, &n, &r); itoa(n, str, r); puts(str); return 0;注意:由于itoa函數(shù)不是標(biāo)準(zhǔn)C語言函數(shù),所以不能在所有的編譯器中使用。將一個(gè)十進(jìn)制n(0n109)轉(zhuǎn)換為r(1r17)進(jìn)制數(shù)輸出自定義進(jìn)制轉(zhuǎn)換函數(shù)編程實(shí)現(xiàn)自定義函數(shù) dToR(int n, char str, int r),將十進(jìn)制整數(shù)n轉(zhuǎn)化為r(1r17)進(jìn)制,存入str。dToR的實(shí)現(xiàn):除r取余法13262321201110高低10110難
41、點(diǎn)一:先得到的余數(shù)位權(quán)最低 (1)將得到的余數(shù)依次放入數(shù)組str0、str1.,記下長度len。(2)加上字符串結(jié)束標(biāo)志0(3)將字符串str逆置難點(diǎn)二:若r大于10,需要將數(shù)字10轉(zhuǎn)換為a,11轉(zhuǎn)換為b.11010void dToR(int n, char str, int r) int k = 0, d; char H = abcdef; while(n != 0) d = n % r; strk=Hd; k+; n = n/r; strk = 0; strrev(str);void dToR(int n, char str, int r) int k, d; k = 0; while(n
42、 != 0) d = n % r; if(d 10) strk = d + 0; else strk = d 10 + a; k+; n = n/r; strk = 0; strrev(str);strk= abcdefd;8.8.2 使用指針處理字符串字符串還可以定義為:char *s = “abcde”; 或 char *s; s = “abcde“; 首先在內(nèi)存中為字符串“abcde“ 分配空間,占用6個(gè)字節(jié),然后把該空間的首地址存入指針變量sabcdd0s s0 s1 s2 s3 s4 s5字符串常量 ”abcde” 的值是地址, 故可以賦給指針變量schar sa = array;c
43、har *sp = point;printf(“%sn, sa);printf(%sn, sa+2); printf(%sn, sp+3); printf(%sn, string+1); char sa = array;char *sp = point;printf(“%sn, sa);printf(%sn, sa+2); printf(%sn, sp+3); printf(%sn, string+1); array字符串的輸出:從printf第二個(gè)參數(shù)指向的地址開始順序向后逐字符輸出,直到遇到0;字符串由起始地址和0唯一確定。字符串由起始地址和0唯一確定。raynttring字符串處理技巧決
44、定一個(gè)字符串的關(guān)鍵因素有兩個(gè):起始地址和字符串結(jié)束標(biāo)志0字符串在內(nèi)存中存儲(chǔ)的本質(zhì)就是從一個(gè)內(nèi)存地址開始順序向后,遇到0之前的所有內(nèi)容;在理解了字符串在內(nèi)存中存儲(chǔ)的本質(zhì)之后,可以用字符指針來靈活高效地處理字符串輸入一個(gè)字符串,輸出該字符串的靠后長度為3的子串 ,如何實(shí)現(xiàn)?可使str1 = str+(len-3), len代表str的長度, 也就是把倒數(shù)第三個(gè)字符的地址賦給字符指針str1,這時(shí)如果把str1當(dāng)做一個(gè)字符串來使用,會(huì)發(fā)現(xiàn)它就是”efg” 字符串由起始地址和 0唯一確定例8.13 求指定子串#includeint main()char str100;char str1;int len
45、;gets(str);len = strlen(str);str1 = str + len - 3; /str1指向倒數(shù)第三個(gè)字符puts(str1); /把str1作為一個(gè)字符串輸出return 0;源程序8.13:求指定子串例8.14: 已知一個(gè)字符串表示一個(gè)實(shí)數(shù)(不超過100位) ,請(qǐng)輸出其整數(shù)部分,且輸出不含前導(dǎo)0,但如果該整數(shù)為0,則輸出0。解決問題:實(shí)數(shù)取整分析:(1)去掉整數(shù)部分的前導(dǎo)0時(shí)要注意整數(shù)部分全為0的情況下要保留一個(gè)0。(2)查找小數(shù)點(diǎn),并將其位置置為00例8.14的實(shí)現(xiàn)char *p=str, *q;while(*p = 0)p+;q = strchr(str, .)
46、; /找到小數(shù)點(diǎn)if(q != NULL)/若存在小數(shù)點(diǎn) *q = 0; /將小數(shù)點(diǎn)置為0if(*p = 0) /整數(shù)部分為0 printf(“0n”);else puts(p); q=strchr(str, .);strchr函數(shù)在字符串str中搜索字符.,返回該字符第一出現(xiàn)的內(nèi)存地址,其類型為”char *”例8.15 賬單處理問題描述每到月末,superbin就會(huì)對(duì)這個(gè)月的支出賬單進(jìn)行整理和統(tǒng)計(jì)。如今電腦已經(jīng)普及大學(xué)校園,所以superbin想讓電腦幫忙做這件事情。聰明的你就為superbin編一個(gè)程序來完成這件事情吧輸入第一行是整數(shù)n (n100)。然后是n行的賬單信息,每一行由事物的
47、名字name和對(duì)應(yīng)的花費(fèi)c組成,長度不超過200。中間會(huì)有一個(gè)或多個(gè)空格,而每一行的開頭和結(jié)尾沒有空格。 0.0 c 1000.0。輸出 輸出總的花費(fèi),小數(shù)點(diǎn)后保留一位數(shù)字。輸入樣例:3Apple 2.3Buy clothes for girl friend 260.5Go to cinema 30輸出樣例:292.8思路分析難點(diǎn)(1)如何將每一行最后的費(fèi)用分離來?(2)把字符串轉(zhuǎn)化為實(shí)數(shù)?難點(diǎn)1的分析:注意到花費(fèi)c在每一行的最后,且因?yàn)槊恳恍械拈_頭和結(jié)尾沒有空格,可以從后向前找第一個(gè)空格,其后的內(nèi)容就是花費(fèi)c。strrchr()可完成該任務(wù)。難點(diǎn)2的分析:將字符串轉(zhuǎn)化為實(shí)數(shù)可以使用stdli
48、b中的函數(shù)atof()實(shí)現(xiàn)實(shí)現(xiàn)過程(1)定義字符數(shù)組str,字符指針p,累加器sum等(2)讀入n(3)sum初始化為0;(4)控制循環(huán)進(jìn)行n次: (4.1)讀入一行字符存入str (4.2)讓p指向倒數(shù)第一個(gè)空格的下一個(gè)位置 (4.3)把字符串p轉(zhuǎn)換成實(shí)數(shù)存入f; (4.4)將f累加到sum中(5)輸出sum的值。int main()int i, n;double f, sum;char strLEN+1, *p;scanf(%d, &n);getchar(); /吃掉整數(shù)后面的回車sum = 0;for(i=0; in; i+)gets(str);p = strrchr(str, ); /
49、從后向前查找空格p+; /指向空格后的數(shù)字f = atof(p); /將字符串p轉(zhuǎn)換為實(shí)數(shù)sum = sum + f;printf(%.1fn, sum);return 0;課下練習(xí):自定義并實(shí)現(xiàn)atof函數(shù),將字符串轉(zhuǎn)換為實(shí)數(shù)#include#include#include#define LEN 2008.8.3.字符數(shù)組與字符指針的區(qū)別 char sa = This is a string;char *sp = This is a string;saThisisastring0spThisisastring0如果要改變數(shù)組sa所代表的字符串,只能改變數(shù)組元素的內(nèi)容,如sa0=t;如果要改變
50、指針sp所代表的字符串,只能改變指針的值,讓它指向新的字符串,不能改變其元素,如sp0=t;非法內(nèi)存訪問。字符串常量”This is a string”不允許修改。字符數(shù)組與字符指針的區(qū)別char sa = This is a string;char *sp = This is a string;問題1:把sa和sp中的 T變成 tsa0 = t; 合法sp0 = t; 非法內(nèi)存訪問。字符串常量不允許被修改應(yīng)該用:char *sp = “this is a string;問題2:把字符串sa和sp的內(nèi)容改為:”Hello”sp = Hello; sa = “Hello”; 非法,數(shù)組名是常量,
51、不能對(duì)它賦值應(yīng)該用 strcpy (sa, Hello);字符指針必須先賦值,后引用定義字符指針后,如果沒有對(duì)它賦值,指針的值不確定。 char *s ;scanf(“%s”, s);char *s, str20;s = str;scanf(“%s”, s);建議定義指針時(shí),先將它的初值置為空char *s = NULL; 危險(xiǎn)!不要引用未賦值的指針“野指針”char *s=“Happy”; /正確思路分析: 輸入的實(shí)數(shù)位數(shù)可能超過19位,顯然用double類型無法表示, 只能用字符串存儲(chǔ)。 顯然需要去掉整數(shù)部分的前導(dǎo)0和小數(shù)部分的末尾0,然后調(diào)用字符串比較函數(shù)判斷相等。擴(kuò)展練習(xí):判斷實(shí)數(shù)相等從鍵盤輸入兩個(gè)實(shí)數(shù),位數(shù)不超過200,試判斷這兩個(gè)實(shí)數(shù)是否完全相等。注意輸入的實(shí)數(shù)整數(shù)部分可能有前導(dǎo)0,小數(shù)部分可能有末尾0。(1) 去掉前導(dǎo)0char *p = str;while(*p = 0)p+;p即去掉前
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 《客戶跟蹤技巧》課件
- 《chapter固定資產(chǎn)》課件
- 《肩關(guān)節(jié)鏡簡介》課件
- 單位管理制度合并選集【人事管理篇】
- 2024第八屆全國職工職業(yè)技能大賽(網(wǎng)約配送員)網(wǎng)上練兵考試題庫-中(多選題)
- 單位管理制度分享匯編人事管理篇
- 單位管理制度分享大全人力資源管理篇十篇
- 單位管理制度范例選集人力資源管理篇十篇
- 單位管理制度呈現(xiàn)合集人事管理十篇
- 《電子欺騙》課件
- 《馬克思主義基本原理》學(xué)習(xí)通超星期末考試答案章節(jié)答案2024年
- 期末測(cè)試卷(試題)-2024-2025學(xué)年人教PEP版(2024)英語三年級(jí)上冊(cè)
- 《旅游大數(shù)據(jù)》-課程教學(xué)大綱
- 工藝以及質(zhì)量保證措施,工程實(shí)施的重點(diǎn)、難點(diǎn)分析和解決方案
- 七年級(jí)上冊(cè)道德與法治第1-4單元共4個(gè)單元復(fù)習(xí)教學(xué)設(shè)計(jì)
- SY-T 5412-2023 下套管作業(yè)規(guī)程
- 四色安全風(fēng)險(xiǎn)空間分布圖設(shè)計(jì)原則和要求
- 八年級(jí)化學(xué)下冊(cè)期末試卷及答案【完整版】
- 合伙人散伙分家協(xié)議書范文
- 紅色旅游智慧樹知到期末考試答案章節(jié)答案2024年南昌大學(xué)
- CBT3780-1997 管子吊架行業(yè)標(biāo)準(zhǔn)
評(píng)論
0/150
提交評(píng)論