C语言学习笔记 day02 二维数组的调用及其数组名的含义

个人整理学习用,非教材,有错误欢迎指正

数组名 arr

无论一维数组与二维数组,数组名在绝大多数情况下都表示数组的首元素地址,是一个地址。但有两个例外:sizeof() 和 & 后如果跟数组名,此时数组名表示的是整个数组,而不单单是首元素地址

//32位,一个int大小4字节,一个地址大小4字节
int arr[10] = {0};					//数组名arr
printf("1 -- %p\n", &arr[0]);		//0x00EFFE94
printf("2 -- %p\n", arr);			//0x00EFFE94
printf("3 -- %p\n", &arr);			//0x00EFFE94
printf("4 -- %d\n", sizeof(arr));	//结果为40,此处arr并非一个地址,否则结果应为4

需要注意的是,上图中1、2中的数组名【arr】是完全相同的,都是首元素地址。而3的结果虽然与1、2相同,但【arr】意义不同。可以让地址自加1来验证。可看到,arr+1仅在地址上加了一个int型变量的大小 4,而&arr+1加了一整个数组的大小 40

int arr[10] = {0};
printf("首元素地址:[%p]",arr);	//0076FA30
printf(" arr+1=[%p]",arr+1);	//0076FA34
printf("&arr+1=[%p]",&arr+1);	//0076FA58

上面是数组在一个函数中的情况。若涉及多个函数间的调用,C语言关于数组的调用都是传地址的,因此所有的数组名在调用过程中都变为了一个指针,其大小仅与你的运行环境是32位还是64位有关。

函数调用时的形参与实参

一维数组

C语言中,对数组的调用都是传址调用。依据形参,对数组的调用分三种:int* arrint arr[10]int arr[ ],三种写法等价。由于数组名本身就是首元素下标,因此属于传址调用。在函数调用中,即使采用第二种方式,在形参种声明了数组大小,也无法通过sizeof() 在函数中获得数组大小,最好的做法是在函数外部计算好函数大小,再作为一个变量传入函数中。
例如:int(int arr[10],int arrSize){ ... }

二维数组

首先需明确的是,在内存中仅存在一维数组。二维数组也是按照一维数组的形式存在内存中的。二维数组的数组名是二级指针,其中的每一行都可以视为一个数组。如:int arr[2][3],则arr[1]是一个一维数组,其类型是int *aint a[]

int arr[2][3] = {{4,5,6},{8,9,10}};
//此处会提示越界,但是VS2019仍可编译运行。且arr[0][3] = arr[1][0] = 8
printf("arr[0][3] = %d", arr[0][3]);
printf("arr[1][0] = %d", arr[1][0])
//arr[0][3]与arr[1][0]地址相同,二维数组是按照行优先,以一维数组的形式存储的

二维数组也分为三种调用方式

//二级指针 m代表行数,n代表列数
int arrTest01(int** arr, int m, int n) {
	for (int i = 0; i < m; i++) {
		for (int j = 0; j < n; j++) {
			//需要特别注意,二级指针的方式无法通过arr[i][j]的方式访问数组,原因见后文
			printf("01--> arr[%d][%d] = %d   ", i, j, *((int*)arr + i * n + j));
		}
		printf("\n");
	}
}

//全声明 m代表行数,n代表列数
int arrTest02(int arr[2][3], int m,int n) {
	for (int i = 0; i < m; i++) {
		for (int j = 0; j < n; j++) {
			printf("02--> arr[%d][%d] = %d   ", i, j, arr[i][j]);
		}
		printf("\n");
	}
}

//仅声明列数 m代表行数,n代表列数
int arrTest03(int arr[][3], int m,int n) {
	for (int i = 0; i < m; i++) {
		for (int j = 0; j < n; j++) {
			printf("03--> arr[%d][%d] = %d   ", i, j, arr[i][j]);
		}
		printf("\n");
	}
}

int main() {
	int arr[2][3] = { {4,5,6},{8,9,10} };
	arrTest01(arr, 2, 3);
	arrTest02(arr, 2, 3);
	arrTest03(arr, 2, 3);

	return 0;
}

由法2、法3可得,当使用arr[][]的方式作为形参时,必须给出arr的列数。由上文知,二维数组在内存中是顺序存储的,新一行的开头紧挨着上一行的结尾。如果不给出数组的列数,计算机无法分辨在何时结束第一行,开始第二行。
而法1中,传入的是二级指针则没有这种问题,计算机仅仅把arr当作一个地址。与法2、法3不同的是,没有列数,当要在函数中访问arr时,必须通过一维数组的方式进行访问,即将二维数组退化为一维数组,通过对地址arr[x]的直接访问获得值。由于传入的是二级地址,必须进行强制类型转换,并将行号、列号映射为一维的格式。
*((int*)arr + i * n + j) 其中,i、j为想要访问的行号列号,此访问方式可应用于法2、法3

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值