c++函数返回值的若干问题汇总

胖博主面试遇到的问题,特地整理一下,汇总了几位大佬的博文,学习一下,十分感谢大佬们的博文。

一、函数返回多个参数

有两种方法,第一种是将返回值作为写参数,第二种方法是定义结构体,返回该结构体指针

struct Result
{
   int shang;
   int yu;
}

struct Result div(int a,int b)
{
  struct Result ret;
  ret.shang=a/b;
  ret.yu=a%b;
}

struct Result r=div(33432,44);

用typedef为结构体起个大名

 

typedef struct Result{
    int shang;
    int yu;
}Result; 

Result div(int a,int b){
    struct Result ret;
    ret.shang = a/b;
    ret.yu = a%b;
}

Result r = div(33432,44);

 用返回指针的方式

struct result
{
  int a;
  char b;
  string c;
};

result *fun()
{
  result *test=new result;
  test->a=i;
  test->b=b;
  test->c="test";
  return test;
}

int main()
{
 result *test;
 test=fun();
 cout << test->a << " " << test->b << " " << test->c << endl;
 delete test;
 return 1;
}

二、函数调用


以下转自:https://www.cnblogs.com/HPAHPA/p/8301625.html

1、test1

void test(int *p)
{
	int b=2;
	p=&b;
	cout<<p<<endl;
}

int main()
{
	int a=10;
	int *p=&a;
	cout<<p<<endl;
	test(p);
	cout<<p<<endl;
	system("pause");
	return 0;
}

输出:

第一行输出和第三行输出的结果相同,而第一行、第三行与第二行输出的结果不同。从这里可以看出,当指针作为参数进行传递时传递的也只是一个值,只不过该值只一个地址,因此对于形参的改变并不影响实参。

2.test2

char* test(void)
{
	char str[]="hello world!";
	return str;
}

int main()
{
	char *p;
	p=test();
	cout<<p<<endl;
	system("pause");
	return 0;
}

 

出现这种情况的原因在于:在test函数内部声明的str数组以及它的值"hello world”是在栈上保存的,当用return将str的值返回时,将str的值拷贝一份传回,当test函数执行结束后,会自动释放栈上的空间,即存放hello world的单元可能被重新写入数据,因此虽然main函数中的指针p是指向存放hello world的单元,但是无法保证test函数执行完后该存储单元里面存放的还是hello world,所以打印出的结果有时候是hello world,有时候是乱麻。

3.test3

int test(void)
{
	int a=1;
	return a;
}

int main()
{
	int b;
	b=test();
	cout<<b<<endl;

	system("pause");
	return 0;
}

在test函数执行完后,存放a值的单元是可能会被重写,但是在函数执行return时,会创建一个int型的临时变量,将a的值复制拷贝给该临时变量,因此返回后能够得到正确的值,即使存放a值的单元被重写数据,但是不会受到影响。

4.test4

char* test(void)
{
	char *p="hello world!";
	return p;
}

int main()
{
	char *str;
	str=test();
	cout<<str<<endl;

	system("pause");
	return 0;
}

char *p="hello world!",指针p是存放在栈上的,但是"hello world!”是一个常量字符串,因此存放在常量区,而常量区的变量的生存期与整个程序执行的生命期是一样的,因此在test函数执行完后,str指向存放“hello world!”的单元,并且该单元里的内容在程序没有执行完是不会被修改的,因此可以正确输出结果。

5.test5

char* test(void)
{
	char *p=(char *)malloc(sizeof(char)*100);
	strcpy(p,"hello world");
	return p;
}

int main()
{
	char *str;
	str=test();
	cout<<str<<endl;

	system("pause");
	return 0;
}

 这种情况下同样可以输出正确的结果,是因为是用malloc在堆上申请的空间,这部分空间是由程序员自己管理的,如果程序员没有手动释放堆区的空间,那么存储单元里的内容是不会被重写的,因此可以正确输出结果。

6.test6

void test(void)
{
	char *p=(char *)malloc(sizeof(char)*100);
	strcpy(p,"hello world");
	free(p);
	if(p==NULL)
	{
		cout<<"NULL"<<endl;
	}
}

int main()
{
	test();
	system("pause");
	return 0;
}

在这里注意了,free()释放的是指针指向的内存!注意!释放的是内存,不是指针!这点非常非常重 要!指针是一个变量,只有程序结束时才被销毁。释放了内存空间后,原来指向这块空间的指针还是存在!只不过现在指针指向的内容的垃圾,是未定义的,所以说是垃圾。因此,释放内存后应把把指针指向NULL,防止指针在后面不小心又被使用,造成无法估计的后果。


以下转自:https://blog.csdn.net/kwsy2008/article/details/49530549#

