数组指针和指向数组的指针变量
C语言规定:如果指针变量p已指向数组中的一个元素,则p+1指向同一数组中的下一个元素,因为在C语言中数组名代表数组的首地址。
int a[5], *pa;
pa = a; /* 数组名表示数组的首地址,故可赋予指向数组的指针变量pa */
//等价于
pa = &a[0]; /* 数组第一个元素的地址也是整个数组的首地址, 也可赋予pa */
//当然也可采取初始化赋值的方法:
int a[5], *pa = a;
举例1.
#include
main(){
char a[10] = {'T', 'h', 'i', 's', ' ', 'i', 's', ' ', 'A'};
char *p;
p = a;
printf("p = %d, *p = %c, *(p + 2) = %c\n", p, *p, *(p + 2));
//p = 1245044, *p = T, *(p + 2) = i
}
举例2.通过不同方式输出数组元素
#include
main(){
//(1)./(2).int a[10];
int a[10], *p = a;
for(int i = 0; i < 10; i++) {
//(1.)a[i] = i;
//(2).*(a + i) = i;
* (p + i) = i; //注意这里只能是(p + i)而不能为p++
}
puts("---------------------------");
for(int j = 0; j < 10; j++) {
//(1).printf("a[%d] = %d\n", j, a[j]);
//(2).printf("a[%d] = %d\n", j, *(a + j));
printf("a[%d] = %d\n", j, *(p + j));
}
printf("-------------------------\n");
}
举例3.使用指针的++而不是+i来输出数组元素
#include
main(){
int a[10], *p = a;
for(int i = 0; i < 10; i++) {
* p++ = i;
}
puts("---------------------------");
for(int j = 0; j < 10; j++) {
printf("a[%d] = %d\n", j, *p++);
}
printf("-------------------------\n");
}
注意:
(1).虽然定义数组时指定它包含10个元素,但指针变量可以指到数组以后的内存单元(
由两处p++导致),系统并不认为非法。
(2).*p++,由于++和*同优先级,结合方向自右而左,等价于*(p++)
(3).*(p++)与*(++p)作用不同。若p的初值为a,则*(p++)等价a[0],*(++p)等价a[1]。
(4).(*p)++表示p所指向的元素值加1。
举例3.数组作为函数参数
#define TOTAL 7
#include
void reverse (int b[]) {
int temp = -1;
for (int m = 0 ; m < float(TOTAL / 2) ; m++) {
temp = b[m];
b[m] = b[TOTAL - m - 1];
b[TOTAL - m - 1] = temp;
}
}
main(){
int a[TOTAL];
for(int i = 0 ; i < TOTAL ; i++) {
a[i] = i;
}
puts("-----------before reverse----------------");
for(int j = 0 ; j < TOTAL ; j++) {
printf("a[%d] = %d\n", j, a[j]);
}
reverse(a);
printf("----------after reverse---------------\n");
for(int k = 0 ; k < TOTAL ; k++) {
printf("a[%d] = %d\n", k, a[k]);
}
}
说明:当执行了第一个for循环为数组各元素赋予了从0到TOTAL的数值后,其内存模型如下(左图)。当我们将数组作为参数传递后,b也指向了数组a的地址(右图)。
实际上也可以通过指针来实现逆序,即将上面的reverse代码使用如下代码替换即可。
void reverse (int *p) {
int temp = -1;
for (int m = 0 ; m < float(TOTAL / 2) ; m++) {
temp = *(p + m);
*(p + m) = *(p + TOTAL - m -1);
*(p + TOTAL - m -1) = temp;
}
}
归纳起来,如果有一个实参数组,想在函数中改变此数组的元素的值,实参与形参的对应关系有以下4种:
1).形参和实参都是数组名(a, b)。
2).实用数组,形参用指针变量(a, *p)。
3).实参、形参都用指针变量(略)。
4).实参为指针变量,形参为数组名(略)。
二维数组指针变量说明的一般形式为:
类型说明符 (*指针变量名)[长度]
其中“类型说明符”为所指数组的数据类型。“*”表示其后的变量是指针类型。“长度”表示二维数组分解为多个一维数组时,一维数组的长度,也就是二维数组的列数。应注意“(*指针变量名)”两边的括号不可少,如缺少括号则表示是指针数组。
举例4.二维数组的地址
#include
main(){
int a[3][COLUMN]={{0, 1, 2, 3}, {4, 5, 6, 7}, {8, 9, 10, 11}};
printf("a = %d, a[0] = %d, &a[0][0] = %d\n", a, a[0], &a[0][0]);
printf("a[1] = %d, &a[1][0] = %d\n", a[1], &a[1][0]);
printf("\n");
printf("(a[0] + 1) = %d, &a[0][1] = %d\n", (a[0] + 1), &a[0][1]);
printf("(a[1] + 1) = %d, &a[1][1] = %d\n", (a[1] + 1), &a[1][1]);
}
举例5.使用指针实现二维数组
#define COLUMN 4
#include
main(){
int a[3][COLUMN]={{0, 1, 2, 3}, {4, 5, 6, 7}, {8, 9, 10, 11}};
int (*p)[COLUMN];
p = a;
printf("a = %d, p = %d\n", a, p);
printf("a[0] = %d, &a[0][0] = %d\n", a[0], &a[0][0]);
printf("a[1] = %d, &a[1][0] = %d\n", a[1], &a[1][0]);
printf("a[2] = %d, &a[2][0] = %d\n", a[2], &a[2][0]);
for (int i = 0 ; i < 3 ; i++ ) {
printf("*(p + %d) = %d\n", i, *(p + i));
for (int j = 0 ; j < 4 ; j++) {
printf("\t*(*(p + %d) + %d) = %d\n", i, j, *(*(p + i) + j));
}
}
}