指针的深入理解(一)

本文详细介绍了指针的概念、内存地址的管理、指针变量的创建与类型、解引用操作、void指针、const修饰、指针运算等内容,帮助读者理解指针在编程中的作用和基本原理。
摘要由CSDN通过智能技术生成

指针的深入理解(一)

前言

哈喽,各位小伙伴们,大家好!最近也是学习到了指针内容,于是小编经过深入学习后,马不停蹄地给大家分享干货。由于指针内容较多,所以小编分期讲解。也希望大家学习过程要有耐心。话不多说,向大厂冲锋,杀gigi!

一.内存和地址

1.1内存

我们知道计算机GPU(中央处理器)处理数据时,数据是从内存中读取的。那内存中那么多数据,如何进行高效的管理的呢?其实内存就像一个酒店,酒店为了方便管理分成很多个房间。内存也是一样的分为一个个的内存单元,每个内存单元大小取一个字节(一个字节=八个bit(比特位)=(八个二进制数字的大小))。也就是说一个内存单元可以存八个二进制数。
在这里插入图片描述
那酒店的每个房间都有房间号,所以每个内存单元也有属于自己的编号,这个编号就是内存的地址,而c语言中我们把这个编号叫做指针。所以我们得出一个结论:

结论
结论一内存的编号=地址=指针

这三者其实是完全等价的。

1.2编址

那CPU是如何拿到内存的呢?这个过程是怎样的实现的呢?这就和三条线有关联了。
在这里插入图片描述
计算机之间硬件与硬件直接是相互协调工作的,这时候就必须进行数据传递。那么如何传递数据呢?其实就是用线传递。CPU和内存也是用线进行传递。当CPU要向内存读取数据时(读操作),通过地址总线传递地址信号,找到数据。然后通过数据总线将数据传递给CPU**。如果将数据从CPU传到内存(写操作),也是通过数据总线传递,而控制总线则是控制是进行读操作还是写操作。这就是数据传递的过程。32位的机器就有32根地址总线,64位的机器就有64跟地址总线。每根地址总线传递的信号为0或者1电脉冲的有无)。所以32位机器可以产生2的32次方个二进制序列,64位机器可以产生2的64次方个二进制序列,每个二进制序列就是一个内存单元地址。那我们写的程序又是如何访问内存的?其实我们程序中的地址是虚拟地址,需要通过操作系统和硬件复杂的协同关系,转化为物理地址才能访问内存。

二.指针变量和地址

2.1变量创建的本质

变量创建的本质其实就是在内存中开辟一块空间。而开辟的空间多大取决变量的类型,例如int类型大小为四个字节,那就开辟四个字节大小的空间,而每个字节都由一个地址来控制。那我们&变量取出的地址是四个地址吗?其实不是的,我们&操作符去除的地址是第一个字节的地址,也是最低地址的那个。我们只要知道第一个字节的地址,顺藤摸瓜就能找到其他字节的地址啦。

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
	int a = 30;
	printf("%p", &a);
	return 0;
}

以这个代码为例。
在这里插入图片描述

2.2指针变量

我们之前说过指针就是地址。那我们要创建一个指针,是不是需要创建一个变量,然后用&将地址赋值给变量,那变量创建需要明确类型,那指针的类型该怎么写呢?那就是int*啦。这就是一个指针变量。

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
	int a = 30;
	int * p = &a;//指针变量,*表示这是指针,int表示指针指向的变量的类型
	return 0;
}

指针变量的int*我们需要分开理解。*表示这是个指针变量,而int表示指针指向的变量是int类型的。我们口头所说的指针其实就是指针变量。

2.3指针变量的大小

指针变量的大小是多大呢?我们知道指针变量里面存放的是地址,那指针变量的大小多大取决于他里面放的是什么,我们又知道32位机器有32根地址总线,能产生32个二进制数,这个数字就是地址,所以指针变量的大小就是32个bit也就是4个字节的大小。那64位机器下,指针变量的大小就是64bit,就是8个字节大小。

结论
结论二指针变量大小在32位机器下为4字节,64位机器下为8字节。

那假如是char*类型的指针呢?指针大小会不会改变呢?这里用vs2022给大家验证一下。

大家可以发现指针大小没有改变。所以我们又得出一个结论。

结论
结论三指针变量的大小与类型无关,只与平台大小有关(32或者64)

2.4解引用操作符

我们创建指针变量后,有什么用呢?我们可以通过指针找到该地址的变量。但是这需要使用解引用操作符*。

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
	int a = 30;
	int * p = &a;//指针变量,*表示这是指针,int表示指针指向的变量的类型
	printf("%d\n", *p);
	*p = 100;//解引用找到a,此时*p等价于a,所以*p=100,相当于a=100;
	printf("%d", *p);
	return 0;
}

而*p解引用就可以找到a,此时星号p等价于a,所以星号p=100,相当于a=100。所以相当于修改了a的值。大家也可以把星号p理解为星号&a,而星号和&操作符相互抵消所以*p=a

2.5指针类型

