C語言程序設計實例教程課件:指針_第1頁
C語言程序設計實例教程課件:指針_第2頁
C語言程序設計實例教程課件:指針_第3頁
C語言程序設計實例教程課件:指針_第4頁
C語言程序設計實例教程課件:指針_第5頁
已閱讀5頁,還剩82頁未讀, 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

指針指針的概念6.1指針與函數6.2指針與數組6.3動態(tài)內存分配6.436.1指針的概念6.1.1地址與指針在計算機中,正在運行的程序及數據都是存放在內部存儲器(簡稱內存)中的。內存由線性連續(xù)的內存單元組成。為了正確地訪問這些內存單元,計算機系統(tǒng)以字節(jié)為單位對內存單元進行了編號,內存單元的編號就稱為地址。根據一個內存單元的地址(編號)即可準確地找到該內存單元。46.1.1地址與指針通常,一個變量在內存中占用一個存儲空間,而存儲空間的大?。ㄗ止?jié)數)是由變量的類型決定的。例如,char類型的變量占用1個字節(jié)內存單元,double類型的變量占用8個字節(jié)內存單元。如果變量占用多個字節(jié)的內存單元將對應多個編號。為了能正確的訪問變量所代表的存儲空間,C語言規(guī)定將一個變量所占用的存儲空間第1個字節(jié)的地址(即首地址)稱為該變量的地址。

5在編寫程序時,可通過變量名來直接訪問變量所占用的存儲空間。實際上,編譯器在編譯程序時會將變量名轉換為實際的內存地址,編程者一般不必關心變量在內存中具體的地址。例

直接訪問#include<stdio.h>voidmain(){inta=2,b=4,c;c=a*b;}6.1.1地址與指針6在計算機中,地址是用二進制編碼的,因此也可以成為程序處理的數據。為此C語言提了一種特殊的數據類型——指針類型,專門用來處理地址值。指針類型的變量稱為指針變量(簡稱指針),指針是一個其數值為地址的變量,正如char類型的變量用字符作為其數值,而int類型變量的數值是整數,指針中所存放的數值是地址,即內存單元的編號。變量占用的一定的存儲空間,有對應的地址。若程序可以處理變量的地址,就可通過該地址來處理相關變量。例如,假設指針p中存放了另一個整型變量x的地址。通常形象地描述為p“指向”x。6.1.1地址與指針7當要訪問變量x的存儲空間時,除了前面介紹的直接訪問的方式以外,還可以通過指針p來訪問(使用對應的運算符)。其訪問過程是:先訪問(直接訪問)指針p的存儲空間,其中存放的是變量x的地址值,再根據該地址值訪問變量x的存儲空間。這是對變量的存儲空間訪問的另外一種方式稱為間接訪問。在C語言中,指針提供了一種間接訪問其他對象的手段,指針是變量,可以通過賦不同的地址值,使其指向發(fā)生改變。利用這種機制能更靈活方便地實施對各種對象的操作。6.1.1地址與指針86.1.2指針的定義與初始化1.指針的定義指針與其它變量一樣,在使用前必須先定義。指針定義在程序的不同位置,決定了指針的作用范圍。定義指針的一般形式:[存儲類型]數據類型*指針變量名1,*指針變量名2,......;指針和普通變量一樣,也有auto、static、register和extern四種存儲類型,它決定了指針的生存期或作用域;數據類型表示指針所要指向目標變量的數據類型,而不是指針本身的類型。指針類型是由“*”指定的?!?”表示其后定義的是指針變量。指針變量名同樣也遵循標識符的起名規(guī)則。9例

指針定義示例#include<stdio.h>voidmain(){int*p,*q;//表示p、q是指向整型變量的指針變量charc,*s;//表示變量c是字符變量,*s是指向字符變量的指針變量}6.1.2指針的定義與初始化10盡管指針變量的地址值都是整型的,指向不同類型對象的指針變量存儲空間大小也相同。但還是要將指針變量按其指向的對象定義為不同的類型,原因是計算機對于指針的運算是按照定義指針變量時所指向對象類型來進行的。指向不同類型對象的指針在內存中進行移動操作時,其移動的字節(jié)數是不一樣的。6.1.2指針的定義與初始化11例

