C语言——深入解析C语言指针:从基础到实践从入门到精通(三)

🏡润下 :个人主页
🔥个人专栏 : 《C语言基础》

🏔️山高万仞,只登一步!



文章目录

前面简单介绍指针访问数组,本节接介绍指针和数组的关系,如何用指针更高效,更快捷的访问数组!

一.数组名的理解

在前面我们在使用指针访问数组的时候通常用:

c 复制代码
int arr[10] = { 1,2,3,4,5,6,7,8,10 };
int* p = &arr[0];

使用&arr0的方式拿到了数组的首元素地址,但是也可以用arr获取首元素地址

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


发现数组名就是数组首元素(第一个元素)地址

如果数组名是首元素地址的话,用sizeof计算出来的地址大小应该是4/8

但是之前在用sizeof计算数组大小的时候,arr作为表达式时候计算的出来的是整个数组的大小

c 复制代码
#include<stdio.h>
int main()
{
	int arr[5] = { 1,2,3,4,5 };
	printf("%d\n", sizeof(arr));
	return 0;
}

输出的结果是20,如果是数组地址输出的应为4/8;

其实:数组名是首元素地址是正确的,但是有两个例外

sizeof(数组名),sizeof中单独放数组名,表示为整个数组计算的是整个数组的大小,单位是字节

&数组名,表示为整个数组,取出的是整个数组的地址(整个数组的地址和数组首元素的地址是有区别的 )
除此之外:数组名都表示数组首元素的地址

实例:

c 复制代码
#include<stdio.h>
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	printf("&arr[0] =%p\n", &arr[0]);//首元素地址
	printf("arr     =%p\n", arr);//首元素地址
	printf("&arr    =%p\n", &arr);//数组的地址
	return 0;
}

但是发现输出的结果都一样,那么数组的地址和数组首元素的地址到底有什么区别呢?
arr与&arr

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

&arr0+1相差4个字节,arr和arr+1相差4个字节,他们都是首元素的地址,+1跳过一个元素

&arr和&arr+1相差40个字节,因为&arr是数组的地址,+1跳过整个数组
指针类型决定±1跳过多少字节

二.使用指针访问数组

指针访问数组

c 复制代码
#include<stdio.h>
int main()
{
	int arr[10] = { 0 };
	int i = 0;
	int sz = sizeof(arr) / sizeof(arr[0]);
	int* p = arr;
	for ( i = 0; i <sz; i++)
	{
		scanf("%d", p + i);
	}
	for ( i = 0; i <sz; i++)
	{
		printf("%d ", *(p + i));
	}
	return 0;
}

由前面介绍知道,数组名arr是首元素的地址,用arr赋值给p,arr等价于p,那么我们可以用arr访问数组,是否也可以用pi访问数组

c 复制代码
#include<stdio.h>
int main()
{
	int arr[10] = { 0 };
	int i = 0;
	int sz = sizeof(arr) / sizeof(arr[0]);
	int* p = arr;
	for (i = 0; i < sz; i++)
	{
		scanf("%d", arr+ i);
	}
	for (i = 0; i < sz; i++)
	{
		printf("%d ", *(arr + i));
	}
	return 0;
}


结论 :

可以把下标引用操作符 当作加号 +可以进行交换律
指针让我们对空间多了一种访问方式

三.一维数组传参的本质

数组是无法在函数内部计算数组元素的个数的

c 复制代码
#include<stdio.h>
void test(int arr[])
{
	int sz2 = sizeof(arr) / sizeof(arr[0]);
	printf("sz2   =%d\n", sz2);
}
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	printf("sz1   =%d\n", sz);
	test(arr);
	return 0;
}

在test函数中没有正确得出元素个数

数组名是首元素地址,在作为参数传递的过程中传递的是数组名,实际上传递 的是数组首元素的地址 。因此函数内部计算的是地址的大小而不是数组的个数。函数参数部分是指针(地址),所以在函数内部是无法求数组元素个数的

因为传递的是指针,所以函数参数部分也可以写成指针的形式

c 复制代码
#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 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	printf("sz1   =%d\n", sz);
	test1(arr);
	test2(arr);
	return 0;
}

如果想要在函数内打印数组可以写成:

c 复制代码
#include<stdio.h>
void test(int* arr, int sz)
{
	int i = 0;
	for ( i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
}
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	printf("sz1   =%d\n", sz);
	test(arr,sz);
	return 0;
}

