-
C基礎(chǔ)第四天
今天講的是指針和字符串?dāng)?shù)組,不知道是之前留下的印象還是確實(shí)難理解,講到這里的時候思維就自然而然的跟不上了。只能多接觸試試了撮奏。
指針
**1升敲、地址指針的概念
**
** 變量的指針和指向變量的指針
**
** 定義一個指針變量
**
** 指針變量的引用
**
**2昧识、指針變量做函數(shù)參數(shù)
**
3攻臀、數(shù)組指針和指向數(shù)組的指針變量
**
** 指向數(shù)組元素的指針
**
** 通過指針引用數(shù)組元素
**
** 指向多維數(shù)組的指針和指針變量
**
**
**
** 在計(jì)算機(jī)中所有的數(shù)據(jù)都是存放在存儲器中的焕数,存儲器被劃分為一個一個的內(nèi)存單元,為了正確的找到這些信息刨啸,必須為每一個內(nèi)存單元進(jìn)行編號堡赔,內(nèi)存單元的編號就是地址。地址通常也稱為指針设联。
** 舉個具體的例子: 我們?nèi)ャy行存取款善已,銀行的工作人員根據(jù)我們的賬號找到我們的存款單。找到以后進(jìn)行存取款操作离例,并做相關(guān)記錄换团。這里,賬號就是存單指針粘招,存款數(shù)就是存單的內(nèi)容.
**
**
**
**如何定義一個指針變量?
**
**對指針變量的定義包括三個內(nèi)容:
**
**1偎球、指針類型的說明洒扎,定義變量為一個指針變量;
**
**2衰絮、指針變量名袍冷;
**
**3、變量值(指針)所指向的數(shù)據(jù)類型猫牡;
**
**
**
**指針變量定義的一般形式為:
**
** 類型說明符 *變量名胡诗;
**
*注: 表示這個變量為指針變量,變量名即為定義的指針變量名,類型說明符表示本指針?biāo)赶虻淖兞康臄?shù)據(jù)類型煌恢。
**
**例:int *p;
**
**表示p是一個指針變量骇陈,它指向某個整型變量,他的值是某個整型變量的地址瑰抵;p具體指向那一個整型變量你雌,由向p賦值的地址來決定;
**
例:
int *p2; /*p2是指向整型變量的的指針變量*/
float *p3; //p3是指向浮點(diǎn)型變量的指針變量
char *p4; //p4是指向字符型變量的指針變量
**注:一個指針只能指向同類型的變量二汛,p2只能指向浮點(diǎn)型變量 婿崭。
**
**
**
**指針變量的使用:
**
**指針變量和普通變量一樣,使用之前必須要定義說明和賦值肴颊。未經(jīng)賦值的指針變量不能使用氓栈,否則會造成系統(tǒng)混亂,甚至是死機(jī)婿着。
**
**指針變量的賦值只能是地址授瘦,決對不能賦其他任何數(shù)據(jù)。
**
**
**
**兩個相關(guān)的運(yùn)算符: &:取地址運(yùn)算符祟身; *:指針運(yùn)算符(或間接訪址運(yùn)算符)奥务。
**
**C語言中提供了地址運(yùn)算符&,表示變量的地址袜硫;
**
**使用的一般形式為:
**
** &變量名氯葬;
**
**例:&a 表示變量a的地址,&b表示b的地址婉陷,變量本身必須事先說明帚称。
**
**(1)、指針變量的初始化方法
**
int a;
int *p=&a;
**(2)秽澳、指針變量的賦值
**
int a;
int *p;
p=&a;
**不允許把一個賦值給指針變量闯睹,int *p; p=1000; 這樣的做法是錯誤的。
**
被賦值的的指針變量前面不能再加'*'說明符担神,如:*p=&a;
**
**
**我們定義兩個整形變量和一個指針變量:
**
int i=200楼吃,x; int *ip; //i,x中存放的是整型變量,ip中只能存放整型變量的地址妄讯。
**
**
**此時指針變量ip指向整型變量i孩锡,假設(shè)i的地址是1800,這個賦值語句可以理解為
其中*ip和i是等價的亥贸,*p可以完全代替i躬窜,
x=*ip; //ip通過指針間接訪問變量i地址,等價于 x=i;
指針變量和一般的變量一樣炕置,存放的值是可以改變的
int i,j,*p1,*p2;
i='a';
j='b';
p1=&i;
p2=&j;
建立如下的對應(yīng)關(guān)系
這時賦值表達(dá)式p2=p1;//p2與p1指向同一對象i,此時p2就等價于i;*
如果執(zhí)行p2=p1;//表示把p1指向的內(nèi)容賦值給p2;**
#include <stdio.h>
int main()
{
int i=3,j=7;
int *p1,*p2;
p1=&i;
p2=&j;
p2=p1;//分別執(zhí)行p2=p1 和 *p2=*p1
//*p2=*p1;
printf("i=%d,j=%d,*p1=%d,*p2=%d,p1=%p,p2=%p\n",i,j,*p1,*p2,p1,p1);
return 0;
}
*''和'&'使用注意事項(xiàng)
**
*''是指針運(yùn)算符荣挨,間接訪問運(yùn)算符男韧,'&'是取地址運(yùn)算符。
**
**初始化 int *p=&i; 兩個符號必須同時在
**
**賦值時 p=&i; 只能有一個取地址符號在
**
***p和一個整型變量等價默垄,&i和一個指針變量等價此虑。
**
**指針變量作為函數(shù)的參數(shù)
**
**函數(shù)的參數(shù)除了時整型、字符型厕倍、浮點(diǎn)型等寡壮,還可以是指針類型的。
**
指針類型的參數(shù)的作用是把一個變量的地址傳入函數(shù)中讹弯。
#include <stdio.h>
void swap(int *pa,*pb)
{
int temp;
temp=*pa;
*pa=*pb;
*pb=temp;
}
int main()
{
int a,b;
int *pa,*pb;
printf("請輸入a和b的值\n");
printf("a=");
scanf("%d",&a);
printf("b=");
scanf("%d",&b);
pa=&a;
pb=&b;
swap(pa,pb);
printf("a=%d,b=%d",a,b);
return 0;
}
**指針變量的運(yùn)算
**
**1况既、賦值運(yùn)算。
**
** (1)指針變量的初始化和賦值前面?zhèn)€已經(jīng)介紹過了
**
** (2)把一個變量的地址賦值給指向相同數(shù)據(jù)類型的指針變量
**
int a ,*pa;
pa=&a;//把整型變量a的地址復(fù)制給整型指針變量pa
** (3)把一個指針變量的值賦給另一個指針變量(二者類型相同)
**
int a,*pa,*pb;
pa=&a;
pb=pa; //把a(bǔ)的地址賦給pb组民,pa,pb類型相同可以相互賦值棒仍;
** (4)把數(shù)組的首地址賦給指向數(shù)組的指針變量
**
int a[5],*pa;
pa=a;//注意:這里不需要取地址符,a表示數(shù)組的首地址
//等價于 pa=&a[0];數(shù)組第一個元素的地址也是整個數(shù)組的首地址
** (5)把字符串的首地址賦給指向字符類型的指針變量
**
char *p;
p="C program";//這里不是吧整個字符串裝入指針變量臭胜,而是把存放該字符串的字符數(shù)組的首地址裝入指針變量莫其。
** (6)把函數(shù)的入口地址賦給指向函數(shù)的指針變量
**
int (*pf)();
pf=f; //f為函數(shù)名
**2、指針變量的加減法
**
** 指針的加減法主要的運(yùn)算對象是數(shù)組耸三。
**
** 指針變量加上或減去一個整數(shù)n的意義是把指針指向的當(dāng)前位置(某數(shù)組元素)向前向后移動n個位置乱陡。
**
**數(shù)組指針變量移動一個位子,和地址加一減一的概念是不同的仪壮。數(shù)組是不同類型的憨颠,所以數(shù)組元素所占字節(jié)數(shù)也是不同的,指針變量加一积锅,即向后移動一個位置爽彤,表示指針指向下一個數(shù)組元素的首地址。而不是在原地址上加一缚陷。
**
int a[5],*pal
pa=a; //pa指向數(shù)組的第一個元素a[0]
pa=pa+2;//pa向后移動兩個位置适篙,指向數(shù)組的第三個元素,a[2];
**指針變量的加減法只能對數(shù)組指針變量進(jìn)行箫爷,對指向其他數(shù)據(jù)類型的指針變量加減操作是毫無意義的.
**
**3嚷节、兩個指針變量間的運(yùn)算:只有指向同一數(shù)組的兩個指針變量之間才能夠進(jìn)行運(yùn)算,否則是毫無意義的虎锚。
**
** (1)兩指針變量相減:兩指針變量相減所得之差是兩個指針?biāo)冈刂g相差的元素個數(shù)硫痰。實(shí)際上就是兩個指針值(地址)相減的差值再除以該數(shù)組元素的長度。
**
** 注:兩指針之間不能進(jìn)行加操作翁都,加操作毫無意義
**
** (2)兩指針之間的關(guān)系運(yùn)算: 指向同一數(shù)組的兩個指針變量進(jìn)行關(guān)系運(yùn)算可表示它們指向的數(shù)組元素之間的關(guān)系碍论。
**
pf1==pf2;//表示pf1和pf2指向同以數(shù)組元素谅猾。
pf1>pf2;//表示pf1處于高地址位
pf1<pf2;//表示pf1處于低地址位
** 指針變量還可以與0進(jìn)行比較柄慰,
**
** 當(dāng)p為指針變量時鳍悠,p==0;表示p時空指針,它不指向任何變量坐搔。
**
** P藏研!=0; 表時指針 不為空
**
** 空指針是對指針變量賦0得到的概行。
**
** 對指針變量賦0和不賦值是不同的蠢挡。指針變量未賦值,可以是任意值凳忙,是不能使用的业踏,否則將造成意外錯誤。指針變量賦0值以后涧卵,則可以使用勤家,只是它不指向具體的變量而已。
**
例:
int main()
{
int a=10,b=20,s,t,*pa,*pb;
pa=&a;
pb=&b;
s=*pa+*pb;//求和
t=*pa * *pb;//求積
printf("a=%d\nb=%d\na+b=\na*b=%d\n",a,b,a+b,a*b);
printf("s=%d\ns=%d\n",s,t);
}
**數(shù)組指針和指向數(shù)組的指針變量
**
**一個變量有一個地址柳恐,一個數(shù)組包含若干個元素伐脖,每個數(shù)組元素都在內(nèi)存中占用存儲單元,他們都有相應(yīng)的地址乐设。所謂數(shù)組的指針是指數(shù)組的起始地址讼庇,數(shù)組元素的地址是數(shù)組元素的地址。
**
**
**
*指向數(shù)組元素的指針
**
一個數(shù)組是由連續(xù)的一塊內(nèi)存單元組成的近尚。數(shù)組名就是這塊連續(xù)內(nèi)存單元的首地址蠕啄。一個數(shù)組也是由各個數(shù)組元素(下標(biāo)變量)組成的。每個數(shù)組元素按其類型不同占有幾個連續(xù)的內(nèi)存單元肿男。一個數(shù)組元素的首地址也是指它所占有的幾個內(nèi)存單元的首地址定義一個指向數(shù)組元素的指針變量的方法介汹,與以前介紹的指針變量相同。例如:int a[10]舶沛; /不定義a為包含10個整型數(shù)據(jù)的數(shù)組/intp嘹承; /定義p為指向整型變量的指針/應(yīng)當(dāng)注意,因?yàn)閿?shù)組為int型如庭,所以指針變量也應(yīng)為指向int型的指針變量叹卷。下面是對指針變量賦值:p=&a[0];把a(bǔ)[10]元素的地地賦給指針變量p坪它。也就是說骤竹,p指向a數(shù)組的第0號元素.
**
**C語言規(guī)定數(shù)組名代表的就是數(shù)組的首地址,也就是第0號元素的地址往毡,
**
**p=&a[0]; 等價于 p=a;
**
**在定義指針變量時可以賦給初值
**
int *p=&a[0]; 等價于 int *p; p=&a[0]; 同時等價于 int *p=a;
**從圖中的關(guān)系可以卡出 p,a,&a[0]均指向同一單元蒙揣,他們是數(shù)組a的首地址,也就是0號元素a[0]的首地址开瞭。需要注意的是p是變量懒震,a,&a[0]是常量罩息。
**
**
**
**通過指針引用數(shù)組元素。
**
**C語言規(guī)定:如果指針變量p已經(jīng)指向數(shù)組中的一個元素个扰,則P+1指向同數(shù)組的下一個元素瓷炮。
**
**引入指針變量以后我們就可以用兩種方法來訪問數(shù)組元素。
**
如果P的初值為&a[0],則
(1)P+i和a+i就是a[i]的地址递宅,或者說他們指向a數(shù)組的第i個元素娘香;
(2)*(p+i)或*(a+i)就是p+i或a+i所指向的數(shù)組元素,即a[i].例如*(p+5)或*(a+5)就是a[5]办龄;
(3)指向數(shù)組的指針變量也可以帶下標(biāo)烘绽,p[i]與*(p+i)等價;
所以說俐填,引用數(shù)組可以使用下標(biāo)法和指針法
1诀姚、下標(biāo)法:即用a[i]的形式訪問數(shù)組元素,
2玷禽、指針法:即采用*(a+i),*(p+i)形式赫段,用間接訪問的方法來訪問數(shù)組元素,其中a是數(shù)組名矢赁,p是指向數(shù)組的指針變量糯笙,p=a;
int main()
{
int a[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));
}
指針數(shù)組的概念:
一個數(shù)組的所有元素都是指針則是數(shù)組指針,指針數(shù)組是一組有序的指針的集合撩银。
指針數(shù)組的所有元素必須是具有相同存儲類型和指向相同數(shù)據(jù)類型的指針變量给涕。
**指針數(shù)組的一般形式:
類型說明符 * 數(shù)組名[數(shù)組長度];
**
其中類型說明符為指針指向的變量的類型:
*例如:int pa[3];:pa是一個指針數(shù)組,他有三個數(shù)組元素额获,每個元素都是一個指針够庙,指向整型變量。
指向指針的指針:如果一個人指針變量中存放的另一個指針變量的地址抄邀,則稱這個指針變量為指向指針的指針變量耘眨。
int i;
int *p;
int a[n];
int *p[n];
int (*p)[n];
int f();
int *p();
int (*p)();
int **p;
**
**
**二、函數(shù)指針
**
**指向函數(shù)的指針包含了函數(shù)的地址境肾,可以通過它來調(diào)用函數(shù)剔难。聲明格式如下:
類型說明符 (*函數(shù)名)(參數(shù))
**
**其實(shí)這里不能稱為函數(shù)名,應(yīng)該叫做指針的變量名奥喻。
**
**這個特殊的指針指向一個返回整型值的函數(shù)偶宫。
**
**指針的聲明筆削和它指向函數(shù)的聲明保持一致。
**
**指針名和指針運(yùn)算符外面的括號改變了默認(rèn)的運(yùn)算符優(yōu)先級环鲤。
**
**如果沒有圓括號纯趋,就變成了一個返回整型指針的函數(shù)的原型聲明。
**
**
**
*void (fptr)();
**
**
**
**把函數(shù)的地址賦值給函數(shù)指針,可以采用下面兩種形式:
**
**
**
**fptr=&Function; fptr=Function;
**
**
**
**取地址運(yùn)算符&不是必需的吵冒,因?yàn)閱螁我粋€函數(shù)標(biāo)識符就標(biāo)號表示了它的地址唇兑,
**
**如果是函數(shù)調(diào)用,還必須包含一個圓括號括起來的參數(shù)表桦锄。
**
**可以采用如下兩種方式來通過指針調(diào)用函數(shù):
**
*x=(fptr)(); x=fptr();
**
**第二種格式看上去和函數(shù)調(diào)用無異。
**
**但是有些程序員傾向于使用第一種格式蔫耽,因?yàn)樗鞔_指出是通過指針而非函數(shù)名來調(diào)用函數(shù)的结耀。
**
void (*funcp)(); //一個函數(shù)指針
void FileFunc(),EditFunc(); //聲明兩個函數(shù)
main()
{
funcp=FileFunc; //把函數(shù)的地址賦值給函數(shù)指針
(*funcp)(); //利用函數(shù)指針調(diào)用函數(shù)
funcp=EditFunc; //把函數(shù)的地址賦值給函數(shù)指針
(*funcp)(); //利用函數(shù)指針調(diào)用函數(shù)
}
void FileFunc() //FileFunc函數(shù)的定義
{
printf("FileFunc\n");
}
void EditFunc() //EditFunc函數(shù)的定義
{
printf("EditFunc\n");
}
程序輸出為:
FileFunc EditFunc
FileFunc EditFunc
**一、指針函數(shù)
**
** 當(dāng)一個函數(shù)聲明其返回值為一個指針時匙铡,實(shí)際上就是返回一個地址給調(diào)用函數(shù)图甜,
**
** 以用于需要指針或地址的表達(dá)式中。
**
**
格式:
類型說明符 * 函數(shù)名(參數(shù))
**
**當(dāng)然了鳖眼,由于返回的是一個地址黑毅,所以類型說明符一般都是int。
**
**例如:
**
int *GetDate(); int * aaa(int,int);
**函數(shù)返回的是一個地址值钦讳,經(jīng)常使用在返回?cái)?shù)組的某一元素地址上矿瘦。
**
int * GetDate(int wk,int dy);
void main()
{
int wk,dy;
do {
printf("Enter week(1-5)day(1-7)\n");
scanf("%d%d",&wk,&dy);
}while(wk<1||wk>5||dy<1||dy>7);
printf("%d\n",*GetDate(wk,dy));
}
int * GetDate(int wk,int dy)
{
static int calendar[5][7]= {
{1,2,3,4,5,6,7},
{8,9,10,11,12,13,14},
{15,16,17,18,19,20,21},
{22,23,24,25,26,27,28},
{29,30,31,-1} };
return &calendar[wk-1][dy-1];
}
程序應(yīng)該是很好理解的,子函數(shù)返回的是數(shù)組某元素的地址愿卒。輸出的是這個地址里的值缚去。
字符數(shù)組
1、字符數(shù)組的定義:與數(shù)組的定義相同
例如:char c[10].
2琼开、字符數(shù)組的初始化
字符數(shù)組也允許在定義的時候初始化賦值:
例:char c[10]={'C',' ','p','r','o','g','r','a','m'};
賦值后各元素的值為:
c[0]為‘C’易结,
c[1]為‘ ’,
c[2]為'p'
........
c[8]='m';
c[9]默認(rèn)賦值為0;
3柜候、字符數(shù)組的引用
#include <stdio.h>
int main()
{
int i,j;
chara[][5]=
{
{'B','A','S','I','C'},
{'d','B','A','S','E'}
};
for(i=0;i<=1;i++)
{
for(j=0;j<5;j++)
{
printf("%c ",a[i][j]);
}
printf("\n");
}
}
字符串和字符串結(jié)尾標(biāo)志
在C語言中沒有專門的字符串變量搞动,通常用一個字符數(shù)組來存放一個字符串。當(dāng)把一個字符串存入數(shù)組時渣刷,也把結(jié)束符‘\0’存入數(shù)組鹦肿,并以此作為該字符串的結(jié)束標(biāo)志。有了‘\0’以后辅柴,就不必再用字符數(shù)組的長度來判斷字符串的長度了狮惜。
C語言允許使用字符串的方式對數(shù)組作初始化賦值。
例:char c[]={'C',' ','p','r','o','g','r','a','m'};
可寫為:char c[]={"C program"};或去掉{} 寫為:char c[]="C program";
用字符串賦值要比用字符逐個賦值多占一個字節(jié)碌识,用于存放字符串結(jié)束標(biāo)志'\0'.
'\0'是由C編譯系統(tǒng)自動加上的碾篡,由于采用'\0'結(jié)束標(biāo)志,所以在用字符串賦初值時一般無須指定數(shù)組的長度筏餐,而由系統(tǒng)自行處理开泽。
字符數(shù)組的輸入輸出:
除了上述賦值方法以外還可以使用printf,scanf函數(shù)直接輸入輸出;
int main()
{
char string[]="TIAN YONG";
printf("%s\n",string);
return 0;
}
int main()
{
char str[20];
printf("intput str:");
scanf("%s",str);
printf("%s\n",str);
return 0;
}
空格以后的字符都不能輸出魁瞪。
字符串處理函數(shù):
1:puts()字符串輸出函數(shù)
一般形式:puts(字符數(shù)組名)
功能:把字符數(shù)組中的字符串輸出到顯示器:
int main()
{
char c[]="string666";
puts(c);
return 0;
}
2:gets()字符串輸入函數(shù)
一般格式:gets(字符數(shù)組名)
功能;從標(biāo)準(zhǔn)輸入設(shè)備上輸入一個字符串
int main()
{
cahr st[15];
printf("input st:");
gets(st);
puts(st);
return 0;
}
3:strcat:字符串連接函數(shù)
一般形式:strcat(字符數(shù)組名1穆律,字符數(shù)組名2)
功能:把字符串2中的字符串連接到字符數(shù)組1中字符串后面惠呼,并刪除數(shù)組1中的‘\0’.
例題連接“my nane is XXX”
4:strcpy:字符串拷貝函數(shù)
一般形式:strcpy(字符數(shù)組名1,字符數(shù)組名2)
功能:把字符數(shù)組2中的字符串拷貝到字符數(shù)組1中峦耘。結(jié)束標(biāo)志‘\0’也一同拷貝剔蹋。注意:要求字符數(shù)組1要足夠長,否則不能全部裝入所拷貝的字符串辅髓。
5:strcmp:字符串比較函數(shù)
一般形式:strcmp(字符數(shù)組名1泣崩,字符數(shù)組名2)
按照ASCII嗎順序比較兩個數(shù)組中的字符串,并由函數(shù)返回值返回比較洛口,相等返回0矫付,1>2返回值大于,否則返回值小于0第焰;
6:strlen:測試字符串長度
一般形式:strlen(字符數(shù)組名)
功能:測試字符串的實(shí)際長度(不含字符串結(jié)束標(biāo)志‘\0’)并作為函數(shù)返回值买优。