指向不同類型對象的指針變量存儲空間大小#include<stdio.h>voidmain(){int*pi;//指向整型對象的指針float*pf; //指向單精度浮點型對象的指針char*pc; //指向字符型對象的指針,簡稱字符指針long*pl; //指向長整型對象的指針double*pd; //指向雙精度浮點型對象的指針printf(“pint=%d\n”,sizeof(pi));printf(“pfloat=%d\n”,sizeof(pf));printf(“pchar=%d\n”,sizeof(pc));printf(“plong=%d\n”,sizeof(pl));printf(“pdouble=%d\n”,sizeof(pd));}6.1.2指針的定義與初始化12當指針沒有指向具體類型的數據對象,僅指向內存的某個地址,而該地址所存儲的數據對象的類型也尚未確定,可以定義為void型指針。例如:void*p;void型指針也稱為無指定類型指針。它是一種具有獨特性質的指針,它不能直接用來訪問數據,但可以通過強制類型轉換將它轉換成某種數據類型的指針,然后用它來訪問同類型的對象。6.1.2指針的定義與初始化132.指針的初始化指針初始化是指在定義指針的同時給它賦予合法的初始值。指針初始化的一般形式為:[存儲類型]數據類型*指針變量名=初始值;指針初始化時,合法的初始值可以是一個地址值、0或者NULL。1)地址值由于指針是存放地址的變量,所以初始化時賦予的初值通常是地址值。6.1.2指針的定義與初始化14例指針初始化(地址值)#include<stdio.h>voidmain(){floatf,*p=&f;//&為取地址運算符}6.1.2指針的定義與初始化152)0或NULL指針數值為0稱為空指針值,標準庫專門定義了符號常量NULL表示它(頭文件stdio.h和另外幾個標準庫頭文件中定義)。#defineNULL0將指針初始化為NULL等于將指針初始化為0。數值為0或者NULL的指針稱為空指針。空指針并不是指針的存儲空間為空,而是有著特定的值——零,它是指針的一種狀態(tài),表示指針不指向任何目標變量,即指針變量閑置。為使程序具有良好的可移植性,初始化指針是應該用NULL而不是0。6.1.2指針的定義與初始化16例

指針初始化(0或NULL)#include<stdio.h>voidmain(){int*p=NULL;int*q=0;}6.1.2指針的定義與初始化176.1.3指針的運算指針運算是以指針所存放的地址值為運算量進行的運算。指針運算的實質是地址的計算。C語言具有自己的一套適用于指針、數組等地址計算的規(guī)則化方法。由于許多運算對于地址進行操作是沒有意義的,因此C語言對指針只支持幾種有特定意義的運算。181.基本運算在C語言中,有兩個與指針有關的運算符。1)取地址運算符&其功能是取得操作數的地址。表達式一般格式為:&operand其中:“&”是單目運算符,操作數operand是變量名或數組元素,表達式的值為操作數operand的地址。變量的存儲單元是在編譯時或程序運行時分配的,因此變量的地址要通過取地址運算符“&”獲取。

6.1.3指針的運算19例

取地址運算符&示例#include<stdio.h>voidmain(){inta;floatb;charc;scanf("%d%f%c",&a,&b,&c);}6.1.3指針的運算20取地址運算符&的形式和位操作中的“按位與”運算符相同,但后者是一個二元運算符,編譯器會根據操作數個數自動判別。值得注意的是:①取地址運算符“&”作用在一個變量或數組元素上,就可以得到該變量或數組元素的地址。如有如下定義:inta,d[10];則可用&a或&d[2]得到變量或數組元素的地址。②取地址運算符“&”不能作用到常量、表達式上,如&25,&(x+y)等,是錯誤的。6.1.3指針的運算212)間接訪問運算符*其功能是用來獲取指定地址中的數據。使用格式為:*add其中,“*”是單目運算符,操作數add是地址量,如指針變量名、數組名、變量或數組元素的地址等。表達式的值為操作數所指定地址中的數據。6.1.3指針的運算22例

間接訪問運算符*示例#include<stdio.h>voidmain(){inta=3,*p=&a;//初始化時將變量a的地址存放在指針p中

printf("a=%d\n",a);printf("pa=%d\n",*p);}6.1.3指針的運算232.指針的賦值運算指針變量同普通變量一樣,使用之前不僅要定義,而且必須賦予具體的地址值。指針賦值是將對象(如變量)的地址存入指針變量。能夠給指針賦值的只有:0或NULL、同類型的地址值。6.1.3指針的運算24例

指針賦值示例#include<stdio.h>voidmain(){int*p;p=0; //賦值為0p=NULL; //賦值為NULLintn=10;p=&n; //賦值為變量n的地址,即指向n

int*q;inta[10];q=a; //數組名a也是int指針,即指向數組的首地址q=&a[0]; //賦值為a[0]的存放地址,即指向數組的首地址q=&a[5]; //賦值為a[5]的存放地址,即指向a[5]