C++把内存交给了程序猿,但是,请你注意,它可没把所有的内存都交给你,交给你的只是堆上的内存,也就是你通过malloc函数  和new 关键字申请来的内存,除了这些内存以外,其他的内存,你最好别碰,最好别碰,最好别碰,重要的事情说三遍。

 

        如果你的函数返回值在后续使用中出错了,尤其是返回函数内的局部变量这种事情,那么,基本可以肯定,你碰了不该碰的内存。这时候,你会觉得自己很冤枉啊,我没有啊。但事实是,没有冤枉你,所以,为了不被bug检察院起诉你,作为一个C++程序猿,你必须学会甄别那些内存是能碰的,那些内存是不能碰的。

char *pstr = "This is the buffer text";    
return pstr;  

          如果你的函数是这么写的,那么恭喜你,返回正确,因为这个pstr指向的是常量存储区,这里的内存,你是可以碰的,但是注意,这个碰,仅仅是读,你想修改,那是万万不可以的。

char buffer[] = "This is the buffer text";    
return buffer;

   如果你的函数是这么写的,那么恭喜你,等着bug联邦检察院起诉你吧。这里的buffer指向的是栈上内存,这个,就是你碰不得的,前面的pstr就好比公园,公园嘛,大家都可以来玩,但是你不能把公园里的假山拆了,你也不能把公园里的树砍了,你只能是来玩,不能修改它,栈上的内存,就好比是私家花园,你一个外人,是不能进去的。那么怎么甄别的,方法倒也简单,你见到带中括号的,就应该明白,这东西是栈上的,出了这个函数,你就别想再碰的,你只要敢碰,bug联邦检察院就会起诉你。

static char buffer[] = "This is the buffer text";    
return buffer;  

如果你的函数是这么写的,那么恭喜你,返回正确,可是刚才不是明明说,这里是私家花园嘛,没错,但是你注意看,前面还加了一个static,只要加了这个关键字,就相当于说国家把这个私家花园征用了,那么,它就从私家花园变成了静态存储区里的一个小花园,静态存储区里的内存,国家说,静态存储区对外开放,你们都可以来。

 

 函数返回的都是值拷贝,栈上的内存,在函数结束的时候,都会被收回。在函数内部,你可以碰栈上的内存,那是因为这个时候你是在栈的家里做客,那他们家的内存小花园当然允许你访问,可是函数结束了,就相当于你离开了栈的家,栈把内存小花园的门关上了,你怎么可以进去,你进去了,就会被bug联邦法院起诉! 

但是呢,总有一些奇怪的现象让你以为你可以在函数结束后仍然可以访问栈上的内存。

            我们定义一个结构体

struct person
{
	int age;
}

 写一个函数

person*  getperson2()
{
	person p;
	p.age = 99;
	return &p;
}

在得到函数的返回值以后,你可以输出对象的年龄

person *p2 = getperson2();
cout<<p2->age<<endl;

你会发现,这段代码居然可以正确执行!在函数getperson2内部,p这个变量是局部变量,必然是在栈上申请的,返回的是&p,这不就是栈上的内存地址么,那为啥在函数外部,却仍然可以输出age呢?

           虽然,函数结束后,对象被销毁,但是销毁的不够彻底,似乎计算机在管理内存时也不需要那么彻底的销毁一个对象,你之所以能输出age,那是因为那个区域,没有被彻底销毁,这一小块的内存(存储age的4个byte)没有发生变化。你可以暂时的碰这块内存,但迟早是要出问题的,如果某一刻,计算机打算用这块内存,发现你在非法使用,那么必然会报警,然后bug联邦检察院会起诉你。

           为了让问题更透明一些,我们修改一下结构体

struct person
{
	int age;
	char* name;
	person()
	{
		name = new char(10);
		strcpy(name,"sheng");
	}
	~person()
	{
		name = NULL;
	}
};

 

person*  getperson2()
{
	person p;
	p.age = 99;
	return &p;
}
person *p2 = getperson2();
cout<<p2->age<<endl;
cout<<p2->name<<endl;

   这一次,函数结束后,对象的销毁要比上一次彻底的多,虽然,age的区域还是没有被彻底销毁,但是name区域被彻底销毁了,如果你访问name的区域,就必然出错,这就好比啊,私家花园关门了,可是花园好大的,所以不是每一处都安装了摄像头和报警器,比如age这片区域,所以,你偷偷的从age这个区域溜进去时,花园的主人没发现,直到花园的巡防大队到age区域巡防时,发现你竟然在这里偷偷菜花,结果就是把你打的崩溃了。而name这边区域,在~person这个析构函数中安装了摄像头和报警器,你只要来,就立刻报警,然后把你打的崩溃。

 

          千言万语,汇成一句话,函数不要返回指向栈的内存地址,切记,是地址,别被吓的所有的函数内的变量都不敢返回,只要不是栈的内存地址,你尽管放心的返回。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值