畅玩指针内功修——进阶篇(壹)

         Hi~你好呀,这里是刹那芳间,浅算一下,距离上次更博客已经过去两个月啦~确实,我也没有想到还会有这么多小伙伴关注俺,soooooo俺又回来写博客啦!!!🙌😆💕(谢谢大家的关注~)最近正在学习指针,所以会整理出一篇指针的合集,希望对你有帮助~一起进步~~

前言

之前有在学校学习过指针,但内容是比较浅显的啊,相信很多学校都是这样子的,所以现在正学的是指针进阶,较之前会有一些些拔高,不管之前学得如何,请具备空杯心态,继续学习,打起精神,认认真真,不要急~慢慢消化~

📚关于指针的简单介绍:

1.指针是一个变量,用来存放地址,地址唯一标识一块内存空间;

 2.指针的大小是固定的4/8个字节(32位平台/64位平台);

这里是个很重要容易误以为的点,曾经的我也以为char型的指针大小是一个字节,但不是,实际情况是,char型的指针大小和int型的指针大小都是4个字节,至于是4还是8,看运行平台,在vs2019的x86环境下是4个字节,x64是8个字节。

3.指针是有类型,指针的类型决定了指针+-整数的步长,指针解引用操作时的权限;

一个char型的指针  +1向后跳一个字节    -1向前走一个字节                                             

一个int型的指针     +1向后跳四个字节    -1向前走四个字节

4.指针的运算

具体接触了三种:                                                                                                                 

1.指针 +- 整数                                                                                                                       

 2.指针 - 指针                                                                                                                         

3.指针的关系运算


1.字符指针

一般场景:改变字符

 Besides, 也可以这样使用:

#include <stdio.h>
int main()
{
	char* p = "abcdef";//p是指针变量,存储的是字符串首元素a的地址
	printf("%c\n", *p);//打印第一个字符,即a
	printf("%s\n", p);//打印整个字符串,即abcdef
	return 0;
}

在我所用的编译器环境下,指针的大小是4个字节,字符串abcdef再加上个'\0',是7个字节,指针变量p是存不下的,所以规定无论哪个编译器,将一个常量字符串放到一个指针变量里,指针变量存储的是该字符串的第一个字符的地址。

这里的" "双引号内的字符串是常量字符串,里面的内容是不能被改变的,

比如:

想要将这个字符串的第一个元素变成字符w,于是你写了这么一个代码:

 好家伙,喵喵喵,报错 error   运行了  异常

所以有些时候在定义一个常变量时,前面加一个const , 对于在写一个很长的代码的时候,出现错误时可以减轻一些调试量,加const,欲改变这个常变量,编译器是不让通过的,无法编译

 一道面试题:(思考一下)

#include <stdio.h>
int main()
{
	const char* p1 = "abcdef";
	const char* p2 = "abcdef";
	char arr1[] = "abcdef";
	char arr2[] = "abcdef";
	if (p1 == p2)
	{
		printf("p1==p2\n");
	}
	else
	{
		printf("p1!=p2\n");
	}
	if (arr1 == arr2)
	{
		printf("arr1==arr2\n");
	}
	else
	{
		printf("arr1!=arr2\n");
	}
	return 0;
}

这里的运行结果最终是什么样子呢?                                                                                             

恭喜你~说对了~

 详解:

变量p1所指向的字符串是abcdef,变量p2所指向的字符串也叫做abcdef,这两个字符串都是常量字符串并且相同,都不能被修改,试问,在电脑中有没有必要保留两份吗?

答案很简单,电脑中保存一份,共用 ,这样子,内存空间会得到一定的节省。                           

所以p1和p2指向的是同一个字符串abcdef,它们所存储的地址一模一样,所以p1==p2

char arr1[] = "abcdef";
char arr2[] = "abcdef";

这两句代码的意思是用字符串abcdef去初始化arr1和arr2这两个数组,这两个数组是不一样的,它们在内存中有着独立的空间,数组名表示首元素的地址,所以arr1!=arr2


