再议 C 语言中的指针与数组(4)
一 概述
前面的文章中,回顾了 C 语言中的指针,对指针有了一个比较初步的了解。在本文中,结合数组,再次对指针进行回顾。
二 数组与指针
在 C 语言中,指向数组的指针是比较常见的,也是非常方便和适用的。
2.1 指向数组的指针
# include<stdio.h>
int main(int argc,char *argv[]){
int a[10] = {1,2,3,4,6,5,7,8,9,0};
int *p;
// p = a;
p = &a[0];
for (int i = 0; i < 10; i++){
printf("%d\t",*p);
p++;
}
return 0;
}
// 1 2 3 4 6 5 7 8 9 0
本例中,指针变量 p 指向了数组 a[10],并演示了通过指针遍历数组的常规方法。 我们可以直接通过数组名直接将指针指向该数组的第一个元素,“p = a;” 和 “p = &a[10];”这两行代码在本质上是等价的。需要注意的是:通过这种方式使指针指向整个数组,数组名前面不能再使用运算符 &。 若指针指向数组的某一元素,运算符 & 不能省略。
2.2 指向复合常量的指针
# include<stdio.h>
int main(int argc,char *argv[]){
int *p = (int []){1,2,3,4,6,5,7,8,9,0};
for (int i = 0; i < 10; i++){
printf("%d\t",*p);
p++;
}
return 0;
}
//1 2 3 4 6 5 7 8 9 0
本例声明并初始化了一个没有名称的数组。 通过这种方式,我们不需要先声明一个数组,然后再用指针指向数组的第一个元素。 在某些场景中,这个特性使用起来比较方便。 这是 C99 的一个特性。 另外, 在本例的 for 循环体,声明并初始化了 i, 这也是 C99 的一个特性,需要注意一下。
可以声明匿名数组的长度。
# include<stdio.h>
int main(int argc,char *argv[]){
int *p = (int [10]){1,2,3,4,6,5,7,8,9,0};
for (int i = 0; i < 10; i++){
printf("%d\t",*p);
p++;
}
return 0;
}
2.3 通过指针对数组进行操作
通过指针也可以很方便、高效地对数组进行操作,请看以下例子:
# include<stdio.h>
# define N 10
int main(int argc,char *argv[]){
int a[N];
int *p;
for (p = a; p < a + N; p++){
printf("Please input a[%d]:",p - a);
scanf("%d",p);
}
for (p = a; p < a + N; p++){
printf("a[%d] = %d;\t ", p - a, *p);
}
printf("\n");
return 0;
}
/*
Please input a[0]:1
Please input a[1]:2
Please input a[2]:3
Please input a[3]:4
Please input a[4]:5
Please input a[5]:66
Please input a[6]:7
Please input a[7]:7
Please input a[8]:8
Please input a[9]:9
a[0] = 1; a[1] = 2; a[2] = 3; a[3] = 4; a[4] = 5; a[5] = 66; a[6] = 7; a[7] = 7; a[8] = 8; a[9] = 9;
*/
这个例子展示了通过操作指针对数组进行赋值,并通过指针的移动完成对数组的遍历。例子中使用了两个指针相减的方式确定了数组下标。使用指针操作对数组进行赋值或遍历的过程中,在操作开始之前需要将指针复位,指向数组的第一个元素。这个操作必不可少,否则将出错。
2.4 指针与数组在函数定义中的使用
在函数定义时,数组可以使用指针或显示声明来定义形式参数。
# include<stdio.h>
int main(int argc,char *argv[]){
unsigned int array[] = {3,5,6,7,1,2,0}, len;
int find_max(unsigned int [], int n);
len = sizeof array / sizeof array[0];
printf("%d\n",find_max(array,len));
return 0;
}
int find_max(unsigned int a[], int n){
int max = 0;
for (int i = 0; i < n; i++){
if ( a[i] > max)
max = a[i];
}
return max;
}
// 7
# include<stdio.h>
int main(int argc,char *argv[]){
unsigned int array[] = {3,5,6,7,1,2,0}, len;
int find_max(unsigned int [], int n);
// int find_max(unsigned int *, int n);
len = sizeof array / sizeof array[0];
printf("%d\n",find_max(array,len));
return 0;
}
int find_max(unsigned int *a, int n){
int max = 0;
for (int i = 0; i < n; i++){
if ( a[i] > max)
max = a[i];
}
return max;
}
// 7
在以上2段代码中,写法不一样,但执行效果却一致。事实上数组作为形参时,是以指针进行传递的。也就是说,对于形参而言,声明为数组与声明为指针是一样的,但是对于变量来说,声明为数组与声明为指针是不一样的。指定长度的数组会导致编译器预留指定数据类型长度的空间,申明为指针会导致编译器为指针变量分配空间。
2.5 多维数组与指针
使用指针遍历多维数组:
# include<stdio.h>
int main(int argc,char *argv[]){
int *p, array[2][3] = {{12,43,11},{10,56,89}};
for (p = &array[0][0]; p <= &array[1][2]; p++)
printf("array[%d][%d]: %d\n",(p - &array[0][0])/3, (p - &array[0][0])%3, *p);
return 0;
}
/*
array[0][0]: 12
array[0][1]: 43
array[0][2]: 11
array[1][0]: 10
array[1][1]: 56
array[1][2]: 89
*/
以上代码等价于:
# include<stdio.h>
int main(int argc,char *argv[]){
int *p, array[2][3] = {{12,43,11},{10,56,89}};
for (p = array[0]; p <= &array[1][2]; p++)
printf("array[%d][%d]: %d\n",(p - &array[0][0])/3, (p - &array[0][0])%3, *p);
return 0;
}
对比以上两端代码,乍一看,并没有什么差异!举着个例子的重点在第四行的 “p = &array0” 和 “p = array[0]”。通过这两行代码,不难看出:二维数组中,指针 p 不是指向 array0 的指针,而是指向 array[0] 的指针。
多维数组是不能以数组名直接作为指针指向的对象,需要稍微做一些调整才能使用数组名作为指针。在 C 语言中,多维数组实际上就是以一维数组来进行处理的。结合上面的例子,C 语言把 array 当作一维数组来进行处理,而这个一维数组的美一个元素又是一个一维数组。由此,可以推广到多维数组。
那么,在多维数组内是否可以直接以数组名为作为指针呢?请看以下例子:
# include<stdio.h>
# define ROWS 2
# define COLS 3
int main(int argc,char *argv[]){
int *p, array[ROWS][COLS] = {{12,43,11},{10,56,89}};
for (p = *array; p < *array + (ROWS * COLS); p++)
printf("array[%d][%d]: %d\n",(p - *array) / COLS, (p - *array) % COLS, *p);
return 0;
}
/*
array[0][0]: 12
array[0][1]: 43
array[0][2]: 11
array[1][0]: 10
array[1][1]: 56
array[1][2]: 89
*/
在这一代码片段中,将指针变量 p 指向一个指针类型的数组。也就是说,指针变量 p 指向了一个数组,这个数组的全部元素均为指针。简而言之,指针变量 p 是指向指针数组的指针。
三 总结
3.1 在 C 语言中,指针与数组关系密切,既有联系又有区别。在实际的使用过程中要特别谨慎。
3.2 指针是 C 语言中的精华。作为一名 C 语言学习者,指针虽然比较坑,但是这个是无法逃避的,必须花大量的时间与精力去学习与理解。
3.3 指针常常会与数组发生关联,对指针的理解必须透彻。
3.4 鉴于笔者水平,文中可能存在若干谬误,希望大家能帮忙指出,谢谢!