一.传值调用和传址调用
#include <stdio.h>
// 传值调用
void swap1(int a, int b) {
int temp = a;
a = b;
b = temp;
printf("函数内: a=%d, b=%d\n", a, b);
}
// 传地址调用
void swap2(int* a, int* b) {
int temp = *a;
*a = *b;
*b = temp;
printf("函数内: *a=%d, *b=%d\n", *a, *b);
}
int main() {
int x = 10, y = 20;
printf("原始值: x=%d, y=%d\n", x, y);
// 传值调用
swap1(x, y);
printf("传值调用后: x=%d, y=%d\n\n", x, y);
// 传地址调用
swap2(&x, &y);
printf("传地址调用后: x=%d, y=%d\n", x, y);
return 0;
}
通过运行这段代码,我们会发现,swap1函数在函数内部完成了数据交换,但传值调用后仍没有达到理想的效果,这是因为他们调用函数的方式不一样。实参传递给形参的时候,形参也会创建一份临时空间来接受实参,对形参的修改不影响实参,所以swap1行不通。
为了解决问题,我们可以用传址调用,直接改变两个变量的地址,这样就可以实现两个数的交换了。
二.数组名的理解
除了一下两种情况,数组名就是元素的首地址。
1.sizeof(数组名):sizeof中放入数组名,计算的是整个数组的大小,这里的数组名表示整个数组,单位是字节。
2.&数组名,这里的数字名表示整个数组,去除的是整个数组的地址。
除此之外,任何地方使用数组名,数组名都表示受元素地址。
代码示例:
#include <stdio.h>
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
printf("%p\n",&arr[0]);//数组首元素地址,整形指针。
printf("%p\n",&arr[0] + 1);//加了4个字节
printf("%p\n",arr);//数组元素首地址,整形指针。
printf("%p\n",arr+1);//加了四个字节
printf("%p\n",&arr);//这里arr代表整个数组,数组指针 --> int(*p)[10]
printf("%p\n",&arr + 1);//加了40个字节
printf("%d\n",sizeof(arr));//这里arr表示整个数组,整型数组一个元素4个字节,一共40个字节,打印40。
return 0;
}
三.一维数组传参的本质
数组名是数组首元素的的地址 --> 本质上数组传参传递的是数组元素的首地址。
所以一维数组传参,形参的部分可以写成数组形式,也可以写成指针形式。
#include <stdio.h>
void test1(int arr[])//参数写成数组形式,本质上还是指针
{
printf("%d\n", sizeof(arr));
}
void test2(int* arr)//参数写成指针形式
{
printf("%d\n", sizeof(arr));//计算一个指针变量的大小
}
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
test1(arr);
test2(arr);//打印结果一样
return 0;
}
四.冒泡排序
4.1冒泡排序的思想是:两两相邻的元素进行比较。
4.2案例:升序排序一个一维数组。
1,思路:

2.代码示例:
#include <stdio.h>
void bubble_sort(int arr[],int sz)
//参数:arr - 待排序数组,sz - 数组长度
{
int i = 0;
//外层循环
for ( i = 0; i < sz - 1; i++)
{
int flag = 1;//假设本轮有序
//内层循环:每轮将最大值放到末尾
int j = 0;
//每轮冒泡都会将最大值移至末尾,末尾 i 个元素已有序,内层循环边界sz-1-i跳过有序尾部,减少无效比较。
for ( j = 0; j < sz - 1 - i ; j++)
{
//相邻数比较
if (arr[j] > arr[j + 1])
{
flag = 0;//发生了交换,所以还未完全有序
int tmp = arr[j];//三步交换
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
}
}
if (flag == 1)//本轮没有任何交换
{
break;//数组已有序,提前结束
}
}
}
void print_arr(int arr[],int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ",arr[i]);
}
printf("\n");
}
int main()
{
int arr[] = { 9,8,7,6,5,4,3,2,1,0 };// 0 1 2 3 4 5 6 7 8 9
int sz = sizeof(arr) / sizeof(arr[0]);
bubble_sort(arr, sz);
print_arr(arr, sz);
return 0;
}
五.二级指针
指针就是变量,变量也有地址,那么他地址放在哪里呢?就放在二级指针中。
六.指针数组
1.整型数组是存放整型的数组,字符数组是存放字符的数组,由此可以推出指针数组是存放指针的数组。
2.举例:int (*p)5
七.模拟实现二维数组
1.思路:

2.代码示例:
#include <stdio.h>
int main()
{
int arr1[] = { 1,2,3,4,5 };
int arr2[] = { 2,3,4,5,6 };
int arr3[] = { 3,4,5,6,7 };
//数组名是数组首元素的地址,类型是int*的,就可以存放在parr数组中
int* parr[3] = { arr1, arr2, arr3 };//数组名是首元素地址
int i = 0;
int j = 0;
//外层循环:打印3个数组
for (i = 0; i < 3; i++)
{
//内层循环:打印每个数组的5个元素。
for (j = 0; j < 5; j++)
{
printf("%d ", parr[i][j]);
}
printf("\n");
}
return 0;
}
3.注意:这个代码只是模拟了二维数组的效果,并不是二维数组,二维数组的每一行是连续存储的。