【C语言_指针[2]_复习篇】

目录

一、数组名的理解

二、使用指针访问一维数组中的每个元素

三、一维数组传参的本质

四、冒泡排序

五、二级指针

六、指针数组

七、指针数组模拟二维数组


一、数组名的理解

  1. ++一般情况下,数组名就是数组首元素的地址++。

  2. ++特殊情况1:sizeof(数组名)++ ,这里的数组名指的是整个数组,++sizeof计算的结果也将是整个数组的大小++。

  3. ++特殊情况2:&数组名++ ,这里取到的地址是++整个数组的地址++。

  4. ++数组首元素的地址和数组的地址两者的区别++:指针变量进行+-整数操作时,向前向后一步移动的距离是有差异的,例如下图代码,arr == &arr[0] != &arr,当arr和&arr的地址同时进行+1操作时,arr的地址移动的是4个字节,而&arr的地址移动的是40个字节。

0x....A4 - 0x....CC = 10*16+4+1 - 12*16+12*1= -40。

  1. 注意不要混淆:++数组名一般情况下是数组首元素的地址++ ,++函数名是函数的地址++ ,++而变量名不能理解成变量的地址,它仅仅代表变量本身而已++。

二、使用指针访问一维数组中的每个元素

  1. 请注意!++指针变量本身就是地址++ ,p == arr。++如果想直接使用拿到的地址,也可以不进行把地址存入指针变量的操作,直接将地址当作指针变量进行解引用、+- 整数操作也行++。

  2. arr[i] 的不同写法理解:.......

① ++arr[i] 本质是 *(arr+i)++,通过数组首元素地址偏移并解引用地址,即可找到数组中的每一位元素。

② ++[i]arr 是 *(arr+i) 交换律的产物++,即 [i]arr 的本质是 *(i+arr),不过很少在代码中如此表达。

3.++总之,++当我们想要访问一个数组每个元素时,可以利用数组首元素地址arr或存有数组首元素地址的指针p+ [i],表示利用数组首元素地址偏移并解引用找到地址所指向的变量,arr[i] == p[i],或写成 i[arr]==i[arr];也可以写成这种形式 *(arr+i)=*(p+i) 。

cpp 复制代码
//使用指针访问一维数组中的每个元素
int main()
{
	int arr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	int* p = arr;//数组名是数组首元素的地址,地址所指向的变量是int类型
	int i = 0;//循环变量
	for (i = 0; i < sz; i++)
	{
		//一边输入,一边输出
		scanf("%d", p + i);
		printf("%d ", *(p + i));//利用地址偏移并解引用地址找到指针所指向的数组元素

		//写法二:利用地址直接代替指针
		//scanf("%d", arr + i);
		//printf("%d ", *(arr + i));

		//写法三:arr与i实行交换律的产物
		//scanf("%d", p + i);       //arr[i]==*(p + i)==*(arr + i)
		//printf("%d ", i[arr]);    //*(arr + i)==*(i + arr)==i[arr]
								    //即arr[i]本质是*(arr+i)
								    //即[i]arr本质是*(i+arr)
	}
	return 0;
}

三、一维数组传参的本质

  1. ++一维数组传参,本质上传递的是数组⾸元素的地址++ ,而不是整个数组,也不是整个数组的地址。

2.++数组的大小只能在自己所被创建的函数中求,所以我们常常把数组的大小作为一个函数的参数一起传给自定义函数++。

test(arr, sz);//sz是数组arr的大小

  1. ⼀维数组传参,++形参的部分的两种写法:① 直接写成数组的形式++ ,②++写成指针变量的形式,但这两种写法形参的本质都是数组首元素地址,只是有不同写法而已。++

void test(int arr[ ]); == void test(int* p);

  1. 注意理解:++一维数组传参属于传址调用++。
cpp 复制代码
//在函数内部求数组的大小
//结论:数组传参本质上传递的是数组⾸元素的地址,而不是整个数组
//      数组的大小只能在自己所被创建的函数中求

void test(int arr[])//现在的arr是存有数组首元素地址的指针,x86下指针的大小是4字节
{
	int sz2 = sizeof(arr) / sizeof(arr[2]);//这里的arr[i]==*(arr+i)表示一个整型变量
										   //大小为4字节
	printf("sz2=%d\n", sz2);//打印1
}

int main()
{
	int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	int sz1 = sizeof(arr) / sizeof(arr[0]);
	printf("sz1=%d\n", sz1);//打印10
	test(arr);//掉用test函数求arr的大小
	return 0;
}
cpp 复制代码
//用函数调用的方式打印一维数组中的内容

//形参写法一:
void Print(int* p, int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", *(p + i));
	}
}