2.指针数组

存放指针的数组。

📚类比理解:

int arr[10];  //整型数组,存放整型的数组

char ch[2];  //字符数组,存放字符的数组

使用场景(一): (特意将地址直接初始化数组中的这种情况是比较少见的)

#include <stdio.h>
int main()
{
	int a = 10;
	int b = 20;
	int c = 30;
	int* arr[3] = { &a,&b,&c };//arr就是一个指针数组
	int i = 0;
	for (i = 0; i < 3; i++)
	{
		printf("%d ", *(arr[i]));//对这个地址(指针)解引用
	}
	return 0;
}

程序运行结果:

使用场景(二):

#include <stdio.h>
int main()
{
	int arr1[5] = { 1,2,3,4,5 };
	int arr2[5] = { 2,3,4,5,6 };
	int arr3[5] = { 3,4,5,6,7 };
	int* parr[3] = { arr1,arr2,arr3 };
	int i = 0;
	for (i = 0; i < 3; i++)
	{
		int j = 0;
		for (j = 0; j < 5; j++)
		{
			//printf("%d ", parr[i][j]);
			printf("%d ", *(parr[i] + j));
		}
		printf("\n");
	}
	return 0;
}

 这有点像一个二维数组,不是吗?🤸‍♀️

3.1 数组指针

数组指针是能够指向数组的指针,不是数组

int* p1[10];        指针数组

int (*p2)[10];      数组指针

巧记:

[ ]的优先级高于 *

p1先与[ ]结合,说明p1是一个数组,再看int* ,说明p1数组里存的是整型指针,即指向整型的指针;

( ) 优先,所以p2先与 * 结合,说明p2是一个指针变量,然后指针指向的是一个大小为10个整型的数组

 arr 和 &arr  在数值上相同,但类型不同。

 arr 是数组名,也是首元素的地址,类型是 int*

&arr 是整个数组的地址,类型是 int (*)[10] ,[ ]内的数字不能省


3.2 数组名

通常情况下,人们所说的数组名指的首元素的地址,

但是有两个例外:

1. sizeof(数组名),这里的数组名表示的是整个数组,sizeof(数组名) 计算的是整个数组的大小;

2. &(数组名) ,这里的数组名表示的也是整个数组, &(数组名) ,取得是整个数组的地址。


3.3 数组指针有什么好处

一般会用在二维数组

函数传参时,二维数组传过去,用数组指针指向一维数组,进行降维,会更加方便。

任务列表:

写一个函数打印一个二维数组。

法一:

#include <stdio.h>
void printf1(int arr[3][5], int c, int r)
{
	int i = 0;
	for (i = 0; i < c; i++)
	{
		int j = 0;
		for (j = 0; j < r; j++)
		{
			printf("%d ", arr[i][j]);
		}
		printf("\n");
	}
}
int main()
{
	int arr[3][5] = { {1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7} };
	printf1(arr, 3, 5);
	return 0;
}

法二:

#include <stdio.h>
void printf2(int (*p)[5], int c, int r)
{
	int i = 0;
	for (i = 0; i < c; i++)
	{
		int j = 0;
		for (j = 0; j < r; j++)
		{
			//p指向第0行,p+i指向第i行
			//*(p+i)相当于拿到了第i行,也相当于第i行的数组名
			//数组名表示首元素的地址,*(p+i)表示第i行第一个元素的地址
			printf("%d ", *(*(p+i)+j));
		}
		printf("\n");
	}
}
int main()
{
	int arr[3][5] = { {1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7} };
	//二维数组名相当于首元素的地址,相当于第一行的地址,二维数组的首元素是第一行
	printf2(arr, 3, 5);
	return 0;
}

📚一些数组的等价写法:

arr[i]
*(arr+i)

arr[i][j]
*(arr+i)[j]
*(*(arr+i)+j)


今天的内容就先到这里啦~

谢谢你的耐心阅读,

愿:

Keep up working hard !

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

刹那芳间-

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

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

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

打赏作者

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

抵扣说明:

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

余额充值