變量在內存存放是有地址的,數組在內存存放也同樣具有地址。對數組來說,數組名就是數組在內存安放的首地址。指針變量是用於存放變量的地址,可以指向變量,當然也可存放數組的首址或數組元素的地址,這就是說,指針變量可以指向數組或數組元素,對數組而言,數組和數組元素的引用,也同樣可以使用指針變量。下面就分別介紹指針與不同類型的數組。
6.4.1指針與一維數組
假設我們定義一個一維數組,該數組在內存會有系統分配的一個存儲空間,其數組的名字就是數組在內存的首地址。若再定義一個指針變量,並將數組的首址傳給指針變量,則該指針就指向了這個一維數組。我們說數組名是數組的首地址,也就是數組的指針。而定義的指針變量就是指向該數組的指針變量。對一維數組的引用,既可以用傳統的數組元素的下標法,也可使用指針的表示方法。
int a[10],*ptr;/*定義數組與指針變量*/
做賦值操作:
ptr=a;或ptr=&a[0];
則ptr就得到了數組的首址。其中,a是數組的首地址,&a[0]是數組元素a[0]的地址,由於a[0]的地址就是數組的首地址,所以,兩條賦值操作效果完全相同。指針變量ptr就是指向數組a的指針變量。
若ptr指向了一維數組,現在看一下C規定指針對數組的表示方法:
1)ptr+n與a+n表示數組元素a[n]的地址,即&a[n]。對整個a數組來說,共有10個元素,n的取值為0~9,則數組元素的地址就可以表示為ptr+0~ptr+9或a+0~a+9,與&a[0]~&a[9]保持一致。
2)知道了數組元素的地址表示方法,*(ptr+n)和*(a+n)就表示為數組的各元素即等效於a[n]。
3)指向數組的指針變量也可用數組的下標形式表示為ptr[n],其效果相當於*(ptr+n)。
[例6-5]/*以下標法輸入輸出數組各元素。
下面從鍵盤輸入10個數,以數組的不同引用形式輸出數組各元素的值。
#include <stdio.h>
main()
{
int n,a[10],*ptr=a;
for(n=0;n<=9;n++)
scanf("%d",&a[n]);
printf("1------output!\n");
for(n=0;n<=9;n++)
printf("%4d",a[n]);
printf("\n");
}
運行程序:
RUN
1234567890¿
1------output!
1234567890
[例6-6]采用指針變量表示的地址法輸入輸出數組各元素。
#include <stdio.h>
main()
{
int n,a[10],*ptr=a;/*定義時對指針變量初始化*/
for(n=0;n<=9;n++)
scanf("%d",ptr+n);
print f("2------output!\n");
for(n=0;n<=9;n++)
print f("%4d",*(ptr+n));
print f("\n");
}
運行程序:
RUN
1234567890¿
2------output!
1234567890
[例6-7]采用數組名表示的地址法輸入輸出數組各元素。
main()
{
int n,a[10],*ptr=a;
for(n=0;n<=9;n++)
scanf("%d",a+n);
print f("3------output!\n");
for(n=0;n<=9;n++)
print f("%4d",*(a+n));
print f("\n");
}
運行程序:
RUN
1234567890¿
3------output!
1234567890
[例6-8]用指針表示的下標法輸入輸出數組各元素。
main()
{
int n,a[10],*ptr=a;
for(n=0;n<=9;n++)
scanf("%d",&ptr[n]);
print f("4------output!\n");
for(n=0;n<=9;n++)
print f("%4d",ptr[n]);
print f("\n");
}
運行程序:
RUN
1234567890
4----output!
1234567890
[例6-9]利用指針法輸入輸出數組各元素。
main()
{
int n,a[10],*ptr=a;
for(n=0;n<=9;n++)
scanf("%d",ptr++);
print f("5------output!\n");
ptr=a;/*指針變量重新指向數組首址*/
for(n=0;n<=9;n++)
print f("%4d",*ptr++);
print f("\n");
}
運行程序:
RUN
1234567890¿
5-----output!
1234567890
在程序中要注意*ptr++所表示的含義。*ptr表示指針所指向的變量;ptr++表示指針所指向的變量地址加1個變量所占字節數,具體地說,若指向整型變量,則指針值加2,若指向實型,則加4,依此類推。而print f(“%4d”,*ptr++)中,*ptr++所起作用為先輸出指針指向的變量的值,然後指針變量加1。循環結束後,指針變量指向如圖6-6所示:
指針變量的值在循環結束後,指向數組的尾部的後面。假設元素a[9]的地址為1000,整型占2字節,則ptr的值就為1002。請思考下面的程序段:
main()
{
int n,a[10],*ptr=a;
for(n=0;n<=9;n++)
scanf("%d",ptr++);
print f("4------output!\n");
for(n=0;n<=9;n++)
print f("%4d",*ptr++);
print f("\n");
}
程序與例6-9相比,只少了賦值語句ptr=a;程序的運行結果還相同嗎?
6.4.2 指針與二維數組
定義一個二維數組:
int a[3][4];
表示二維數組有三行四列共12個元素,在內存中按行存放,存放形式為圖6-7:
其中a是二維數組的首地址,&a[0][0]既可以看作數組0行0列的首地址,同樣還可以看作是二維數組的首地址,a[0]是第0行的首地址,當然也是數組的首地址。同理a[n]就是第n行的首址;&a[n][m]就是數組元素a[n][m]的地址。
既然二維數組每行的首地址都可以用a[n]來表示,我們就可以把二維數組看成是由n行一維數組構成,將每行的首地址傳遞給指針變量,行中的其余元素均可以由指針來表示。下面的圖6-8給出了指針與二維數組的關系:
我們定義的二維數組其元素類型為整型,每個元素在內存占兩個字節,若假定二維數組從1000單元開始存放,則以按行存放的原則,數組元素在內存的存放地址為1000~1022。
用地址法來表示數組各元素的地址。對元素a[1][2],&a[1][2]是其地址,a[1]+2也是其地址。分析a[1]+1與a[1]+2的地址關系,它們地址的差並非整數1,而是一個數組元素的所占位置2,原因是每個數組元素占兩個字節。
對0行首地址與1行首地址a與a+1來說,地址的差同樣也並非整數1,是一行,四個元素占的字節數8。
由於數組元素在內存的連續存放。給指向整型變量的指針傳遞數組的首地址,則該指針指向二維數組。
int *ptr,a[3][4];
若賦值:ptr=a;則用ptr++就能訪問數組的各元素。
[例6-10]用地址法輸入輸出二維數組各元素。
#include<stdio.h>
main()
{
int a[3][4];
int i,j;
for(i=0;i<3;i++)
for(j=0;j<4;j++)
scanf("%d",a[i]+j);/*地址法*/
for(i=0;i<3;i++)
{
for(j=0;j<4;j++)
printf("%4d",*(a[i]+j));/**(a[i]+是j地)址法所表示的數組元素*/
printf("\n");
}
}
運行程序:
RUN
1 2 3 4 5 6 7 8 9 10 11 12
1 2 3 4
5 6 7 8
9 10 11 12