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

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

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



文章目录

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

一.数组名的理解

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

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

使用&arr[0]的方式拿到了数组的首元素地址,但是也可以用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;
}

&arr[0]+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访问数组,是否也可以用p[i]访问数组

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;
}


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

总结

相关推荐
知白守黑2674 小时前
docker网络
开发语言·php
细节控菜鸡4 小时前
【2025最新】ArcGIS for JS 范围裁剪(只保留特定区域显示),实现精准地理范围聚焦
开发语言·javascript·arcgis
焚 城4 小时前
UniApp中Flex布局学习
学习·uni-app
你真的可爱呀4 小时前
uniapp学习【整体实践】
前端·学习·uni-app·实践
一根甜苦瓜5 小时前
Go语言Slice的一道骚题
开发语言·后端·golang
驰羽5 小时前
[GO]Go语言泛型详解
开发语言·golang·xcode
NPE~5 小时前
[手写系列]Go手写db — — 第五版(实现数据库操作模块)
开发语言·数据库·后端·golang·教程·手写系列·手写数据库
润 下5 小时前
C语言——深入解析C语言指针:从基础到实践从入门到精通(二)
c语言·开发语言·经验分享·笔记·学习·程序人生
布伦鸽5 小时前
C# WPF DataGrid使用Observable<Observable<object>类型作为数据源
开发语言·c#·wpf