您的位置:首页 > 编程语言 > C语言/C++

C指针基础(四)

2017-03-14 22:02 148 查看
这篇文章我们来一起讨论一下指针与数组。指针与数组密不可分,但是绝不能将二者混为一谈。

数组名用作指针

我们可以用数组的名字作为指向数组第一个元素的指针。因此通常情况下,
a+i
等同于
&a[i]
*(a+i)
等同于
a[i]
,其中a是数组名。于是我们可以这样操作:

int a[100];
*a = 7;   // 数组第一个元素赋值7
*(a+2) = 4;   // 数组第2个元素赋值4


指针用作数组名

既然我们可以用数组名作为指针,那么反过来也是可以的。

int a[9], *p = a;

p[3] = 5;   // 数组a的第三个元素赋值5


通常情况下,
p[i]
可以看作
*(p+i)


用指针处理数组

了解了上面的用法后,我们可以很轻松地用指针来处理数组。下面我们来吃几个栗子。

第一个栗子:一维数组求和

#define N 10
...
int a
, sum, *p;
...
sum = 0;
for (p = &a[0]; p < &a
; p++)
sum += *p;


上面的例子中,我们将p指向数组a的第一个元素,然后依次对指针p自增从而遍历整个数组。你可能会怀疑
p < &a
的用法,其实这样做是完全正确的。即使元素
a
不存在,但是对它使用取地址运算符也是合法的。

第二个栗子:二维数组的求和

#define R 9
#define C 8
int a[R][C];
int *p, sum = 0;
...
for (p = &a[0][0]; P <= &a[R-1][C-1]; p++)
sum += *p;


如果我们要对一个二维数组进行求和,通常我们会用两个嵌套的
for
循环,但是如果我们有了指针的话,我们只用一个循环就可以搞定,只不过可读性变差了。

第三个栗子:二维数组的第i行求和

...
int a[R][C], *p, i;
...
for (p = &a[i][0]; p < &a[i][C]; p++)
sum += *p;


上面的代码很容易理解,但是我们可以进一步简化。
&a[i][0]
指向第i行的第一个元素,而对于二维数组,
a[i]
即为指向第i行的第一个元素的指针,因此我们完全可以用
a[i]
代替
&a[i][0]
,同理可以用
a[i]+C
代替
&a[i][C]


int a[R][C], *p, i;
...
for (p = a[i]; p < a[i] + C; p++)
sum += *p;


同样,第二个栗子的代码也可以简化成这样:

...
int a[R][C];
int *p, sum = 0;
...
for (p = a[0]; P < a[R]; p++)
sum += *p;


因为a[0]指向数组第i行的第一个元素,同样也是数组的第一个元素。

第四个栗子:二维数组的第i列求和

int a[R][C], (*p)[C], i, sum = 0;
...
for (p = &a[0]; p < &a[R]; p++)
sum += (*p)[i];


上面的代码有些晦涩。在声明中,我们把
p
指向长度为
C
的整型数组的指针,在
(*p)[C]
中,
*p
是需要使用括号的;如果没有括号,编译器将认为
p
是指针数组,而不是指向数组的指针。表达式
p++
p
移动到下一行的开始位置。在表达式
(*p)[i]
*p
表示
a
的一整行,因此
(*p)[i]
选中了该行第i列的那个元素。如果你还是不懂的话,你可以联想一下一维数组的声明方法
int a[C]
,再看看这里
p
的声明
(*p)[C]
,是不是可以对应上呢?
(*p)
可以对应数组a的名字
a
,而
p
对应
&a
(*p)[i]
中的括号是必要的,因为编译器会将
*p[i]
解释为
*(p[i])


其实,上面的代码还可以进一步简化:

int a[R][C], (*p)[C], i, sum = 0;
...
for (p = a; p < a+R; p++)
sum += (*p)[i];


理解上面这个代码,必须首先要理解
a
(记住此时数组为二维数组)的含义。a不是指向
a[0][0]
的指针,而是指向
a[0]
的指针。因此
&a[0]
就可以简化为
a


参考资料

C语言程序设计现代方法, K.N.King, 人民邮电出版社




本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c语言