指针讲解与常见问题

本文详细介绍了指针作为数据类型的基本概念,包括指针变量、内存地址、野指针和空指针的含义,以及间接访问操作符、指针的步长、间接赋值的规则。此外,还讨论了指针在函数参数中的输入和输出特性,常见错误如越界、指针叠加和内存释放的处理,以及指针与引用的区别。
摘要由CSDN通过智能技术生成

指针是一种数据类型

指针变量

指针是一种数据类型,占用内存空间,用来保存内存地址。
与其他变量或常量一样,必须在使用指针存储其他变量之前,对其进行声明。

void test01(){
	
	int* p1 = 0x1234;
	int*** p2 = 0x1111;

	printf("p1 size:%d\n",sizeof(p1));
	printf("p2 size:%d\n",sizeof(p2));


	//指针是变量,指针本身也占内存空间,指针也可以被赋值
	int a = 10;
	p1 = &a;

	printf("p1 address:%p\n", &p1);
	printf("p1 address:%p\n", p1);
	printf("a address:%p\n", &a);

}

野指针和空指针

空指针:作为一个特殊的指针变量,表示不指向任何东西。
野指针:指向一个已删除的对象或未申请访问受限内存区域 (不确定其指向)的指针。

对一个NULL指针因引用是一个非法的操作,在解引用之前,必须确保它不是一个NULL指针。

什么情况下会导致野指针?

1.指针变量未初始化
2.指针释放后未置空
3.指针操作超越变量作用域:不要返回指向栈内存的指针或引用,因为栈内存在函数结束时会被释放。

如何避免野指针

1.定义时初始化
2.释放时置 NULL

释放:free()释放的是指针指向的空间内存,不是指针;
置空:意思就是指针不会再指向任何地方;

置空的本质:指针置空是将指针变量赋值为0
置空的目的:避免越过作用域使用指针:确保指针不会超出其所在作用域范围。 当指针指向局部变量时,确保在变量超出作用域前不再使用该指针。

间接访问操作符

声明指针时,* 号表示所声明的变量为指针
使用指针时,* 号表示操作指针所指向的内存空间

1)* 相当通过地址(指针变量的值)找到指针指向的内存,再操作内存
2)* 放在等号的左边赋值(给内存赋值,写内存)
3)* 放在等号的右边取值(从内存中取值,读内存)

说白了,就是声明指针时的那个 * 就是执行间接访问的操作符
间接访问:通过一个指针访问它所指向的地址 / 或者叫解引用指针

指针的步长

指针是一种数据类型,是指它指向的内存空间的数据类型
指针所指向的内存空间(数据类型)决定了指针的步长。
指针的步长指的是,当指针+1时候,移动多少字节单位。

int a = 0xaabbccdd;
unsigned int *p1 = &a;
unsigned char *p2 = &a;


printf("p1  =%d\n", p1);
printf("p1+1=%d\n", p1 + 1);   //p1指针+1加了4字节

printf("p2  =%d\n", p2);
printf("p2+1=%d\n", p2 + 1);   //p2指针+1加了1字节

指针的意义:间接赋值

间接赋值的三大条件

void test(){
	int a = 100;	//1:两个变量
	int *p = NULL;
	//2.建立关系
	//3.指针指向谁,就把谁的地址赋值给指针
	p = &a;
	//通过*操作内存
	*p = 22;
}

间接赋值的推论

用 n 级指针形参,间接修改了 n-1 级指针(实参)的值。

当在主函数调用函数,在传参时,传入的实参为指针是,被调函数的形参需要用一个更高一级的指针去接收实参。

指针做函数参数

指针做函数参数,有输入特性输出特性

输入特性

主调函数分配内存

void fun(char *p)
{
	strcpy(p, "abcddsgsd");
}

void test(void)
{
	char buf[100] = { 0 };   //分配内存
	fun(buf);
	printf("buf  = %s\n", buf);
}

输出特性

被调函数分配内存

void fun(char **p, int *len)
{
	char *tmp = (char *)malloc(100);   //分配内存
	if (tmp == NULL)
	{
		return;
	}
	strcpy(tmp, "adlsgjldsk");
	*p = tmp;
	*len = strlen(tmp);
}
void test(void)
{
	char *p = NULL;
	int len = 0;
	fun(&p, &len);
	if (p != NULL)
	{
		printf("p = %s, len = %d\n", p, len);
	}

一级指针易错点

越界

void test(){
	char buf[3] = "abc";   //这里只声明了 3 个空间,但是字符串还有一个 /0
	printf("buf:%s\n",buf);   //造成越界
}

指针叠加会不断改变指针指向

void test(){
	char *p = (char *)malloc(50);
	char buf[] = "abcdef";
	int n = strlen(buf);
	int i = 0;
	for (i = 0; i < n; i++)
	{                                      
		*p = buf[i];
		p++;  //修改原指针指向
	}
	free(p);   //这里操作了偏移后的指针
}

解决方案:使用一个临时指针pp指向p,操作pp,而p指针始终没动

返回局部变量地址

char *get_str()
{
	char str[] = "abcdedsgads"; //栈区,
	printf("[get_str]str = %s\n", str);
	return str;
}

外部函数调用时str已经被释放了,会造成不可预知的错误

同一块内存释放多次

void test(){	
	char *p = NULL;
	p = (char *)malloc(50);
	strcpy(p, "abcdef");
	if (p != NULL)
	{
		free(p); 
	}
	if (p != NULL)
	{
		free(p);
	}
}

free()函数的功能只是告诉系统 p 指向的内存可以回收了
就是说,p 指向的内存使用权交还给系统
但是,p的值还是原来的值(野指针),p还是指向原来的内存

指针和引用的区别

指针:
是一个变量,保存内存地址;
指向的内存空间在运行期间是可以修改的;
指针本身是占用内存空间的
可以为空值(不初始化直接悬空)
可以有多级指针(定义指针的指针)

引用:
是已存在变量的别名;
引用所绑定的对象一旦初始化绑定就不能改变
作为一个别名,不占内存空间
不可为空(初始化时必须绑定对象)
引用只能是一级指针(不能定义引用的引用)

  • 40
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值