首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >初识指针(指针和指针变量、如何理解地址、指针类型的意义、void*指针、野指针、空指针)(笔记)

初识指针(指针和指针变量、如何理解地址、指针类型的意义、void*指针、野指针、空指针)(笔记)

作者头像
走在努力路上的自己
发布2024-01-26 16:28:13
发布2024-01-26 16:28:13
70100
代码可运行
举报
运行总次数:0
代码可运行
一、指针的概念

指针是一个特殊的变量,它里面存储的数值被解释成为内存里的一个地址。

指针所指向的内存区:

在函数调用时就会创建一个栈桢,在栈桢中内存被划分为一个一个的单元,

其中每个内存单元能存放8个比特位(一个字节),每个单元也有一个编号。

*:解引用操作符

&:取地址操作符

内存单元的编号 = 地址 = 指针

代码语言:javascript
代码运行次数:0
运行
复制
int main()
{
	int a = 10;//创建一个变量a,并赋值为10
	//在内存上申请4个字节的空间,存放10

	printf("%p\n", &a);//000000B633B8FBE4	以16进制的形式输出
	//只输出起始(低)位置,后面的地址依次加1;
	//&取出地址操作符

	int* pa = &a;//pa指针变量 - 存放地址 - 地址又被存放指针
	//int* pa,变量的类型,变量的名字	(变量 即 存放的地址)

	*pa;//*解引用操作符,*pa等价于a
	//&   ---   *
	//取地址     解引用
	return 0;
}
二、指针和指针变量

指针:地址 指针变量:变量-存放地址

指针变量用来存放地址的,指针变量并不完全等同指针, 但口头上 指针 一般是 指针变量

2.1指针变量的大小

1.指针变量是专门用来存放地址的,指针变量的大小取决于一个地址存放需要多大空间 32位机器上:地址线32根,地址的二进制序列就是32bit位 - 要把这个地址存起来, 需要4个字节的空间,也就是32bit位的空间 所以:32位机器上指针变量的大小是4个字节! 2.32位平台下地址是32个bit,指针变量的大小是4个字节 64位平台下地址是64个bit,指针变量的大小是8个字节

三、如何理解地址:

计算机中硬件单元要互相协同工作(协同:互相进行数据传递), 但是硬件和硬件之间相互独立,故用"线"连接起来(物理上的), 而CPU和内存之间也有大量的数据交互,所以两者也用线连接起来。 CPU访问内存中的某个字节空间,必须知道这个字节空间在内存的什么位置, 而因为内存中的字节很多,所以需要给内存编号。 计算机中的编址,并不是把每个字节的地址记录下来, 而是通过硬件设计完成的。 可以简单理解为:32位的机器就有32根地址总线,每根线只有两态, 表示0,1[电脉冲有无],那么一根线就能表示2中含义,2根线就能有4种含义。 依此类推,32根地址线,就能表示2^32种含义,每一种含义都代表一个地址。 地址信息被下达给内存,在内存上,就可以找到该地址对应的数据, 将数据在通过数据总线传入CPU内寄存器。

四、指针类型的意义(为什么不用ptr_t p代表所有指针)

1.指针解引用的时候有多大权限 (如果一个指针代替所有的话,解引用时的字节与变量定义类型不同) 2.指针类型决定了指针向前或向后走一步有多大(距离)

代码语言:javascript
代码运行次数:0
运行
复制
/*指针解引用的权限*/
int main()
{
	int a = 0x11223344;
	char* pa = &a;//pa可以存放下a的地址


	*pa = 0;//解引用时这样只能改第一个字节,但是int型有四个字节
	printf("%p", *pa);
	return 0;
}
代码语言:javascript
代码运行次数:0
运行
复制
/*指针解引用的时候有多大权限*/

int main()
{
	int a = 10;
	int* pa = &a;
	char* pc = (char*)&a;//int*

	printf("pa = %d", pa); //9697748
	printf("pc = %d", pc); //9697748
	printf("pa + 1 = %d", pa + 1); //9697752
	printf("pc + 1 = %d", pc + 1); //9697749
}
五、void*指针:无具体指针(泛型指针)

