C语言指针详解2

一.传值调用和传址调用

复制代码
#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.注意:这个代码只是模拟了二维数组的效果,并不是二维数组,二维数组的每一行是连续存储的。