对指针的一点理解、二级指针、野指针、指针作为函数返回值

可能之前定义指针变量的时候总是用int *p这种形式,总是顺其自然的就认为*p是一个指针变量,实际上p才是指针变量,*p是一个表达式,*是取值运算符,不要再认为*p是指针变量了。

int* p; p是一级指针

int** p,p是一个二级指针,p是二级指针的名字。

感觉还是int* p,int** p这样写更清楚一点,以后尽量少用int *p这种表达方式吧。

指针变量名上也是不带*的,注意。

int* ptr=NULL;

//======================================野指针================

而且定义指针的时候,像vs都不能定义野指针了,必须要让指针有所指向,野指针的危害:

https://blog.csdn.net/qq_40927789/article/details/80686723

野指针的实例:https://blog.csdn.net/acs713/article/details/9055193?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522163056484516780269880339%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=163056484516780269880339&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_v2~rank_v29-1-9055193.pc_search_result_cache&utm_term=%E9%87%8E%E6%8C%87%E9%92%88+%E4%B8%8D%E8%A6%81%E8%BF%94%E5%9B%9E%E6%8C%87%E5%90%91%E6%A0%88%E5%86%85%E5%AD%98%E7%9A%84%E6%8C%87%E9%92%88&spm=1018.2226.3001.4187

//=====================二级指针========================

下面的内容转自https://blog.csdn.net/chen1083376511/article/details/78382435

int** p二级指针

*p和**p的区别:

int* p:一级指针,表示p所指向的地址里面存放的是一个int类型的值

int** p:二级指针,表示p所指向的地址里面存放的是一个指向int类型的指针(即p指向的地址里面存放的是一个指向int的一级指针)

#include<stdio.h>
#include<string.h>

int main(int argc, char* agrv[])
{
	int a = 1;
	int* p1 = &a;
	int** p2 = &p1;

	printf("a=%d\n", a);
	printf("a=%d\n", *p1);
	printf("a=%d\n", **p2);



	return 0;
}

//==================指针定义完之后是否为空====================

#include<stdio.h>

int main(void)
{
	int* p = NULL;//NULL是0.地址为0的内存是给操作系统用的,编译器是没有权限进行管理的,不指向任何东西。

	//定义完指针变量之后,经常有这样的用法:
	if (p)// 指针p非空
	{
		

		;
	}

	if (!p) //指针p为空
	{



		;
	}
	return 0;
}

//=========================指针作为函数返回值==================

要注意函数的返回值如果是函数内部存放在栈中的局部变量的地址,结果可能导致错误。因为在执行完return之后,给局部变量分配的内存已经被释放,虽然改制地址内存还在,但是上面的内容已经是不确定的了。如果是返回函数内在静态存储区存放的变量的地址,那么结果是正确的。注意函数的返回值是指针时,操作的安全性。看下面两个例子:

#include<stdio.h>
#include<string.h>

char* GetAddress(void)
{
	//static char str[] = "hello";
	char str[] = "hello";//“hello”是分配在动态栈区中的,返回这种局部变量的指针很危险,结果是错误的。
   
	return str;

}


char* GetArr2(void)
{
	char* s = "hello";

	return  s;

}
int main(void)
{
	printf("%s\n", GetAddress());
	printf("%s\n", GetArr2());

	return 0;
}

上面程序结果是错误的,再看下面的程序,如果函数把一个放在静态存储区中的数据的地址作为函数的返回值,那么结果就是正确的。如何能让函数的变量放在静态存储区呢,用static来限制。

#include<stdio.h>
#include<string.h>

char* GetAddress(void)
{
	static char str[] = "hello";//这里变了
	
	return str;

}


char* GetArr2(void)
{
	char* s = "hello";

	return  s;

}
int main(void)
{
	printf("%s\n", GetAddress());
	printf("%s\n", GetArr2());

	return 0;
}

这样的结果就是正确的。

关于函数执行到return,栈区怎么释放,可以参考https://blog.csdn.net/lsm135/article/details/50165369

对于指针类型的函数,也就是返回值是指针的函数,其返回函数中局部变量的内存地址是危险的,如果返回的是main()主调函数中的局部变量的内存地址是可以的,让main()函数中的局部变量的地址作为参数,给到指针类型的函数进行相应的操作,要看局部变量是定义在main()函数还是其他函数里的。

#include<stdio.h>
#include<string.h>

//通过调用函数GetArr2,来对main()函数中定义的局部变量,也就是数组a中的成员进行修改。


void GetArr2(char* p)
{
	*(p + 1) = 'i';

	return ;

}
int main(void)
{
	char a[] = "hello";

	GetArr2(a);

	printf("%s\n", a);
	return 0;
}

//===========================函数的return语句=======================

对于函数来说,执行到return的时候会得到一个返回值,编译器将这个返回值放到寄存器中,再从寄存器中调取出来给到接收函数返回值的变量。

关于函数执行到return,栈区怎么释放,可以参考https://blog.csdn.net/lsm135/article/details/50165369

//================指针作为函数返回值时,“值传递”与“地址传递”==========

#include<stdio.h>

char* CharMy()
{

	char cs = 'G';
	char* csp = &cs;
	

	return csp;
}

int main(int argc, char* agrv[])
{


	printf("%c\n", *CharMy());
//输出结果不是字符G,因为局部变量在函数结束后将释放,改地址上已经不再是字符'G'。

	return 0;

}


再看下面这段代码,就可以,因为CharMy()函数返回的就是一个实实在在的字符数值。
#include<stdio.h>

char CharMy()
{

	char cs = 'G';


	return cs;
}

int main(int argc, char* agrv[])
{


	printf("%c\n", CharMy());//此时CharMy()的值就是实实在在的字符常量'G'

	return 0;

}

虽然有时候返回子函数中局部变量的地址结果也是正确的,但可能只是编译器是这么设置的,但这种做法仍然是不对的,因为不知道什么时候被释放的栈区就被改变。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小哇123

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

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

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

打赏作者

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

抵扣说明:

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

余额充值