从0开始学c语言-15-数组作为函数参数的地址、值与类型变化深度解析

发布于:2022-12-21 ⋅ 阅读:(401) ⋅ 点赞:(0)

本人0基础开始学编程,我能学会的,你也一定可以,学会多少写多少。

下载安装请从官网入手,社区版本即可,这里主要使用的软件是VS2019,图标如下。

 上一篇:从0开始学c语言-15-一维数组与二维数组的创建、初始化以及在内存中的储存、数组越界和数组作为函数参数_阿秋的阿秋不是阿秋的博客-CSDN博客

目录

数组作为函数参数

书写形式

还未进入函数的监视

 进入函数1

 进入函数2

总结

形参实参的对比

进入函数之前

进入函数1

进入函数2

 总结

数组名是什么?

代码演示


接续上一篇

数组作为函数参数

书写形式

数组作为函数传参的时候
可以写成两种形式
1·数组形式
2·指针形式

//形参数组形式
void test1(int arr[]) //10可写可不写,因为传过来是首元素的地址
{
}
//形参指针形式
void test2(int* arr) //这两种写法都可以,本质上都是指针,只不过是两种书写方式
{
}
int main()
{
	int arr[10] = { 0 };
	test1(arr);
    test2(arr);
	return 0;
}

调试来看看

还未进入函数的监视

在未进入函数的时候展开看一下,arr是首元素的地址,包含所有值,类型为int[10]

 ​​​​​可以看到arr和&arr在未进入函数的时候,地址和包含的值都一样,只有类型不一样。

 arr+1代表下一个元素的地址和值,类型为int*

*arr和arr[0]都是首元素的值,都为int类型。

 进入函数1

arr进入函数后,是首元素的地址和值,类型变为int*

&arr的地址有所变化,但是包含arr的地址与值,类型为int**

arr+1的地址、值、类型都未改变。

arr[0]和*arr也未发生改变。

 进入函数2

 可以看到函数2和函数1的图可以说是一模一样,这就是两种写法的监视图展示。

总结

名称 地址 类型
进入函数
arr 首元素地址 所有值 只有首元素

int

[数组大小]

int*
&arr 首元素地址 新地址(包含arr地址) 所有值 只有首元素

int

[数组大小]*

int**
arr+1 下一个元素地址 下一个元素的值 int*
arr[0] 首元素的值
 
int
*arr
*(arr+1) 下一个元素的值

写到这里,我想做个对比,之前在这篇文章里从0开始学c语言-14-关于(1)函数定义、函数分类、函数参数、函数调用以及函数练习_阿秋的阿秋不是阿秋的博客-CSDN博客

有写过形参和实参,但是我觉得还需要和数组对比来看才能更加清晰。

形参实参的对比

我们先拿来代码,这是一段需要交换两个数的值的代码。

void change1(int x, int y)//传值调用
{
	int z = x; //把z理解成空瓶,xy理解为酱油和醋
	x = y;
	y = z;
}
void change2(int* px, int* py)//传址调用
{
	int pz = *px; //通过x找到a,*x就相当于a
	*px = *py;
	*py = pz;
}
int main()
{
	int a = 9;
	int b = 98;
	printf("交换前:%d %d\n", a, b);
	change1(a, b);
	printf("交换后1:%d %d\n", a, b);
	change2(&a, &b);
	printf("交换后2:%d %d\n", a, b); 
	//a和b的地址不变,交换的只是存储的值	
	return 0;
}

我们可以看到,有传值调用和传址调用这两个书写形式,而我们在那个文章里总结的是

1·地址不会交换,只会交换储存的值

2·通过指针可以建立起函数和外界的联系,实现函数内外的数据同步。

这里我们再进行监视,深入剖析一下。

为了方便对比,我们把px和py改成x和y。

进入函数之前

&a和&b的类型是int*。

而*a和*b的a和b不是指针,所以没办法写成*a和*b。

这一点就和数组不一样,因为数组名字本身就代表首元素的地址,还是不多说了,指针这回事我还没出详细文章讲,现在就先记住不一样就行了!

进入函数1

 可以看到&x、&y的地址和&a、&b的地址并不一样,但是包含的值一样。

而在函数中的*x、*y的x和y甚至是未定义。(因为是传值调用啊,只有值怎么调用地址?)

进入函数2

这就可以看到什么叫做名副其实的传值调用了~

传过来的x、y与为进入函数前的&x、&y的地址与值相同(这里展示的是交换后的值)

而函数中的&x、&y则有了新的地址,但是会包含x、y对应的地址与值。

因为传过来的x与y是有地址的,所以此时的*x与*y便终于有了对应的值和类型!

 总结

名称 地址 类型
调用 传值 传址 传值 传址 传值 传址
x 与&a相同 int int*

与函数外传递过来的值

(没交换之前)相同

&x 新地址 新地址(包含&a) int* int**
*x 不存在 不存在 int 不存在 相同

就总结到这里,后续学了指针会理解更深刻一些。

数组名是什么?

数组名是首元素的地址
两个例外:数组名会代表整个数组
1、sizeof(数组名) 中的数组名代表整个数组,计算的是整个数组的大小,单位是字节(函数调用中的sizeof(数组名)中的数组名包含首元素的大小
2、&数组名  中的数组名代表整个数组,取出整个数组的地址

代码演示

int main()
{
	int arr[10] = { 0 };
	printf("%p\n", &arr);
	printf("%p\n\n", &arr+1); //加了十进制的40,十六进制的28

	printf("%p\n", arr);
	printf("%p\n\n", arr+1);  //加了4字节

	printf("%p\n", &arr[0]);
	printf("%p\n\n", &arr[1]);
	return 0;
}

第一组printf,&arr+1代表加了整个数组大小。

第二组printf,arr+1代表加了一个元素的大小。

第三组printf,&arr[0]实际上就是arr,&arr[1]实际上就是arr+1。

 下一篇会进行数组相关的练习,先搞清楚这篇意思再说。

下一篇:从0开始学c语言-16-数组以及数组传参应用:冒泡排序_阿秋的阿秋不是阿秋的博客-CSDN博客


网站公告

今日签到

点亮在社区的每一天
去签到