指针类型不同有啥区别呢?这里给大家观察一下不同指针类型内存的变化。

观察后发现char指针解引用只能访问一个字节,而int指针能访问四个字节。这里相信大家能看出来指针变量的区别在哪里了。我们又可以得出一个结论。

结论
结论四指针类型决定指针进行解引用时访问多大空间(int星号四个字节,char星号一个字节)

大家再来观察一下。

char*指针指向的是char类型加一跳过一个字符,也就是一个字节。int*指针指向的是int类型加一跳过加粗样式一个整型,也就是四个字节。我们又可以得出一个结论。

结论
结论五指针类型决定了指针向前/向后走一步走多大距离

所以我们需要根据实际情况,选择合适的指针类型才能达到效果。

2.6void指针


大家可以看到当我们将int类型变量的地址放到char星号类型指针时,编译器报了个警告说类型不兼容,而放到void指针里警告消失了。这是因为void星号类型的指针是无具体类型的指针,可以接受任意类型的地址,但需要注意void类型指针不能进行指针加减整数和解引用操作。

2.7const修饰

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
	const int a =10;
	a = 100;
	return 0;
}


大家看这段代码编译器报了个错误,说左值指定const对象。这是因为a被const修饰后,在语法上加了限制,这时的a仍然是变量但是在语法上不能被修改,这就是const。那有没有一种办法打破语法限制呢?有,就是使用指针。可以看到a被使用指针修改了。那const修饰指针的话,又会产生什么效果呢?是不是指针也不能修改a了呢?
在这里插入图片描述
在指针左边const修饰后,又报了警告,说明指针也不能修改a了,也就是a的值已经无法修改了,被const限制死了。那把const放在右边又是怎样的呢?注意这里的左右是以星号作为标准。

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
	const int a =10;
	int m = 100;
	const int*p = &a;
	p = &m;
	//*p = 10;
	printf("%d", a);
	return 0;
}

在这里插入图片描述
发现虽然被const修饰了,不能改变指针对象,但是我们可以改变指针指向的对象
在这里插入图片描述
但是const放在右边后,编译器报错,说明此时指针不能更改指向的对象了。相信大家已经能体会到const放在左边和右边的区别了。如果两边都有const,那就产生两种限制结果。

结论
结论六const放在左边限制的是指针对象(不能修改),const放在右边限制的是指针指向的对象

2.8指针运算

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
void printf(int arr[],int b1)//int arr[]本质就是指针,所以也可以是int* p,只是为了方便理解写成数组的形式
{
	int* p = arr;
	//int b = sizeof(arr) / sizeof(arr[0]);
	for (int i = 0; i < b1; i++)
	{
		printf("%d ", *(p+i));//刚开始指针指向首元素,加上下标就是跳过多少个整型后的位置
	}
}
int main()
{
	int arr[] = { 1,3254,4,67,576,34,6,98 };
	int b = sizeof(arr) / sizeof(arr[0]);//统计数组长度
	printf(arr,b);//数组名是数组首元素的地址,所以传过去本质是地址,不是数组
	return 0;
}


大家看我们用指针来打印数组。补充知识点:数组名就是数组首元素的地址(有两个例外),数组在内存中是连续存放的,随着下标增长,地址不断增长。我们用指针加减整数跳过整型来访问数组的每个元素,逐个打印即可。这就是指针的加减整数运算。哪有没有指针间的运算呢?答案是有的。

大家想想指针加减整数等于指针,那反推指针加减指针是不是就等于整数了呢?如果是的话,这个整数又代表什么呢?这里我们使用指针实现strlen库函数给大家讲解。

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
int strlen1(char* p)
{
	char* p1 = p;
	while (*p1 != '\0')
	{
		p1++;
	}
	return p1-p;
}
int main()
{
	char a[] = { "sadsfdshghtrut" };
	int c=strlen(a);
	int b = strlen1(a);
	printf("%d\n", c);
	printf("%d", b);
	return 0;
}


大家发现结果是一样的,这里就用到了指针相减的运算。注意没有指针相加的运算。

我们创建的函数中创建了一个新的指针p1初始化为**p,然后循环字符数组,每次循环p1+1,循环完后p1已经指向’\0’**了,p1指针减去首元素指针(p)就是字符串的长度

最后还有指针的关系运算。

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	int sz = sizeof(arr) / sizeof(arr[0]);//统计长度
	int* p = arr;//首元素地址
	while (p < arr + sz)//指针运算,指针比较大小
	{
		printf("%d ", *p);
		p++;//移动
	}
	return 0;
}


我们用数组首元素指针和arr+sz地址指针做关系运算来判断指针位置,从而打印数组。这是指针关系运算的应用。

后言

指针的知识内容较多,需要我们慢慢消化和理解。希望看完大家能对指针有个大致的了解。今天就分享到这里,谢谢各位小伙伴的耐心阅读!我们下期见!

  • 42
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 12
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

大白的编程日记.

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

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

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

打赏作者

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

抵扣说明:

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

余额充值