指针和数组

1.一维数组和指针

int a[10] = {0,1,2,3,4,5,6,7,8,9};
int *p = a;		//等价于 int *p = &a[0];

在这里插入图片描述

  1. 数组名为数组首元素的地址。 所以第二条语句等价于int *p = &a[0];
  2. 数组名a代表首地址,所以a+1和p+1效果相同。注意数组名是常量,不能变化, 所以不能执行类似a=a+1、a++的操作;p是变量,p可以执行类似操作。
  3. a[i] <=> *(a+i) <=> *(p+i) <=> p[i]。 实际上,在编译时,对数组元素a[i]就是按 *(a+i)处理的,[]是变址运算符。
  4. 在指针已指向一个数组时,可对指针进行加减运算。 p+1指向数组中的下一个元素,p-1指向数组中的上一个元素(p+1并不是将p的值(地址)简单地加1,而是加上一个数组元素所占用的字节数)。
  5. p2-p1的结果是两者之间间隔的元素个数。具体算法是p2-p1的值(两个地址之差)除以数组元素的长度。
  6. 如果在程序中引用了a[10],虽然并不存在这个元素(最后一个元素是a[9]),但C编译器并不认为它非法,因为系统把它按*(a+10)处理。这样做虽然在编译时不出错,但运行结果是不预期的,应避免。

2.二维数组和指针

int a[3][4] = {{1,3,5,7},{9,11,13,15},{17,19,21,23}};

在这里插入图片描述

  1. a是数组名,代表二维数组首元素的地址,但现在的首元素是第0行,即由4个整形元素所组成的一维数组。
  2. 可以认为a[0]、a[1]、a[2]是一维数组名,指向每行的起始元素。
  3. a+1代表序号为1的行的起始地址。而*(a+1)就是a[1],而a[1]是一维数组名,所以也是地址,它指向a[1][0]。
  4. 第0行1列元素的地址怎么表示?应该用a[0]+1、*(a+0)+1来表示。
  5. 有必要对a[i]的性质作进一步说明。a[i]从形式上看是a数组中序号为i的元素。如果a是一维数组名,则a[i]的确表示序号为i的地址单元里的值。但如果a是二维数组,则a[i]是一维数组名,它只是一个地址,并不代表该地址单元中的值。
  6. 现在a[0]是一维数组名(一维数组中首元素的地址),a是二维数组名(二维数组中首行的地址),二者的纯地址相同,为2000,但它们的基类型不同,前者指向整型数据,后者指向一维数组

a[0]、a[1]、a[2]的类型为 int* 型,指向整型变量。
而a的类型为 int(*)[4],指向包含4个元素的一维数组。这就是数组指针。

  1. 在指向行的指针前面加一个*,就转换为指向列的指针, 如a和a+1是指向行的指针,*a和*(a+1)就成为指向列的指针。反之,在指向列的指针前面加&,就成为指向行的指针,如a[0]是指向0行0列元素的指针,而&a[0]指向二维数组的第0行。&a[0] <=> &*a <=> a
    在这里插入图片描述

2.1一级指针遍历二维数组

#include <stdio.h>
int main()
{
	int a[3][4] = {{1,3,5,7},{9,11,13,15},{17,19,21,23}};
	int *p;							//p是int *型指针变量,使其指向列元素
	for(p=a[0]; p<a[0]+12; p++)		//p依次指向下一个元素
	{
		if( (p-a[0])%4==0 )
			printf("\n");
		printf("%4d", *p);
	}
	printf("\n");
	
	return 0;
}

运行结果:
在这里插入图片描述

2.2数组指针遍历二维数组

//输出二维数组任一行一列的元素值
#include <stdio.h>
int main()
{	
	int a[3][4] = {{1,3,5,7},{9,11,13,15},{17,19,21,23}};
	int (*p)[4];	//表示p指向包含4个整型元素的一维数组(数组指针)
	p = a;			//p指向二维数组的第0行
	
	for(int i=0; i<3; i++)
	{
		for(int j=0; j<4; j++)
		{
			printf("%4d", *(*(p+i)+j) );
		}
		printf("\n");
	}
	return 0;
}

2.3数组指针遍历一维数组

重点: 对一维数组名取&,转为指向行的地址

#include <stdio.h>
int main()
{	
	int a[4] = {1, 3, 5, 7};
	int (*p)[4];		//数组指针,指向包含4个整型元素的一维数组
	p = &a;				//重点,对一维数组名取&,转为指向行的地址

	printf("%d\n", (*p)[3] );	//输出a[3],相当于*(*(p+0)+3)
	return 0;
}

在这里插入图片描述

3.数组传参

3.1一维数组的形参

一维数组的形参可以写成如下几种:

void test(int arr[10])
{}

void test(int arr[])
{}

void test(int *arr)
{}

可以接受的参数:
(1)可以是一个整形指针
(2)可以是整型变量地址
(3)可以是一维整型数组数组名

3.2指针数组的形参

void test(int *arr[20])
{}

void test(int **arr)//传过去是指针数组的数组名,代表首元素地址,首元素是个指针向数组的指针,再取地址,就表示二级指针,用二级指针接收
{}

3.3二维数组的形参

void test(int arr[3][4])
{}

void test(int arr[][4])//二维数组的两个方括号,不能全部为空,也不能第二个为空,只能第一个为空
{}

void test(int (*arr)[4])//传过去的是二维数组的数组名,即数组首元素的地址,也就是第一行的地址,第一行也是个数组,用一个数组指针接收
{}

指针的大小

在32位平台下,无论指针的类型是什么,sizeof(指针名)都是4,在64位平台下,无论指针的类型是什么,sizeof(指针名)都是8。

参考:数组和指针的区别与联系(详细)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值