doubled=2.5;double*pd;pd=&d; //賦值為變量d的地址,即指向d }6.1.3指針的運算25通過對指針賦予不同的地址值可以讓指針隨時指向不同的變量。例

對指針賦予不同的地址值#include<stdio.h>voidmain(){inta=1,b=2,c=3;int*p; p=&a; //賦值為變量a的地址,即指向a printf(“*p=%d,a=%d\n”,*p,a);p=&b; //賦值為變量b的地址,即指向b printf(“*p=%d,b=%d\n”,*p,b);p=&c; //賦值為變量c的地址,即指向c printf(“*p=%d,c=%d\n”,*p,c);}6.1.3指針的運算26多個指針也可賦相同的地址值,即同時指向同一目標變量。例

多個指針賦相同的地址值#include<stdio.h>voidmain(){intn=5,*p,*q;p=&n; q=p;//相同類型的指針可以賦值

printf(“*p=%d,*q=%d\n”,*p,*q);}6.1.3指針的運算27指針是存放地址值的變量,C語言不支持把任何其它數據如整數(0除外)賦予指針,也不支持類型不同的指針之間相互賦值。下面例子中展示了一些不允許的賦值方式。例6.12無效的賦值指針#include<stdio.h>voidmain(){inta=5,*p=&a;//初始化可以doubleq;*p=&a;//不允許p=10000; //不允許

p=0x0012ff60; //不允許

p=a;//不允許

q=&a;

//不允許

q=p;

//不允許}6.1.3指針的運算283.指針的引用使用指針可以對它所指向目標變量進行間接訪問。程序中凡能正確使用變量名的地方都可以用其指針的等價形式表示,【例6.1】

用指針進行兩個變量值的交換。#include<stdio.h>voidmain(){inta,b,*p,*q,t;p=&a;q=&b;printf("Entertwonumbers:\n");scanf("%d%d",p,q);//利用指針變量輸入a、b的值printf("before:a=%d,b=%d\n",a,b);t=*p;//利用指針變量的間接訪問交換a、b的值*p=*q;*q=t;printf("after:a=%d,b=%d\n",a,b);}6.1.3指針的運算29【例6.2】從鍵盤輸入兩個整數賦給變量a與b,不改變a與b的值,要求按先小后大的順序輸出。#include<stdio.h>voidmain(){inta,b,*p,*p1=&a,*p2=&b;printf("Entertwonumbers:\n");scanf("%d,%d",&a,&b);if(a>b){p=p1;p1=p2;p2=p;}printf("a=%d\tb=%d\n",a,b);printf("min=%d\tmax=%d\n",*p1,*p2);}6.1.3指針的運算30在使用指針變量之前,一定要給該指針賦予確定的地址值、0或NULL。一個沒有賦值的指針其指向目標是不確定的,這種指針被稱為“懸空指針”。使用懸空指針做間接訪問是個嚴重錯誤,常常會破壞內存中其它領域的內容,嚴重時會造成系統(tǒng)失控。例

懸空指針示例#include<stdio.h>voidmain(){int*p,n=3;*p=2;//非法間接訪問}6.1.3指針的運算316.2指針與函數6.2.1指針作函數的參數函數的參數可以是整型、實型、字符型等基本數據類型以及數組,也可以是指針類型。使用指針類型做函數的參數,實際向函數傳遞的是地址值。指針作為函數參數可以把實參的地址傳入到被調函數中,被調函數中對形參的處理時,可以通過指針間接訪問到實參,而實現(xiàn)對實參的處理。因此形參的改變能夠影響實參。從而達到被調函數中形參的改變能夠影響實參的目的。例6.3交換兩個變量的值(傳地址調用)326.2.1指針作函數的參數指針作函數的參數,不僅能保留函數中對實參的修改,而且由于傳遞的是地址,不需要生成實參的副本,因此參數傳遞的效率較高,特別是傳遞“體積”較大的數據,如數組、結構體等。【例6.4】編寫程序,將數組a中的n個整數按相反順序存放。336.2.2函數返回指針在C語言中,函數的返回值不僅可以整型、字符型、實型等數據,還可以是指針類型,即返回值為存儲某種數據的內存地址。返回指針的函數被稱為指針函數。指針函數定義的一般形式:數據類型*函數名(形參表){}這里“*”表示返回值是指針類型,數據類型表示該返回值即指針所指向存儲空間中存放數據的類型。34在指針函數中,返回的地址值可以是變量的地址、指針變量或數組的首地址,還可以是結構體、聯(lián)合體等構造數據類型的首地址。當返回指針變量時,要求該指針是指向全局變量、靜態(tài)局部變量的指針,注意要謹慎使用返回指向自動局部變量的指針。對于返回指針的函數,函數調用后必須要把它的返回值賦給指針類型的變量。6.2.2函數返回指針如:int*ap(intx,inty){int*p;....../*函數體*/returnp;}表示ap是一個返回指針值的指針函數,它返回的指針指向一個整型變量。356.2.3指向函數的指針

