本人0基础开始学编程,我能学会的,你也一定可以,学会多少写多少。
下载安装请从官网入手,社区版本即可,这里主要使用的软件是VS2019,图标如下。
上一篇:从0开始学c语言-15-一维数组与二维数组的创建、初始化以及在内存中的储存、数组越界和数组作为函数参数_阿秋的阿秋不是阿秋的博客-CSDN博客
目录
接续上一篇
数组作为函数参数
书写形式
数组作为函数传参的时候
可以写成两种形式
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。
下一篇会进行数组相关的练习,先搞清楚这篇意思再说。