C语言之指针和数组

指针和数组虽然是不同的东西,但却有着千丝万缕的关系,下面就让我们逐一了解吧!

指针和数组

数组名原则上会被解释为指向该数组起始元素的指针

也就是说。如果a是数组,那么表达式a的值就是a[0]的值,即与&a[0]一致;如果数组a的元素类型为Type型,那么不管有多少个元素,表达式a的类型都为Type*型。

将数组名视为指针,也催生出了数组与指针的密切关系,我们看下图:

这里声明了数组a和指针p,指针p的初始值是a,又因为数组名a会被解释为&a[0],所以存入p的值为&a[0],也就是说指针p会被初始化为指向数组起始元素的a[0],指针p指向的起始元素,不是数组中的全部元素。

围绕着指向数组元素的指针,有以下规则成立:

指针p指向数组的元素e时:

1.p+i为指向元素e后的第i个元素
2.p-i为指向元素e前的第i个元素

 数组名在什么情况下不会被视为指向起始元素的指针

█作为sizeof运算符的操作数出现时

sizeof(数组名)不会生成指向起始元素的指针的长度,而是生成数组的整体长度

█作为取地址运算符&的操作数出现时

&+数组名不是指向起始元素的指针的指针,而是指向数组整体得指针


也就是说,指向各元素的指针p+i和&a[i]是等价的,其中&a[i]是指向元素a[i]的指针,其值是a[i]的地址

我们用一个代码来显示出它们各自的值:

#include<stdio.h>

int main()
{
	int i = 0;
	int a[5] = {1,2,3,4,5};
	int *p = a;
	
	for(;i<5;i++)
		printf("&a[%d] = %p   p+%d = %p\n", i, &a[i], i, p + i);
	
	return 0;
}

指针运算符和下表运算符

如果在指向数组内元素的指针p+i前写上指针运算符*,会变成什么情况呢?

*(p+i)就是该元素的别名,因此如果p指向a[0],那么表达式*(p+i)就表示a[i]的本身

指针p指向数组的元素e时:

指向元素e后第i个元素*(p+i),可以写为p[i]

指向元素e前第i的元素*(p-i),可以写为p[-i]

 我们来看下它们之间的关系:

  • 因为p+2指向a[2],所以*(p+2)是a[2]的别名(组c)
  • 因为*(p+2)可以写为a[2],所以p[2]也是a[2]的别名(组B)

以下4个表达式都是访问各元素的表达式:

a[i]

*(a+i)

p[i]

*(p+i)

一下4个表达式都是指向各元素的指针:

&a[i]

a+i

&p[i]

p+i

注意

Type*型指针p指向Type型数组a的起始元素a[0]时,指针p的行为就和数组a本身一样

表达式a[i]和p+i中的i,表示位于指针a和p所指的元素后第几个元素的位置,所以数组起始元素的下标必须是0

数组和指针的不同点

int *p;
int y[5];
p = y;

p是指向int型变量的指针,被赋给p的是y,即&y[0],赋值后,指针p指向y[0]

int a[5];
int b[5];
a = b;

指向a=b时会出现编译错误,虽然说a会被解释为指向数组起始元素的指针,但不可以改写其值

如果可以这样赋值,那么数组的地址就会被改变,变为别的地址,因此,赋值表达式的左操作数不可是数组名。

下标运算符的操作数

我们看下指针p和整数i相加的式子前写上指针运算符的表达式*(p+i),括号内的进行的是加法运算,与算数类型的数值间的加法运算等同,也就是*(i+p)

这样一来,访问数组元素的表达式p[i]也可以写成i[p],下表运算符[ ],是具有两个操作数的双目运算符,其中一个操作数的类型是:

指向Type型对象的指针

另一个操作数的类型是:

整数类型数据类型

下标运算符[ ]的操作数的顺序是随意的,例如a[3]也可以写为3[a]

下表运算符[ ]所生成值的类型是:Type型

但是在进行书写时,这种格式虽然没有错误,但还是尽量不要这样写

数组的传递

#include<stdio.h>

/*将数组v开头的n个元素赋值给val*/
void ary_set(int v[], int n, int val)
{
	int i = 0;
	for(; i < n; i++)
		v[i] = val;
}
int main()
{
	int i = 0;
	int a[] = {1,2,3,4,5};
	
	ary_set(a, 5, 99);
	
	for(;i < 5; i++)
		printf("a[%d] = %d\n", i, a[i]);
	
	return 0;
}

对于ary_set函数中数组v的声明可以写为一下几种形式:

a和b都可以解释为c,也就是说形参v的类型不是数组而是指针,即使像b中那样声明元素的个数,也是无用的。

但是我们可以在传递数组时,将数组元素个数作为别的参数来处理。

在调用ary_set函数时,,int*型的形参v将使用实参a,即&a[0]进行初始化,由于指针v指向数组的起始元素a[0],因此在ary_set函数内指针v的行为就像数组本身一样

如果改写所接受的元素的值,结果就会反映到调用方的数组元素上。

注意

函数间数组的传递是以指向第一元素的指针的形式进行的,在被调用的函数中作为指针接收的数组,实际上就是调用方传递的数组。

  • 18
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

学海无涯.苦作舟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值