在C語言中,函數的函數名表示該函數的存儲首地址,即函數的執(zhí)行入口地址。當調用函數時,程序流程轉移的位置就是函數名給定的入口地址。如果把函數名賦予一個指針變量(指針變量的值就是函數的程序代碼存儲區(qū)的首地址),就可以用該指針來調用函數。這種指針變量稱為指向函數的指針,簡稱為函數指針。它的定義形式如下:數據類型(*指針變量名)(函數參數表);其中:數據類型為函數返回值的類型。由于間接訪問運算符“*”的優(yōu)先級低于運算符“()”,因此前面一對包括“*指針變量名”的園括號“()”不能省,表明定義的是一個指針變量;后面一對園括號“()”表示是專門指向函數的指針,其中的“函數參數表”表示函數的形參個數和類型。注意和返回指針的函數定義形式的區(qū)別。例如:int(*p)();定義了一個指向函數的指針變量p,指針p所指向函數應有int型返回值,并沒有形參。36當給函數指針賦值后,在進行函數調用時即可以通過函數名,也可以通過函數指針。對函數指針進行間接訪問“*”運算時,其結果是使程序控制流程轉移到函數指針所指向的函數入口地址執(zhí)行該函數。函數指針的這一特性與其它數據指針不同,數據指針的間接訪問“*”運算訪問是指定地址的數據。例6.5用函數指針調用函數,求三個數中最大的數6.2.3指向函數的指針

37在C語言中,函數指針的主要作用是作為參數在函數間傳遞函數,實際上傳遞的是函數的執(zhí)行地址,或者說傳遞是函數的調用控制。當函數在兩個函數間傳遞時,主調函數的實參應該是被傳遞函數的函數名,而被調函數的形參是接收函數地址的函數指針。可以給函數指針賦予不同的函數名(函數的入口地址),而調用不同的函數。6.2.3指向函數的指針

386.3指針與數組在C語言中,指針與數組之間有著密切的關系,凡是由數組下標完成的操作皆可用指針來實現(xiàn)。使用指針處理數組可使代碼更緊湊、更靈活,程序運行效率更高。6.3.1指針對數組元素的訪問1.指針與一維數組的關系數組在計算機中被存儲在一個連續(xù)的內存空間。數組中的每一個元素都具有相同的數據類型并分配了相同大小的存儲空間,數組元素的地址等于該元素相對數組首地址的偏移量??梢远x類型合適的指針指向數組元素,即用于指向數組元素的指針類型必須與數組類型相同。如:inta[10];/*定義a為包含10個整型數據的數組*/int*p;/*定義p為指向整型變量的指針*/40例

