-
C基礎(chǔ)第四天
今天講的是指針和字符串?dāng)?shù)組,不知道是之前留下的印象還是確實(shí)難理解,講到這里的時(shí)候思維就自然而然的跟不上了。只能多接觸試試了。
指針
**1、地址指針的概念
**
** 變量的指針和指向變量的指針
**
** 定義一個(gè)指針變量
**
** 指針變量的引用
**
**2、指針變量做函數(shù)參數(shù)
**
3、數(shù)組指針和指向數(shù)組的指針變量
**
** 指向數(shù)組元素的指針
**
** 通過指針引用數(shù)組元素
**
** 指向多維數(shù)組的指針和指針變量
**
**
**
** 在計(jì)算機(jī)中所有的數(shù)據(jù)都是存放在存儲(chǔ)器中的,存儲(chǔ)器被劃分為一個(gè)一個(gè)的內(nèi)存單元,為了正確的找到這些信息,必須為每一個(gè)內(nèi)存單元進(jìn)行編號(hào),內(nèi)存單元的編號(hào)就是地址。地址通常也稱為指針。
** 舉個(gè)具體的例子: 我們?nèi)ャy行存取款,銀行的工作人員根據(jù)我們的賬號(hào)找到我們的存款單。找到以后進(jìn)行存取款操作,并做相關(guān)記錄。這里,賬號(hào)就是存單指針,存款數(shù)就是存單的內(nèi)容.
**
**
**
**如何定義一個(gè)指針變量?
**
**對(duì)指針變量的定義包括三個(gè)內(nèi)容:
**
**1、指針類型的說明,定義變量為一個(gè)指針變量;
**
**2、指針變量名;
**
**3、變量值(指針)所指向的數(shù)據(jù)類型;
**
**
**
**指針變量定義的一般形式為:
**
** 類型說明符 *變量名;
**
*注: 表示這個(gè)變量為指針變量,變量名即為定義的指針變量名,類型說明符表示本指針?biāo)赶虻淖兞康臄?shù)據(jù)類型。
**
**例:int *p;
**
**表示p是一個(gè)指針變量,它指向某個(gè)整型變量,他的值是某個(gè)整型變量的地址;p具體指向那一個(gè)整型變量,由向p賦值的地址來決定;
**
例:
int *p2; /*p2是指向整型變量的的指針變量*/
float *p3; //p3是指向浮點(diǎn)型變量的指針變量
char *p4; //p4是指向字符型變量的指針變量
**注:一個(gè)指針只能指向同類型的變量,p2只能指向浮點(diǎn)型變量 。
**
**
**
**指針變量的使用:
**
**指針變量和普通變量一樣,使用之前必須要定義說明和賦值。未經(jīng)賦值的指針變量不能使用,否則會(huì)造成系統(tǒng)混亂,甚至是死機(jī)。
**
**指針變量的賦值只能是地址,決對(duì)不能賦其他任何數(shù)據(jù)。
**
**
**
**兩個(gè)相關(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;
**不允許把一個(gè)賦值給指針變量,int *p; p=1000; 這樣的做法是錯(cuò)誤的。
**
被賦值的的指針變量前面不能再加'*'說明符,如:*p=&a;
**
**
**我們定義兩個(gè)整形變量和一個(gè)指針變量:
**
int i=200,x; int *ip; //i,x中存放的是整型變量,ip中只能存放整型變量的地址。
**
**
**此時(shí)指針變量ip指向整型變量i,假設(shè)i的地址是1800,這個(gè)賦值語句可以理解為
其中*ip和i是等價(jià)的,*p可以完全代替i,
x=*ip; //ip通過指針間接訪問變量i地址,等價(jià)于 x=i;
指針變量和一般的變量一樣,存放的值是可以改變的
int i,j,*p1,*p2;
i='a';
j='b';
p1=&i;
p2=&j;
建立如下的對(duì)應(yīng)關(guān)系
這時(shí)賦值表達(dá)式p2=p1;//p2與p1指向同一對(duì)象i,此時(shí)p2就等價(jià)于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; 兩個(gè)符號(hào)必須同時(shí)在
**
**賦值時(shí) p=&i; 只能有一個(gè)取地址符號(hào)在
**
***p和一個(gè)整型變量等價(jià),&i和一個(gè)指針變量等價(jià)。
**
**指針變量作為函數(shù)的參數(shù)
**
**函數(shù)的參數(shù)除了時(shí)整型、字符型、浮點(diǎn)型等,還可以是指針類型的。
**
指針類型的參數(shù)的作用是把一個(gè)變量的地址傳入函數(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("請(qǐng)輸入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)把一個(gè)變量的地址賦值給指向相同數(shù)據(jù)類型的指針變量
**
int a ,*pa;
pa=&a;//把整型變量a的地址復(fù)制給整型指針變量pa
** (3)把一個(gè)指針變量的值賦給另一個(gè)指針變量(二者類型相同)
**
int a,*pa,*pb;
pa=&a;
pb=pa; //把a(bǔ)的地址賦給pb,pa,pb類型相同可以相互賦值;
** (4)把數(shù)組的首地址賦給指向數(shù)組的指針變量
**
int a[5],*pa;
pa=a;//注意:這里不需要取地址符,a表示數(shù)組的首地址
//等價(jià)于 pa=&a[0];數(shù)組第一個(gè)元素的地址也是整個(gè)數(shù)組的首地址
** (5)把字符串的首地址賦給指向字符類型的指針變量
**
char *p;
p="C program";//這里不是吧整個(gè)字符串裝入指針變量,而是把存放該字符串的字符數(shù)組的首地址裝入指針變量。
** (6)把函數(shù)的入口地址賦給指向函數(shù)的指針變量
**
int (*pf)();
pf=f; //f為函數(shù)名
**2、指針變量的加減法
**
** 指針的加減法主要的運(yùn)算對(duì)象是數(shù)組。
**
** 指針變量加上或減去一個(gè)整數(shù)n的意義是把指針指向的當(dāng)前位置(某數(shù)組元素)向前向后移動(dòng)n個(gè)位置。
**
**數(shù)組指針變量移動(dòng)一個(gè)位子,和地址加一減一的概念是不同的。數(shù)組是不同類型的,所以數(shù)組元素所占字節(jié)數(shù)也是不同的,指針變量加一,即向后移動(dòng)一個(gè)位置,表示指針指向下一個(gè)數(shù)組元素的首地址。而不是在原地址上加一。
**
int a[5],*pal
pa=a; //pa指向數(shù)組的第一個(gè)元素a[0]
pa=pa+2;//pa向后移動(dòng)兩個(gè)位置,指向數(shù)組的第三個(gè)元素,a[2];
**指針變量的加減法只能對(duì)數(shù)組指針變量進(jìn)行,對(duì)指向其他數(shù)據(jù)類型的指針變量加減操作是毫無意義的.
**
**3、兩個(gè)指針變量間的運(yùn)算:只有指向同一數(shù)組的兩個(gè)指針變量之間才能夠進(jìn)行運(yùn)算,否則是毫無意義的。
**
** (1)兩指針變量相減:兩指針變量相減所得之差是兩個(gè)指針?biāo)冈刂g相差的元素個(gè)數(shù)。實(shí)際上就是兩個(gè)指針值(地址)相減的差值再除以該數(shù)組元素的長度。
**
** 注:兩指針之間不能進(jìn)行加操作,加操作毫無意義
**
** (2)兩指針之間的關(guān)系運(yùn)算: 指向同一數(shù)組的兩個(gè)指針變量進(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為指針變量時(shí),p==0;表示p時(shí)空指針,它不指向任何變量。
**
** P!=0; 表時(shí)指針 不為空
**
** 空指針是對(duì)指針變量賦0得到的。
**
** 對(duì)指針變量賦0和不賦值是不同的。指針變量未賦值,可以是任意值,是不能使用的,否則將造成意外錯(cuò)誤。指針變量賦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ù)組的指針變量
**
**一個(gè)變量有一個(gè)地址,一個(gè)數(shù)組包含若干個(gè)元素,每個(gè)數(shù)組元素都在內(nèi)存中占用存儲(chǔ)單元,他們都有相應(yīng)的地址。所謂數(shù)組的指針是指數(shù)組的起始地址,數(shù)組元素的地址是數(shù)組元素的地址。
**
**
**
*指向數(shù)組元素的指針
**
一個(gè)數(shù)組是由連續(xù)的一塊內(nèi)存單元組成的。數(shù)組名就是這塊連續(xù)內(nèi)存單元的首地址。一個(gè)數(shù)組也是由各個(gè)數(shù)組元素(下標(biāo)變量)組成的。每個(gè)數(shù)組元素按其類型不同占有幾個(gè)連續(xù)的內(nèi)存單元。一個(gè)數(shù)組元素的首地址也是指它所占有的幾個(gè)內(nèi)存單元的首地址定義一個(gè)指向數(shù)組元素的指針變量的方法,與以前介紹的指針變量相同。例如:int a[10]; /不定義a為包含10個(gè)整型數(shù)據(jù)的數(shù)組/intp; /定義p為指向整型變量的指針/應(yīng)當(dāng)注意,因?yàn)閿?shù)組為int型,所以指針變量也應(yīng)為指向int型的指針變量。下面是對(duì)指針變量賦值:p=&a[0];把a(bǔ)[10]元素的地地賦給指針變量p。也就是說,p指向a數(shù)組的第0號(hào)元素.
**
**C語言規(guī)定數(shù)組名代表的就是數(shù)組的首地址,也就是第0號(hào)元素的地址,
**
**p=&a[0]; 等價(jià)于 p=a;
**
**在定義指針變量時(shí)可以賦給初值
**
int *p=&a[0]; 等價(jià)于 int *p; p=&a[0]; 同時(shí)等價(jià)于 int *p=a;
**從圖中的關(guān)系可以卡出 p,a,&a[0]均指向同一單元,他們是數(shù)組a的首地址,也就是0號(hào)元素a[0]的首地址。需要注意的是p是變量,a,&a[0]是常量。
**
**
**
**通過指針引用數(shù)組元素。
**
**C語言規(guī)定:如果指針變量p已經(jīng)指向數(shù)組中的一個(gè)元素,則P+1指向同數(shù)組的下一個(gè)元素。
**
**引入指針變量以后我們就可以用兩種方法來訪問數(shù)組元素。
**
如果P的初值為&a[0],則
(1)P+i和a+i就是a[i]的地址,或者說他們指向a數(shù)組的第i個(gè)元素;
(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)等價(jià);
所以說,引用數(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ù)組的概念:
一個(gè)數(shù)組的所有元素都是指針則是數(shù)組指針,指針數(shù)組是一組有序的指針的集合。
指針數(shù)組的所有元素必須是具有相同存儲(chǔ)類型和指向相同數(shù)據(jù)類型的指針變量。
**指針數(shù)組的一般形式:
類型說明符 * 數(shù)組名[數(shù)組長度];
**
其中類型說明符為指針指向的變量的類型:
*例如:int pa[3];:pa是一個(gè)指針數(shù)組,他有三個(gè)數(shù)組元素,每個(gè)元素都是一個(gè)指針,指向整型變量。
指向指針的指針:如果一個(gè)人指針變量中存放的另一個(gè)指針變量的地址,則稱這個(gè)指針變量為指向指針的指針變量。
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)該叫做指針的變量名。
**
**這個(gè)特殊的指針指向一個(gè)返回整型值的函數(shù)。
**
**指針的聲明筆削和它指向函數(shù)的聲明保持一致。
**
**指針名和指針運(yùn)算符外面的括號(hào)改變了默認(rèn)的運(yùn)算符優(yōu)先級(jí)。
**
**如果沒有圓括號(hào),就變成了一個(gè)返回整型指針的函數(shù)的原型聲明。
**
**
**
*void (fptr)();
**
**
**
**把函數(shù)的地址賦值給函數(shù)指針,可以采用下面兩種形式:
**
**
**
**fptr=&Function; fptr=Function;
**
**
**
**取地址運(yùn)算符&不是必需的,因?yàn)閱螁我粋€(gè)函數(shù)標(biāo)識(shí)符就標(biāo)號(hào)表示了它的地址,
**
**如果是函數(shù)調(diào)用,還必須包含一個(gè)圓括號(hào)括起來的參數(shù)表。
**
**可以采用如下兩種方式來通過指針調(diào)用函數(shù):
**
*x=(fptr)(); x=fptr();
**
**第二種格式看上去和函數(shù)調(diào)用無異。
**
**但是有些程序員傾向于使用第一種格式,因?yàn)樗鞔_指出是通過指針而非函數(shù)名來調(diào)用函數(shù)的。
**
void (*funcp)(); //一個(gè)函數(shù)指針
void FileFunc(),EditFunc(); //聲明兩個(gè)函數(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)一個(gè)函數(shù)聲明其返回值為一個(gè)指針時(shí),實(shí)際上就是返回一個(gè)地址給調(diào)用函數(shù),
**
** 以用于需要指針或地址的表達(dá)式中。
**
**
格式:
類型說明符 * 函數(shù)名(參數(shù))
**
**當(dāng)然了,由于返回的是一個(gè)地址,所以類型說明符一般都是int。
**
**例如:
**
int *GetDate(); int * aaa(int,int);
**函數(shù)返回的是一個(gè)地址值,經(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ù)組某元素的地址。輸出的是這個(gè)地址里的值。
字符數(shù)組
1、字符數(shù)組的定義:與數(shù)組的定義相同
例如:char c[10].
2、字符數(shù)組的初始化
字符數(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語言中沒有專門的字符串變量,通常用一個(gè)字符數(shù)組來存放一個(gè)字符串。當(dāng)把一個(gè)字符串存入數(shù)組時(shí),也把結(jié)束符‘\0’存入數(shù)組,并以此作為該字符串的結(jié)束標(biāo)志。有了‘\0’以后,就不必再用字符數(shù)組的長度來判斷字符串的長度了。
C語言允許使用字符串的方式對(duì)數(shù)組作初始化賦值。
例:char c[]={'C',' ','p','r','o','g','r','a','m'};
可寫為:char c[]={"C program"};或去掉{} 寫為:char c[]="C program";
用字符串賦值要比用字符逐個(gè)賦值多占一個(gè)字節(jié),用于存放字符串結(jié)束標(biāo)志'\0'.
'\0'是由C編譯系統(tǒng)自動(dòng)加上的,由于采用'\0'結(jié)束標(biāo)志,所以在用字符串賦初值時(shí)一般無須指定數(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è)備上輸入一個(gè)字符串
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嗎順序比較兩個(gè)數(shù)組中的字符串,并由函數(shù)返回值返回比較,相等返回0,1>2返回值大于,否則返回值小于0;
6:strlen:測(cè)試字符串長度
一般形式:strlen(字符數(shù)組名)
功能:測(cè)試字符串的實(shí)際長度(不含字符串結(jié)束標(biāo)志‘\0’)并作為函數(shù)返回值。