这种类型的指针可以用来接受任意类型的地址,但也有局限性, void*类型的指针,局限性在于他不能直接进行指针的+-整数和解引用的运算

有什么用: 一般void*类型的指针是使用在函数参数的部分,用来接收不同数据类型的地址, 这样可以实现泛型编程的效果,使得一个函数来处理多种类型的数据

注意: void*类型的指针不能直接进行解引用的操作 void* 类型的指针也不能进行指针计算的操作

代码语言:javascript
代码运行次数:0
运行
复制
int main()
{
	int* a = 10;
	char* ch = 'w';
	void* pv = &a;//int*
	void* pv2 = &a;//char*
	
	//*pv = 20;//err	void*类型的指针不能直接进行解引用的操作
	//pv++;//err	void* 类型的指针也不能加减一的操作

	return 0;
}
六、野指针:

指针指向的位置是不可知的(随机的,不正确的,没有明确限制的)

使用完指针后未将其置为NULL,导致该指针指向的内存地址仍然被占用,但该指针却不受控制。野指针是C语言中一个常见的内存泄漏问题。如果程序中存在野指针,当程序再次申请内存时,可能会将之前已经释放的内存分配给新的变量,导致程序出现不可预测的行为,甚至崩溃。

野指针成因: 1. 指针未初始化 2.指针越界访问造成野指针 3.指针指向的空间释放

1. 指针未初始化

代码语言:javascript
代码运行次数:0
运行
复制
int main()
{
	int* ptr;//野指针,没有初始化
	*ptr = 20;//非法访问内存了
	printf("%p\n", ptr);

	return 0;
}

2.指针越界访问造成野指针

代码语言:javascript
代码运行次数:0
运行
复制
int main()
{
	int arr[5] = { 0 };
	//1 1 1 1 1 1 1 1 1 1
	int i = 0;
	int* p = arr;
	for (i = 0; i < 10; i++)
	{
		*p = 1;
		p++;//数组越界访问
	}

	return 0;
}

3.指针指向的空间释放

代码语言:javascript
代码运行次数:0
运行
复制
int* test()
{
	int a = 10;
	//...
	return &a;
}

int main()
{
	int* p = test();
	printf("hehe\n");//为什么这里加了一个代码,这里的值就变了

	printf("%d\n", *p);//

	return 0;
}
如何规避野指针?

1.指针初始化 如果明确知道指针指向哪里就直接赋值地址,如果不知道指针应该指向哪里, 可以给指针赋值NULL。 NULL 是C语言中定义的一个标识符常量,值是0,0也是地址,这个地址是无法使用的,读写该地址会报错。 2.小心指针越界 一个程序向内存申请了哪些空间,通过指针也就只能访问哪些空间,不能超出范围访问,超出了就是越界访问。 3.指针变量不再使用时,及时置NULL,指针使用之前检查有效性? 当指针变量指向一块区域的时候,我们可以通过指针访问该区域,后期不再使用这个指针访问空间的时候,我们可以把该指针置为NULL。因为约定俗成的一个规则就是:只要是NULL指针就不去访问,同时使用指针之前可以判断指针是否为NULL。 4.避免返回局部变量的地址? 如造成野指针的第3个例子,不要返回局部变量的地址。

七、空指针

空指针是一个特殊的数据类型,它的值定义为NULL。空指针不同于NULL的整数表示,它是一个指针变量的特殊值,表示该指针变量不指向任何有效的内存地址。 使用空指针进行解引用操作会导致程序崩溃,因为没有任何有效的内存地址可供访问。在C语言中,空指针主要用于表示指针变量没有指向任何有效的内存地址,例如未初始化的指针变量或已释放的内存块。

代码语言:javascript
代码运行次数:0
运行
复制
int *ptr = NULL;  
if (ptr != NULL) {  
    // 执行解引用操作  
    printf("%d", *ptr);  
} else {  
    printf("空指针");  
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-12-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、指针的概念
  • 二、指针和指针变量
    • 2.1指针变量的大小
  • 三、如何理解地址:
  • 四、指针类型的意义(为什么不用ptr_t p代表所有指针)
  • 五、void*指针:无具体指针(泛型指针)
  • 六、野指针:
    • 如何规避野指针?
  • 七、空指针
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档