指向數組元素的指針#include<stdio.h>voidmain(){int*p1,*p2,*p3,*p4;inta[10]={1,2,3,4,5,6,7,8,9,10};p1=&a[0];p2=p1;p3=&a[5];p4=&a[10];//沒有a[10]這個數組元素}注意,指針p4沒指向數組a的數組元素,而是指向數組a最后元素a[9]后面一個位置。系統(tǒng)保證這個地址存在,但通過*p4進行間接訪問是錯誤的。6.3.1指針對數組元素的訪問41當一個指針指向數組中的某個元素時,不但可以通過該指針訪問被指數組元素,還可以通過它訪問數組里的其他元素。C語言規(guī)定:如果指針p已指向數組中的一個元素,則p+1指向同一數組中的下一個元素。數組名表示數組首地址(即數組第一個元素的地址),這個地址是在數組定義時就已確定的且不可更改,所以數組名可以看作是一個常量指針。則a+1指向同一數組中的第2個元素既a[1]。以此類推,如有定義:inta[10],*p=a;當指針p指向數組的首地址時:p+i和a+i(0≤i≤9)表示指向同一數組a中的第i個元素a[i]或者說它們就是a[i]的地址。*(p+i)或*(a+i)(0≤i≤9)表示指針p+i或a+i所指向的數組元素,即a[i]。指針p也可以帶下標表示數組元素,如p[i](0≤i≤9)即表示a[i]。6.3.1指針對數組元素的訪問42當一個指針p指向數組a的首地址時,指針名p和數組名a能夠相互表示、互換使用,對于一維數組,下表總結了對數組元素表示不同方式。數組名a表示指針名p表示第i個元素a[i]*(a+i)p[i]*(p+i)第i個元素的地址&a[i]a+i&p[i]p+i6.3.1指針對數組元素的訪問432.指針訪問數組元素的方法引入指針變量后,不僅可以通過數組名+下標的方式訪問數組元素,也可以通過指針名+偏移量的方式訪問數組元素。一般來說,通過指針名+偏移量的方式訪問數組元素的速度比通過數組名+下標的方式訪問數組元素的速度更快?!纠?.6】輸出數組中的全部元素。(下標法)#include<stdio.h>voidmain(){inta[10],i;for(i=0;i<10;i++)a[i]=i;for(i=0;i<5;i++)printf("a[%d]=%d\n",i,a[i]);}6.3.1指針對數組元素的訪問44數組名指針法,即通過一維數組名+偏移量的方式訪問數組元素。【例6.7】輸出數組中的全部元素。通過數組名計算元素的地址,找出元素的值)#include<stdio.h>voidmain(){inta[10],i;for(i=0;i<10;i++)*(a+i)=i;for(i=0;i<10;i++)printf("a[%d]=%d\n",i,*(a+i));}6.3.1指針對數組元素的訪問45指針名指針法,即通過指向數組首地址的指針名+偏移量的方式訪問數組元素。【例6.8】輸出數組中的全部元素。(用指針變量指向元素)#include<stdio.h>voidmain(){inta[10],i,*p;p=a;for(i=0;i<10;i++)*(p+i)=i;for(i=0;i<10;i++)printf("a[%d]=%d\n",i,*(p+i));}6.3.1指針對數組元素的訪問46指針名下標法,即通過指針名+下標的方式訪問數組元素#include<stdio.h>voidmain(){inta[]={1,2,3,4,5,6,7,8,9,10},*p=a;p[3]=50;//相當于a[3]=50;scanf("%d",&p[5]);//相當于scanf("%d",&a[5]);printf("%d\n",p[8]);//相當于printf("%d\n",a[8]));}6.3.1指針對數組元素的訪問473.指針的算術運算指針的算術運算是指可以進行指針加/減整數運算,指針的自增/自減運算以及同類型指針之間的減法運算,而乘法、除法、求余運算以及指針之間的加法運算等,并無實際意義,也不支持。(1)指針加/減整數運算指針作為地址量加上或減去一個整數n,表示指針當前指向位置的前方或后方第n個數據的位置,表達式的運算結果是一個新的地址值。由于指針可以指向不同數據類型,即數據長度不同的數據,所以這種運算的結果值取決于指針所指向對象的數據類型。6.3.1指針對數組元素的訪問48例如有如下定義:int*p;這里定義了一個指向int類型的指針p,進行加/減整數運算的示意圖如圖所示(圖中一個單元格表示一個字節(jié)的存儲空間)。13ff7013ff7113ff7213ff7313ff7413ff7513ff7613ff7713ff7813ff7913ff7a13ff7b13ff7c13ff7d13ff7e13ff7f13ff80pp-1p-2P+1P+249指針加/減整數運算示例#include<stdio.h>voidmain(){inta[]={2,4,6,8,10,12,14,16,18,20};int*p=&a[5];printf("*(p-2)=%d\n*(p-1)=%d\n",*(p-2),*(p-1));printf("*p=%d\n",*p);printf("*(p+1)=%d\n*(p+2)=%d\n",*(p+1),*(p+2));}6.3.1指針對數組元素的訪問50(2)指針的自增/自減運算指針自增運算“++”和自減運算“--”也是地址運算。指針進行“++”運算后,指針值會發(fā)生變化而指向下一個對象,同樣,指針進行“--”運算后,指針值會發(fā)生變化而指向上一個對象,運算后指針的地址值也取決于它所指向對象的數據類型。6.3.1指針對數組元素的訪問51指針的自增/自減運算也分為前置運算和后置運算,其前置與后置的運算結果是有區(qū)別的,如表所示:指針p的初值表達式運算后p的值運算后表達式的值對象的地址++q下一個對象的地址下一個對象的地址對象的地址q++下一個對象的地址原對象的地址對象的地址--q上一個對象的地址前一個對象的地址對象的地址q--上一個對象的地址原對象的地址6.3.1指針對數組元素的訪問52指針的++和--運算示例#include<stdio.h>voidmain(){inta[]={1,2,3,4,5},*p=a;printf("*p=%d\n",*p);printf("*p++=%d\n",*p++);printf("*++p=%d\n",*++p);printf("(*p)++=%d\n",(*p)++);printf("++(*p)=%d\n",++(*p));}6.3.1指針對數組元素的訪問53(3)兩個同類型指針相減兩個同類型的指針可以相減,其運算結果是兩個指針所指向的地址位置之間所包含的對象個數(也和指針所指向對象的數據類型有關)。兩個指針相減也是地址計算,但結果值不是地址量,而是一個整數(對象個數)。設指針p和q是指向同類型的對象,則p-q運算的結果按下面公式計算得到:6.3.1指針對數組元素的訪問54兩個同類型指針相減示例。#include<stdio.h>voidmain(){floatx[10];float*p,*q;p=&x[2];q=&x[8];printf("q-p=%d\n",q-p);

}6.3.1指針對數組元素的訪問554.指針的關系運算兩個同類型的指針,或者一個指針和一個地址量之間可以進行比較,比較的結果可以反映出兩個地址位置的前后關系。兩個指針相等是指兩個指針同時指向同一位置。例如,設指針p和q指向同類型的對象,有關系表達式:p<q如果p指向的位置在q所指向位置的前方,則該關系表達式的值為1,即為真。6.3.1指針對數組元素的訪問56例

