指针的深入理解(三)

指针的深入理解

前言

哈喽,各位小伙伴大家好!好久不见,今天小编继续带着大家深入理解指针。今天的内容可能会有点难理解,不过走上坡路总是吃力的!加油,向大厂冲锋!杀gigi!

一.一维数组传参的本质

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
void test(int *arr)//接收数组首元素地址
{
	int len1 = sizeof(arr) / sizeof(arr[0]);//arr数组首元素的地址,64位环境下指针大小为8字节
	printf("%d", len1);//                     首元素int类型4个字节 8/4=2
}
int main()
{
	int arr[10] = { 0 };
	int len = sizeof(arr) / sizeof(arr[0]);//sizeof(数组名)计算的是整个数组的大小=40
	printf("%d\n", len);//                 首元素int类型4个字节 40/4=10
	test(arr);//arr数组名,没有&,也没有单独放在sizeof里,是数组首元素地址
	return 0;
}

大家看一下这段代码,大家觉得代码输出的结果是什么?有人会觉得都是数组的大小/数组受元素的大小==40/4=10。那结果就是两个10。是不是呢?

大家可以看到结果是一个10,一个2。那2是咋来的呢?这里就涉及到了一维数组传参的本质。test(arr)这里的数组名没有&,也没有单独放在sizeof里面,所以这里的arr是数组首元素的地址。所以test函数的sizeof(arr)这里的arr不是数组的地址,是数组首元素的地址。地址就是指针,指针的大小在64位环境下是8个字节8/4=2。所以一维数组传参的本质传的是数组首元素的地址,写成数组接收是为了方便理解,实际本质上传的是地址,用指针变量接收

  1. 结论一:一维数组传参的本质是传数组首元素的地址。

二.冒泡排序(优化版)

冒泡排序


大家可以看到, 冒泡排序的思想就是进行 n-1躺的排序每趟排序从左向右或从右到左进行 相邻两数的比较交换满足条件就交换,每次比较后两个比较数字向左或向右 移动一位。每趟进行 n-1-i次排序,每趟排序将 最大或最小的数排序好。所以我们用 for循环控制趟数,里面嵌套一层 for循环控制每趟比较次数if判断是否满足,满足就叫 交换即可。

但是像这样的数组 无需排序,如果按照 原来的思路仍会按部就班的排序,所以我们可以对他 进行优化。用 flag做标记判断是否数组 本身就是有序,如果是就直接 break跳出即可。

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int count = 0;
void bubble_sort(int arr[],int sz)
{
	for (int i = 0; i < sz - 1; i++)//控制趟数
	{
		int flag = 0;
		for (int j = 0; j < sz - 1 - i; j++)//控制比较次数
		{
			count++;//记录循环次数
			if (arr[j] > arr[j + 1])//判断是否交换
			{
				flag = 1;
				int tmp = arr[j + 1];
				arr[j + 1] = arr[j];
				arr[j] = tmp;//交换
			}
		}
		if (flag == 0)
			break;//已经排好序直接结束循环
	}
	printf("count=%d\n", count);//输出循环次数
}
void printf_arr(int arr[], int sz)
{
	for (int 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]);//数组长度
	bubble_sort(arr,sz);
	printf_arr(arr, sz);
	return 0;
}

这里我们用count变量记录循环次数,对比优化前后的循环次数

  • 优化前
    在这里插入图片描述
  • 优化后

    大家可以看到优化前需要循环45次优化后循环9次即可。这就是优化后的效果

三.二级指针

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
	int a = 10;
	int* p = &a;//一级指针
	int** pp = &p;//二级指针
	int*** ppp = &pp;//三级指针
	printf("%d", ***ppp);//三级指针解引用三次,才能找到一级指针指向的变量
	return 0;
}

指针变量也是变量,是变量就有地址,那指针变量的地址存在哪里呢?答案是存在二级指针二级指针就是接收一级指针地址的指针。以此类推,三级指针就是接收二级指针地址的指针

在这里插入图片描述

*说明这是一个指针,前面的int加上一个星号说明指针指向的是个一级指针,那么这个指针就是二级指针。大家可以发现有多少个星号就说明这是几级指针。

  1. 结论二:二级指针是存放一级指针地址的指针,有多少个星号说明是几级指针。

