C语言深度理解数组与指针——你真的会用数组吗?

1.介绍

本篇是对字符指针、数组指针、指针数组这篇博客进行的补充。

字符指针、数组指针、指针数组以及指针传参——C语言

上一篇博客对字符串常量的介绍较为笼统与模糊,以及对“二维数组”根本没有介绍。

本篇将重点整理数组与指针的关系以及一些便于记忆的代码。

2.字符串常量

我们先研究一段代码:

#include <stdio.h>
int main()
{
	char* str = "abcd";
	char arr[] = "abcd";

	if (str == arr)
		printf("1\n");
	else
		printf("0\n");
	return 0;
}

输出结果:

这段代码我们介绍过,但是并没有给出很明确的解释。


现在我们来详细分析:

我们用 if else 语句来判断 str 和 arr 的地址是否相同,输出结果为 0 ,即不相同。

我们的问题在于,都使用看起来相同的字符串,为什么地址会不相同。

首先看 char* str = "abcd" ; 这条语句:

 我们再看 char arr[] = "abcd" ; 这条语句:

 3.数组与指针

事实上,在C语言中,只存在一维数组。不是有二维数组吗?这个问题在后面解释。

我们先来看一段代码:

#include <stdio.h>
int main()
{
	char arr1[5] = "abcd";
	char arr2[5] = "abcd";

	//都是把第二个元素改为'B
	arr1[1] = 'B';
	*(arr2 + 1) = 'B';

	printf("%s\n", arr1);
	printf("%s\n", arr2);
	return 0;
}

输出结果:

 这个例子很好的将 指针 和 数组 联系起来。

实际上,我们对数组的操作只有两种:

一是确定数组的大小。

二是获得首元素的地址。

这就很奇怪了,我们明明使用数组的下标改掉数组的内容了啊!

其实,除了对数组操作的两种方法外,我们想要操作数组,只能使用指针就算看起来使用的是数组下标,实际上它也是一种指针操作。只不过数组下标是指针操作的简写,被常用而已。

我们再来研究下面这串代码:

#include <stdio.h>
int main()
{
	char str[5] = "abcd";
	char* ps = str;
	printf("%p\n",str);
	printf("%p\n",ps);
	printf("%p\n", &str[0]);
	return 0;
}

运行结果:

可以看见打印出的地址一摸一样。

由此我们得出结论:对于数组来说,在本该出现指针的地方,使用了数组名,那么数组名就被当作首元素地址。

现在我们可以来谈谈 “二维数组” 了。

我们来考虑这段代码:

#include <stdio.h>
int main()
{
	int arr[10][20];
	return 0;
}

我们来试着理解 int arr[10][20]; 是什么意思:

 

 现在理解了 “二维数组” ,现在有一个问题:所有情况下数组名都是首元素地址吗?

我们来看一段代码:

#include <stdio.h>
int main()
{
	int arr[2][3] = { 1,2,3,2,3,4 };
	printf("%d\n", sizeof(arr));
	return 0;
}

我们使用操作符 sizeof 计算数组的大小,可见 arr 并不是一个地址。

所以这里有一个特例:如果数组名不是用在sizeof下,那么数组名就是首元素地址。

我们理解了二维数组,那我们想办法来操作它。

我们有 int arr[2][3] = {1,2,3,2,3,4}; ,那我们想输出第二个3,应该如何做?

#include <stdio.h>
int main()
{
	int arr[2][3] = { 1,2,3,2,3,4 };
	printf("%d\n", *(*(arr + 1) + 1));
	printf("%d\n", arr[1][1]);
	return 0;
}

现在就能输出第二个3了。

由此也可见,当我们使用数组下标,在一定程度上可以简化代码。

4.数组与函数参数

我们来看我们经常使用但是又经常忽略的一种函数传参方式。

#include <stdio.h>
int main()
{
	char str[] = "abcd";
	printf("%s\n", str);
	printf("%s\n", &str[0]);
	return 0;
}

我们要记得,我们把数组名 str 传给了 printf 函数,也就是把数组的首元素地址给了 printf 函数。

%s 它会自己顺着这个地址往后找,直到找到 '\0' 。

所以屏幕上会出现:

因为我们数组名作为参数传参被转化成数组首元素地址,所以,数组作为函数参数是毫无意义的。 

我们来谈谈二维数组的传参:

#include <stdio.h>

void print2(int (*arr)[3])
{
	for (int i = 0; i < 2; i++)
	{
		for (int j = 0; j < 3; j++)
		{
			printf("%d ", *(*(arr+i)+j));
		}
		printf("\n");
	}
}
void print1(int arr[2][3])
{
	for (int i = 0; i < 2; i++)
	{
		for (int j = 0; j < 3; j++)
		{
			printf("%d ", arr[i][j]);
		}
		printf("\n");
	}
}
int main()
{
	int arr[2][3] = { 1,2,3,2,3,4 };
	print1(arr);
	printf("\n");
	print2(arr);
	return 0;
}

输出结果:

可以看到 print1 和 print2 的效果一样。实际上 print1 和 print2 毫无差别,上面说过数组作为函数参数是毫无意义的,所以,print1的参数会自动转换为指针。

猜你喜欢

转载自blog.csdn.net/weixin_59913110/article/details/125221413