從鍵盤輸入10個整數,然后按逆序將它們打印出來#include<stdio.h>voidmain(){inta[10];int*p=a;for(;p<a+10;p++)/*指針順序向后移動*/scanf("%d",p);for(p--;p>=a;p--)/*指針順序向前移動*/printf("%d",*p);printf("\n");}6.3.1指針對數組元素的訪問57【例6.9】

若有一個數列是升序排列的,現(xiàn)插入一個數要求該數列仍保持升序排列。分析:插入算法思想:先假設定義一個具有n+1個元素的一維整型數組a來存放已從小到大排好序n個整數。即要多一個數組元素用來存放待插入的給定值x。從數組的第一元素a[0]開始,將要插入的給定值x與數組中各元素按順序逐個比較,當找到第一個比給定值x大的數組元素a[i]時(0≤i≤n-1),表示該元素之前即為要插入的位置。找到該插入的位置后,應從數組a倒數第二個元素a[n-1]開始到元素a[i]為止,逐個后移(即將前一個數組元素a[j]的值賦于后一個元素a[j+1],其中n-1≥j≥i)。其目的是要留出一個用于存放給定值x的位置,并保持從元素a[i+1到最后一個元素a[n]的排序順序不變。最后把插入的給定值x賦予數組元素a[i]。如果x比所有的元素值都大則將插入到數組最后的元素中。6.3.1指針對數組元素的訪問586.3.2字符指針在C語言中,可以用字符指針來處理字符數組以及字符串,用字符指針處理字符串更為靈活,使程序運行速度更快、效率更高。1.用字符指針處理字符數組在C語言中字符串是通過字符數組來處理的,同樣也可以使用字符指針來處理字符串。通常用字符指針處理字符串時,是先將字符串存放到字符數組中,然后通過字符指針處理數組元素(字符)的方式處理字符串。字符串指針變量的定義說明與指向字符變量的指針變量說明是相同的。只能按對指針變量的賦值不同來區(qū)別。對指向字符變量的指針變量應賦予該字符變量的地址。596.3.2字符指針【例6.10】

字符串的復制#include<stdio.h>//定義函數實現(xiàn)將字符串str2拷貝到字符串str1中voidstrcopy(char*str1,char*str2){while(*str2!='\0'){ *str1=*str2; str1++; str2++;}*str1='\0';}voidmain(){chars1[30],s2[30];printf("Enterstring:");scanf("%s",s2);strcopy(s1,s2);printf("s1=%s\ns2=%s\n",s1,s2);}602.用字符指針處理字符串常量若定義一個字符指針,并用字符串常量對它初始化,或者用字符串常量直接對它賦值,該指針中就存放了字符串常量的首地址即該指針指向字符串常量。例如有定義:char*st=”Hi,Goodmorning!”;或char*st;st=”Hi,Goodmorning!”;通過上面的定義與賦值。使指針st指向了字符串常量”Hi,Goodmorning!”的首地址,于是,就可以用該指針來處理字符串常量。6.3.2字符指針61字符指針處理字符串常量示例#include<stdio.h>voidmain(){char*a=”Iamastudent”;a=a+7;printf(”%c\n”,*a);printf(”%s\n”,a);}6.3.2字符指針62這里總結一下字符數組、字符串和字符指針的聯(lián)系與區(qū)別:(1)字符數組和字符指針都能實現(xiàn)對字符串的處理。(2)字符數組由元素組成,每個元素中存放一個字符。而字符指針中存放的是字符串的地址。(3)只能對字符數組中的各個元素賦值,而不能用賦值語句對整個字符數組賦值。例如,下列賦值是錯誤的:chars[20];s="Howareyou!";//不允許而對字符指針變量賦的是字符串首地址。例如,下列賦值是合法的:char*p;p="Howareyou!";6.3.2字符指針63(4)字符數組名雖然代表地址,但數組名的值不能改變。例如,下列用法是錯誤的:chars[]="Howareyou!";s=s+4;//不允許printf("%s\n",s);但字符指針變量的值可以改變。例如,下列用法是合法的:char*p="Howareyou!";p=p+4;printf("%s\n",p);(5)可以用下標形式引用指針所指向的字符串中的字符。例如:char*p="Howareyou!";printf("%c\n",p[4]);//相當于*(p+4),輸出字符a6.3.2字符指針64(6)可以通過鍵盤輸入字符串的方式為字符數組輸入字符元素,但不能通過輸入函數讓字符指針變量指向一個字符串。因為由鍵盤輸入的字符串,系統(tǒng)是不分配存儲空間的。例如:chars[100],*p;scanf("%s",s);//可以,定義時已經為字符數組分配了存儲空間scanf("%s",p);//不可以,指針p未指向明確地址strcpy(p,"Hello");//不可以,指針p未指向明確地址p=s;//指針p指向數組ascanf("%s",p);//可以,通過指針p訪問數組astrcpy(p,"Hello");//可以,通過指針p修改數組a的內容6.3.2字符指針65(7)將字符串常量通過賦值語句賦予字符指針后,其中的字符不能被修改。例如:chars[100]="Howareyou!";char*p;p="Howareyou!";s[4]='#';//可以,訪問數組元素,并修改p[4]='#';//不可以,指針p所指向的是字符串常量,不能修改其元素strcpy(p,"Hello");//不可以,指針p所指向的是字符串常量,不能修改6.3.2字符指針666.3.3指向數組的指針在C語言中二維數組可以看成其元素是一維數組的一個一維數組。因此,對二維數組的訪問可以通過指向數組的指針來實現(xiàn)。定義一個指向數組的指針方式為:[存儲類型]數據類型(*指針變量名)[數組長度]其中,由于運算符“[]”比“*”優(yōu)先級更高,指針變量名連同其前面的“*”一定要用圓括號“()”括起來,表示定義的是一個指針。方括號中的數組長度是一個整數,表示指針所指向一維數組的長度,也就是二維數組的列數。例如,有如下定義:inta[3][4];int(*p)[4];p=a;其中:用圓括號“()”將*p括起來,讓p先與*結合,說明p是一個指針,然后才與[4]結合,表示p是一個指向數組的指針,它可指向由4個元素組成的一維數組。676.3.3指向數組的指針【例6.11】用指向數組的指針訪問二維數組示例。#include<stdio.h>voidmain(){inta[3][4]={0,1,2,3,4,5,6,7,8,9,10,11};int(*p)[4];inti,j;p=a;for(i=0;i<3;i++) {for(j=0;j<4;j++)printf("%2d",*(*(p+i)+j)); printf("\n");}}686.3.4指針數組1.指針數組的概念和定義一個數組,若其數組元素均為指針類型,稱為指針數組。指針數組是指針的集合,它的每一個數組元素都是一個指針變量,并且可以指向具有相同的數據類型的目標變量。一維指針數組的定義形式為:[存儲類型]數據類型*指針數組名[數組長度];例如:int*p[4];其中:由于運算符“[]”比“*”優(yōu)先級更高,因此標識符p先與[4]結合,形成p[4]的形式,表示定義一個有4個元素的p數組。p前面“int*”表示此數組是指向int型對象的指針類型,每個數組元素都是一個指針,可以指向一個int型對象。這里要注意與指向數組的指針定義形式的區(qū)別。692.指針數組應用在程序中通常使用指針數組處理多維數組。例如,定義一個二維數組和一個指針數組:inta[2][3],*p[2];其中:二維數組a[2][3]可分解為a[0]和a[1]兩個一維數組,它們各有3個元素。指針數組p由兩個指針p[0]和p[1]組成??梢园岩痪S數組a[0]和a[1]的首地址分別賦予指針p[0]和p[1]。例如:p[0]=a[0];或p[0]=&[0][0];p[1]=a[1];或p[1]=&[1][0];則兩個指針分別指向兩個一維數組,這時通過兩個指針就可以對二維數組中的數據進行處理。根據“*”和“[]”的運算意義和地址計算規(guī)則,a[i][j]、*(a[i]+j)、*(p[i]+j)、p[i][j]是意義相同的表示方法,可以根據需要使用任何一種表示形式?!纠?.12】求二維數組a[M][N]各行的平均值,并將各行的平均值依次存放在數組b[M]中。6.3.4指針數組703.命令行參數指針數組的一個重要應用是作為main()函數的形參。一般在程序中,主函數main()都使用其無參形式。實際上,主函數main()也是可以指定形參的。主函數main()的有參形式:main(intargc,char*argv[])

{…

…}其中:(1)形參argc是命令行中參數的個數(可執(zhí)行文件名本身也算一個)。(2)形參argv是一個字符指針數組,其數組元素是指向實參字符串的指針。元素argv[0]指向第1個實參字符串“文件名”,元素argv[1]指向第2個實參字符串,元素argv[2]指向第3個實參字符串。6.3.4指針數組71運行帶形參的主函數,必須在操作系統(tǒng)狀態(tài)(一般在在DOS狀態(tài))下,輸入帶形參主函數所在的可執(zhí)行文件名,以及所需的實參(字符串),然后回車即可。命令行的一般格式為:可執(zhí)行文件名[實參1

實參2……]輸出命令行參數示例#include<stdio.h>voidmain(intargc,char*argv[]){while(argc-->0)//從第一個實參字符串開始

printf(“%s\n”,*argv++);}在DOS狀態(tài)下運行(文件test.exe所在路徑下),當輸入為:test.exeHelloworld程序將輸出命令行中包括可執(zhí)行文件名在內的以空格分隔的所有字符串(一行輸出一個字符串)。6.3.4指針數組726.3.5指向指針的指針指針是一個其數值為地址的變量,如果指針中存放的是數據對象如普通變量或數組元素的地址,被稱為一級指針(通常簡稱為指針)。指針是變量,系統(tǒng)將為它分配相應大小的存儲空間,也有其內存地址,則該地址也可以成為被處理的對象。如果有變量存放的是指針變量的地址,則該變量稱為指向指針的指針,即二級指針。二級指針并不直接指向數據對象,而是指向一級指針。

