由浅到深理解C语言指针和数组的关系

由浅到深理解C语言指针和数组的关系

    • 一. 引言
    • 二. 定义
      • 数组
      • 指针
    • 三.联系
      • 指针对一维数组操作
      • 一维数组对指针的操作
      • 总结1
      • 二维数组与指针的联系
      • 总结2

一. 引言

C语言的指针和数组有着密不可分的联系,如果不理解其中一个概念那么另一个也不会彻底的掌握。对于平日编程用到的以及书里看到的指针以和数组的操作,我梳理了一下。

二. 定义

数组

数组的定义为:<类型名><数组名>[<数组元素大小>]
例如定义一个整型数组a,数组元素个数为10,那么代码写作:

int a[10]

在这里我们需要知道数组有两个特点:1.C语言中的数组的大小在编译期就已经确定,也就是说我们定义一个没有指定大小的数组的时候编译器是会报错的。2.对于一个数组a,我们只能做两件事,一是确定其大小,二是取数组下标为0的元素指针,其它操作的话其实都是通过指针进行的。

举个例子,我们定义一个数组:

struct {
    int a;
    int b[10];
} c[5];

以上定义了一个拥有5个元素的数组c,其中每一个元素都是一个结构体,结构体包含一个整形变量a以及整型数组b。通过这个例子是想说明C语言中的数组元素可以是任何类型的元素,另外在定义这个数组时,其自身以及所包含的元素中的数组个数都是确定的。

那么以上是数组的定义,对于指针的声明似乎要简洁。

指针

声明指针的方式为:<类型名>*<指针名>,例如定义一个整型指针p,代码写作:

int *P;

p就是一个指向整型变量的指针,有如定义了一个整型变量k:

int k;

那么此时可以将k的地址赋值给指针p:

p = &k;

三.联系

指针对一维数组操作

以上我们简单介绍了数组以及指针的定义,下面我们来分析一下指针与数组的相互之间的操作。我们定义十个整型元素的数组a,定义整型指针p:

int a[10];
int *p;

如果想要通过p来操作a数组的第一个元素,只需要将数组a的首元素地址值赋值给p。如果想通过p对数组第二个元素操作只需要将p加1即可,对数组第i个元素操作即对指针加上i操作即可。当然我们现实中也有直接对a进行操作,一种写法是取a的下角标为i的元素进行操作,一种是直接将a看作是指针进行操作。

p = a;

/* 对数组第一个元素进行操作 */
*(p + 1)   = 1;

/* 对数组第i个元素进行操作,当然这个语句不完整 */
*(p + i)   = 2;

/* 对a直接操作,以下两种写法等效 */
a[i]       = 3;
*(a + i)   = 3;

由这个例子我们不难得到一个结论,*a即为数组a下标为0的元素的值。*(a+i)就是数组i的元素值,这种写法被简记为a[i]。由于a+ii+a没有区别,所以i[a]对于编译器而言,也是被认可的,不过一般不建议这种写法。

一维数组对指针的操作

这是利用指针对数组的操作,那么利用数组的方式对指针的操作是否被允许呢?也是一样的,我们可以看下这个例子:

int *p;
int a[10];

p = a;

p[2] = 5;

这个例子中的语句也是被编译器所承认的,我们在这里讲的数组对指针的操作意思是按照数组的方式对指针变量进行操作,指针变量p可以像数组的形式来使用,即变成p[i]。

总结1

对于一维数组而言我们使用这种方法骗过了编译器,使得数组a和指针p的操作符变得一样,以至于我们产生错觉,觉得这里的p就等于a。这里说是骗一点都不为过,因为前面我们已经强调了,一个数组声明的时候必须有确定的大小,以上例子的操作我们实际上是在使用一个指向一个整型数据的指针指向一个拥有10个整型数据元素的数组。

二维数组与指针的联系

再来看二维数组和指针之间操作的联系。我们先看一个例子:

int *p;
int a[5][6];

这里我们定义了一个二维数组a,这个数组我们可以理解为是一个拥有5个元素的数组,每个元素都是一个6元素的数组。有前面的一维数组和指针的介绍我们不难进行以下操作:

p = a[0];

将一维数组a的首元素地址赋值给p,所以此时p指向的是a数组的第一个元素。以上赋值语句被编译器所支持,所以这里又会产生另一种声明二维数组指针的方式:

int (*b)[6];
int a[5][6];

b = a;

有了指针对一维数组的操作的基础我们也可以轻易理解二维数组指针对二维数组的操作:

int (*b)[6];
int a[5][6];
int *p;

b = a;
p = a[0];

b[1][2]       = 4
(*(b + 1))[2] = 4;

代码中的(*(b + 1))我们可以类比为b[1],那么对于整个二维数组我们也可以写成

b[1][2]           = 4
(*(b + 1))[2]     = 4;
*((*(b + 1)) + 2) = 4;

以上三种写法都是被编译器支持的。

总结2

当对一个二维数组遍历时,我们可以尝试以下方法来实现:

int a[5][10];
int (*b)[10];
int *p;

for (b=a; b<&a[4]; b++)
{
	for (p=&((*b)[0]); p<&((*b)[10]); p++)
		*p = 0x55aa55aa;
}

C语言的数组和指针的操作隐藏着许多晦暗不明的地方,有些甚至连编译器都分不清的东西,我们了解了,在开发程序时就会避免这些问题。

你可能感兴趣的:(嵌入式&C语言)