总结:一维数组传参,形参部分可以写数组的形式,也可以写成指针的形式

四.冒泡排序

排序思想:

相邻两个元素进行比较

c 复制代码
#include<stdio.h>
void Bubble_sort(int* arr, int sz)
{
	int i = 0;
	for ( i = 0; i < sz-1; i++)
	{
		int j = 0;
		for ( j= 0; j< sz-1-j; j++)
		{
			if (arr[j] > arr[j + 1])
			{
				int tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
			}
		}
	}
}
int  main()
{
	int arr[10] = { 0 };
	int i = 0;
	int sz = sizeof(arr) / sizeof(arr[0]);
	for ( i = 0; i < sz; i++)
	{
		scanf("%d", &arr[i]);
	}
	Bubble_sort(arr, sz);
	for ( i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

优化:

c 复制代码
#include<stdio.h>
void Bubble_sort(int* arr, int sz)
{
	int flag = 1;
	int i = 0;
	for (i = 0; i < sz - 1; i++)
	{
		int j = 0;
		for (j = 0; j < sz - 1 - j; 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)//如果flag==1说明没有进行交换,是有序
		{
			break;
		}
	}
}
int  main()
{
	int arr[10] = { 0 };
	int i = 0;
	int sz = sizeof(arr) / sizeof(arr[0]);
	for (i = 0; i < sz; i++)
	{
		scanf("%d", &arr[i]);
	}
	Bubble_sort(arr, sz);
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

五.二级指针

指针变量也是变量,是变量就有地址,指针变量用二级指针来存放

c 复制代码
#include<stdio.h>
int main()
{
	int a = 10;
	int* pa = &a;
	int** ppa =&pa;
	printf("%d\n", **ppa);
	return 0;
}

由图会发现ppa也有地址,也可以放在指针变量中,多级指针但是一般情况下不会超过二级指针

六.指针数组

指针数组还是数组 可以类比🚩:整型数组存放的是整数,字符型数组存放的是字符。

那么指针数组存放的是指针

数组类型 存放内容
整型数组 整数
字符型数组 字符
指针数组 指针


实例

c 复制代码
#include<stdio.h>
int main()
{
	int a = 10;
	int b = 20;
	int c = 30;
	int* arr[3] = { &a,&b,&c };
	return 0;
}

一个个创建指针变量太麻烦,可以创建一个指针数组里面存放指针变量

七.指针数组模拟和实现

c 复制代码
#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[3] = { arr1,arr2,arr3 };
	int i = 0;
	int j = 0;
	for ( i = 0; i < 3; i++)
	{
		for (j = 0;j < 5;j++)
		{
			printf("%d ", parr[i][j]);
		}
		printf("\n");
	}
	return 0;
}


注:二维数组是是连续存放的

总结

相关推荐
前进的李工1 小时前
Agent 学习笔记 05:系统提示词应该怎么写
笔记·学习·prompt·agent·个人开发·few-shot·ai应用开发
Zenova EdgeOS1 小时前
Go 工业边缘错误处理实战:用 errors 构建可追溯错误链
开发语言·数据库·golang
取名真是1 小时前
Python 算法知识点从基础到进阶
开发语言·python·算法
FRing031 小时前
vue2干货总结3(computed计算属性、watch监听器)
开发语言·前端·vue.js·vue2
正在走向自律2 小时前
【3/5】人工智能训练师 三级/高级工 考证学习方向:从“独立执行”到“设计、归因与全链条负责”
人工智能·学习·人工智能训练师·注方案设计·数据质控负责人·模型评测与调优辅助·ai训练项目交付
Fatbobman(东坡肘子)2 小时前
快速消失的硬盘容量 -- 肘子的 Swift 周报 #160
开发语言·人工智能·redis·ios·swiftui·iphone·swift
揽星河..3 小时前
【C语言】底层程序设计
c语言·开发语言
JavaPub-rodert3 小时前
从零搭建通用管理后台:ShiyuAdmin 的 Go、React 与 RBAC 实践
开发语言·react.js·golang
别问!问就是全会3 小时前
Jupyter Notebook 安装包下载|单元格分块运行,图表直接内嵌
ide·python·其他·jupyter
蒸蒸yyyyzwd3 小时前
后端学习笔记三个知识
笔记·八股