数组和指针的部分知识点

今天在学习C语言的时候学到了一些关于数组和指针的比较重要的知识点

数组名本质上是数组首元素的地址

#include<stdio.h>
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	printf("%p\n", arr);
	printf("%p\n", &arr[0]);
	return 0;
}

 由代码可以看出,当打印arr的地址和打印arr[ 0 ]的地址的时候,输出的结果是相同的。

给函数传递数组,数组参数应该由指针变量或数组名+[]来接收

​

#include<stdio.h>
void print(int* m)
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	print(arr);
	return 0;
}

​

​

也可以使用数组名+[ ]来接收([ ] 中有没有数字都可以),这样写可以让别人很同意就看出来该函数接收了一个数组的传递。二者本质上是一样的。


#include<stdio.h>
void print(int m[10])
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	print(arr);
	return 0;
}

​

​

给函数传递数组的时候,只传递了首元素的地址,并没有将整个数组传递到函数中

#include<stdio.h>
void print(int *m)
{
	int sz = sizeof(m) / sizeof(m[0]);
	printf("%d\n", sz);
}
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	printf("%d\n", sz);
	print(arr);
	return 0;
}

在主函数中,求数组的长度sz可得到sz的值为10,在print函数中sz的值为2,因为在print函数中,m为数组首元素的地址,sizeof(m)得到的值为8(我用的是64位的电脑,所以地址长度为8,如果使用32位的电脑,sizeof(m)得到的值为4,最后结果为1,这里不必纠结),而m[ 0 ]是具体的int类型的值,长度为4,所以sz的值为2。也就说明在给函数传递数组的时候,并没有将整个数组传递给函数,只是传递了该数组的首元素的地址。

在函数中是无法求得数组的长度的,只能通过传递的方式获取数组长度。

#include<stdio.h>
void print(int *m,int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", m[i]);
	}
}
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	print(arr, sz);
	return 0;
}

运行结果为

 指针和数组

数组元素在内存中是连续存放的。我们可以通过数组的第一个元素的地址求到该数组的其他元素。

先看代码

#include<stdio.h>
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int* p = &arr[0];
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%p  %p\n", p + i, &arr[i]);
	}
	return 0;
}

 运行结果

从运行结果我们发现,当把arr的起始地址赋值给p的时候, p+i 等价于 &arr[ i ]。 p+i 就是下标为 i 的元素的地址。

 以下代码是比较常见的打印数组中各个元素的写法

#include<stdio.h>
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

当我们知道 p+i 就是下标为 i 的元素的地址 就可以

#include<stdio.h>
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int* p = &arr[0];
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", *(p + i));
	}
	return 0;
}

两种方式的运行结果是一样的

有人可能会有疑惑:对于 int 类型的数组,如果p是arr的起始地址,那为什么 p+1 是arr的第二个元素的地址而不是 p+4是arr的第二个地址呢,相邻的两个元素之间的地址不应该相差4个字节吗?

其实是这样的,int 型的指针+1 意思是跳过一个整形,得到的是下一个元素,而不是地址+1。

如果是char 类型的指针,+1跳过的是一个字符,得到下一个元素。

我们刚刚讲到:数组名是数组首元素的地址,也就是arr 等价于 &arr[ 0 ](该文章的第一个代码),既然我们可以写 int*p=&arr[ 0 ],arr 等价于 &arr[ 0 ],那我们同样可以写成 int* p=arr,二者是等价的。出现arr的地方 我们可以换成p 同理,出现p的地方 我们可以换成arr。既然这样,上面的代码可以写成如下

#include<stdio.h>
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int* p = arr;
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", *(arr + i));
	}
	return 0;
}

同样也可以是这样的

#include<stdio.h>
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int* p = arr;
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", p[i]);
	}
	return 0;
}

运行结果是一样的。

我们知道   printf("%d ", arr[ i ])  可以打印下标为 i 的元素的内容 , printf("%d " , *(arr+i)) 同样可以打印下标为 i 的元素的内容,事实上arr[ i ] 本质上是通过 arr+i 然后解引用得到数组内容,也即是说arr[ i ] 本质上是 *(arr+i) 。

既然 arr[ i ] 本质上是*(arr+i) ,而根据加法交换律 *(arr+i) 可以写成 *( i+arr ),既然可以写成           *( i+arr )  那么是不是也可以写成 i[ arr ] 呢? 我们试一试

#include<stdio.h>
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", i[arr]);
	}
	return 0;
}

得到运行结果

我们发现这样也是可以的。下面来解释一下

我们知道 ’ [ ] ‘ 是下标引用操作符,arr [ i ] 本质上是 *( arr+i ) ,我们可以理解成 arr 和 i 是 ‘ [ ] ’ 操作符的两个操作数 ,这样理解就可以明白为什么可以写成 i[ arr ] 了。

在此声明一下,本人刚刚所写的内容,只是为了让大家可以更加深刻地理解数组和指针,内容中部分代码的写法虽然正确,但是并不提倡这样写。比如 arr [ i ] 可以写成 i[ arr ] ,虽然可以这样写,这样写没有错误,但是并不提倡这样写,因为这样写太不直观了。

以上全部内容可能对于部分朋友来说可能排版有点乱,如果有不懂的地方希望大家可以自己动手实践一下,只有自己动手实践,才能对知识点有更深的理解。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值