四.指针数组

4.1指针数组的概念

指针数组有数组又有指针,那他是指针还是数组呢?这里我们不妨类比一下。

这里我们就知道指针数组其实是数组,是一个每个元素为指针的数组,可以是字符指针数组,也可以是整形指针数组。那指针数组变量的类型是什么呢?

  • 整形指针数组
  • int* arr[10] 数组有十个元素,每个元素是一个整形指针。
  • 字符指针数组
  • char* arr[10] 数组有十个元素,每个元素是一个字符指针。
    所以我们又可以得出一个结论:
  1. 结论三:指针数组是数组,每个元素是一个指针。

4.2指针数组模拟二维数组

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
	int a[5] = { 1,2,3,4,5 };
	int a1[5] = { 2,3,4,5,6 };
	int a2[5] = { 3,4,5,6,7 };
	int* arr[3] = { a,a1,a2 };//存放三个数组首元素的地址,是一个指针数组。
	for (int i = 0; i < 3; i++)
	{
		for (int j = 0; j < 5; j++)
		{
			printf("%d ", arr[i][j]);//arr[i]拿到第i个数组的首元素的地址,
		}//                          arr[i][j]拿到第i个数组的首元素的地址后
		printf("\n");//              访问该数组第j个元素。
	}
	return 0;
}


我们创建一个指针数组存放三个数组首元素的地址,所以arr[i]就能拿到数组的地址arr[i][j]拿到数组地址后通过下标j来访问数组的每个元素。这里我们就实现了二维数组的模拟。
在这里插入图片描述

五.字符指针变量

5.1字符指针指向字符

字符指针前面我们已经有所提及了,一般使用情况是这样子的。

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
	char ch = 'w';
	char* pc = &ch;
	printf("%c\n", *pc);
	*pc = 'q';
	printf("%c\n", ch);
	return 0;
}

字符指针是不是只能指向单个字符呢?答案是否定的。

5.2字符指针指向字符串

字符指针不止可以指向单个字符,也能指向字符串。

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
	char* pc = "hello world";//放的是字符串首字符的地址
	printf("%c\n", *pc);//打印第一个字符
	return 0;
}

那这时的字符指针变量又该如何理解呢?是把整个字符串放在指针里面吗不是的。我们可以吧字符串理解为一个字符数组,把数组名也就是数组首元素的地址赋给pc
所以代码其实下面这个和这个的效果是一样的。

int main()
{
	char arr[] = "hello world";//放的是字符串首字符的地址
	char* pc = arr;
	printf("%c\n", *pc);//打印第一个字符
	return 0;
}


在这里插入图片描述
那这两个代码是不是等价的呢?注意这两个代码还是有区别的第一段代码pc指向的是常量字符串,而第二段代码是把字符串放在数组中,数组是可以修改的。这里我们来验证一下。

大家可以看见,当我们解引用修改变量时直接报错。说明常量字符串是不可修改的。

  1. 结论四:字符串放在指针的是首字符的地址,常量字符串不可修改。

5.3代码练习

学以致用,接下来我们看一下这代码的结果

int main()
{
	char str1[] = "hello bit";
	char str2[] = "hello bit";
	char *str3 = "hello bit";
	char *str4 = "hello bit";
	if (str1 == str2)
		printf("str1 and str2 are same\n");//1
	else
		printf("str1 and str2 are not same\n");//2
	if (str3 == str4)
		printf("str3 and str4 are same\n");//3
	else
		printf("str3 and str4 are not same\n");//4
	return 0;
}

大家觉得这段代码的结果是啥呢?

发现结果是2和3。为什么呢?

数组有自己独立的空间,两个数组的空间是不同地址也就不同。但是str3和str4指向的是两个相同内容的常量字符串,两份相同的常量字符串没必要保存两份,所以他们都指向同一块空间,都指向h的地址。

后言

今天的内容还是挺多的,需要大家多加消化。感谢大家的耐心阅读,今天就分享到这里,咱们下期间见!拜拜咯~

  • 26
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 12
    评论
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大白的编程日记.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值