形参写法二:
//void Print(int arr[], int sz)
//{
//	int i = 0;
//	for (i = 0; i < sz; i++)
//	{
//		printf("%d ", arr[i]);
//	}
//}

int main()
{
	int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	Print(arr, sz);//将一维数组首元素的地址和数组的大小一并传给了Print函数
	return 0;
}

四、冒泡排序

  1. 排序的趟数==元素个数-1。

  2. 每趟排序结束后,下一趟最高的数组下标要在现有基础上-1。

  3. 在开始冒泡排序前利用flag=1假设原本数组的排序就是最终想要的序列,如果一旦在第一趟冒泡排序中,程序没有进入到交换阶段,那么这个序列一定就是最终想要的序列,否则就继续正常进行冒泡排序。

cpp 复制代码
void Bubble_sort(int arr[], int sz)
{
	int flag = 1;
	int i = 0, j = 0;
	for (i = 0; i < sz - 1; i++)
	{
		for (j = 0; j < sz - i; j++)//趟数==元素个数-1
		{
			if (arr[j] < arr[j + 1])
			{
				flag = 0;
				int tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
			}
		}
		if (flag)
		{
			break;
		}
	}
}

void Print(int arr[], int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
}

int main()
{
	int arr[] = { 1, 2, 3, 4, 5, 6 ,7 ,8 ,9 ,10 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	Bubble_sort(arr, sz);
	Print(arr, sz);
	return 0;
}

五、二级指针

  1. 二级指针就是++存放指针变量地址的指针变量++。

  2. ++对二级指针两次解引用就可以找到其对应一级指针所指向的变量++。

cpp 复制代码
int main()
{
	int n = 0;
	int* p = &n;
	int** p2 = &p;//二级指针,第二颗*表示p2是一个指针变量,int*表示所指向的变量类型
	**p2 = 20;//*p2==p, 而*p==n,所以**p2==n
	printf("%d\n", n);//打印20
	return 0;
}

六、指针数组

  1. ++指针数组就是存放指针的数组,数组中的每个元素都是指针(地址)++。

  2. ++指针数组的类型是由数组中每个指针的类型决定的++。

cpp 复制代码
int main()
{
	int arr1[] = { 1, 2, 3 };
	int arr2[] = { 2, 3, 4 };
	int arr3[] = { 3, 4, 5 };

	int* arr[3] = { arr1, arr2, arr3 };//指针数组
	//由于数组名是数组首元素的地址,每个数组首元素的地址又是int*类型的
	//所以arr指针数组的类型是int*[3]

	return 0;
}

七、指针数组模拟二维数组

  1. 模拟的⼆维数组,并⾮完全是⼆维数组,因为每⼀⾏的数据在内存中是⾮是连续的。

  2. 下图代码的解释:parr是数组首元素的地址,而parr首元素的地址是数组arr1的地址,我们可以通过对parr+-整数拿到parr中每个元素的地址,即内部每个数组的地址,再通过对这些地址解引用拿到,每个内部数组首元素地址,最后通过首元素的地址偏移和解引用,找到parr内部数组中的每个元素,即有了 *(*(arr+i) + j) == parr[i][j] 。

cpp 复制代码
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;
}
相关推荐
Fantasydg几秒前
DAY 35 leetcode 202--哈希表.快乐数
算法·leetcode·散列表
jyyyx的算法博客1 分钟前
Leetcode 2337 -- 双指针 | 脑筋急转弯
算法·leetcode
SweetCode13 分钟前
裴蜀定理:整数解的奥秘
数据结构·python·线性代数·算法·机器学习
ゞ 正在缓冲99%…26 分钟前
leetcode76.最小覆盖子串
java·算法·leetcode·字符串·双指针·滑动窗口
xuanjiong27 分钟前
纯个人整理,蓝桥杯使用的算法模板day2(0-1背包问题),手打个人理解注释,超全面,且均已验证成功(附带详细手写“模拟流程图”,全网首个
算法·蓝桥杯·动态规划
小郝 小郝38 分钟前
【C语言】strstr查找字符串函数
c语言·开发语言
惊鸿.Jh1 小时前
【滑动窗口】3254. 长度为 K 的子数组的能量值 I
数据结构·算法·leetcode
明灯L1 小时前
《函数基础与内存机制深度剖析:从 return 语句到各类经典编程题详解》
经验分享·python·算法·链表·经典例题
碳基学AI1 小时前
哈尔滨工业大学DeepSeek公开课:探索大模型原理、技术与应用从GPT到DeepSeek|附视频与讲义免费下载方法
大数据·人工智能·python·gpt·算法·语言模型·集成学习
补三补四1 小时前
机器学习-聚类分析算法
人工智能·深度学习·算法·机器学习