【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;
}
相关推荐
爱装代码的小瓶子1 小时前
数据结构之队列(C语言)
c语言·开发语言·数据结构
爱喝矿泉水的猛男2 小时前
非定长滑动窗口(持续更新)
算法·leetcode·职场和发展
YuTaoShao2 小时前
【LeetCode 热题 100】131. 分割回文串——回溯
java·算法·leetcode·深度优先
YouQian7723 小时前
Traffic Lights set的使用
算法
快乐飒男3 小时前
哈希表(c语言)
c语言·哈希算法·散列表
go54631584654 小时前
基于深度学习的食管癌右喉返神经旁淋巴结预测系统研究
图像处理·人工智能·深度学习·神经网络·算法
aramae4 小时前
大话数据结构之<队列>
c语言·开发语言·数据结构·算法
大锦终5 小时前
【算法】前缀和经典例题
算法·leetcode
想变成树袋熊5 小时前
【自用】NLP算法面经(6)
人工智能·算法·自然语言处理
cccc来财5 小时前
Java实现大根堆与小根堆详解
数据结构·算法·leetcode