732.二級指針的定義二級指針的定義的形式:[存儲類型]數據類型**指針變量名其中,指針變量名前面有兩個“*”,表示是一個二級指針。例如,有以下定義:inta,*pa,**ppa;pa=&a;ppa=&pa;6.3.5指向指針的指針74【例6.14】

用二級指針處理字符串示例。#include<stdio.h>voidmain(){char*name[]={"CProgram","BASIC","ComputerEnglish","Word"};char**p;for(p=name;p<name+4;p++)printf("%s\n",*p);}6.3.5指向指針的指針756.4動態(tài)內存分配當程序中定義了變量或數組以后,系統(tǒng)在程序編譯的時候就會給變量或數組按照其數據類型及大小分配相應的內存單元,這塊內存在程序的整個運行期間都存在。例如定義一個float型數組:floatprice[100];系統(tǒng)在程序編譯的時候就會給數組price分配100*4個字節(jié)的內存空間,首地址就是數組名price的值。76這種分配固定大小的內存分配方法稱之為靜態(tài)內存分配。這種內存分配的方法存在比較嚴重的缺陷,特別是處理某些問題時:在大多數情況下會浪費大量的內存空間,在少數情況下,當你定義的數組不夠大時,可能引起下標越界錯誤,甚至導致嚴重后果。在實際的編程中,往往會發(fā)生這種情況,即所需的內存空間取決于實際輸入的數據,而無法預先確定。對于這種問題,用靜態(tài)內存分配的辦法很難解決。用C語言提供的動態(tài)內存分配就可以解決這種的問題。所謂動態(tài)內存分配就是指在程序執(zhí)行的過程中動態(tài)地分配或者回收存儲空間的內存分配方法。動態(tài)內存分配不象靜態(tài)內存分配方法那樣需要預先分配存儲空間,而是由系統(tǒng)根據程序的需要即時分配,且分配的大小就是程序要求的大小。6.4動態(tài)內存分配77進行動態(tài)內存分配需要以下幾個步驟:(1)要確切地知道需要多少內存空間,以避免存儲空間的浪費。(2)利用C標準庫提供的動態(tài)分配函數來分配所需要的存儲空間。(3)使用指針指向獲得的內存空間,并通過指針在該空間內實施運算或操作。(4)當對動態(tài)分配的內存操作完之后,一定要釋放這一空間。如果不釋放獲得的存儲空間,則可能把內存空間用完而影響到其它數據的存儲。6.4動態(tài)內存分配781.帶計數和清0的動態(tài)內存分配的函數calloc()函數原型:void*calloc(unsignedn,unsignedsize)其中:參數

溫馨提示

  • 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

提交評論