用代码说服同学C语言不要返回局部变量地址的辩论过程

用代码说服同学C语言不要返回局部变量地址的辩论过程


事情缘于这一段代码

#include <stdio.h>

char * funa()
{
	char arr[] = "Hello\n";
	return arr;		//直接返回一个数组,数组名当地址使用。
}

char * funb()
{
	char arr[] = "Hello\n";
	char *p = arr;	//把数组的地址保存在一个指针中。
	return p;		//返回指针。
}
int main(void)
{
	printf("%s", funb());	//输出Hello,编译器无报警
	printf("%s", funa());	//输出null,编译器警告错误

	return 0;
}

同学无法理解为什么同样是返回了地址,且编译器没有任何警告,一个会输出null且一个会输出正常数值。

我的理解是:
编译器能分清楚通过数组名返回的是地址,所以给出了警告。
但是通过返回指针变量的方式返回地址,编译器无法分清你返回的是一个变量还是地址,返回的地址是否安全,无法做出预测处理所以正常通过编译


并且在和同学的讨论结束后,用gdb调试了一下这段不安全的代码。发现编译器应该是出于安全考虑,对返回数组的操作都统一返回了0x0的空地址。所以如果对返回值取字符串会返回null。如果返回值当整数数组处理。要对地址做解引用。即尝试对空地址解引用。因为不是输出null而是输出段错误程序崩溃。

Breakpoint 1, main () at arr.c:17
17		printf("%s", funb());
(gdb) n
Hello
18		printf("%s", funa());
(gdb) n
20		return 0;
(gdb) p funa()
$1 = 0x0
(gdb) p funb()
$2 = 0x7fffffffe2e1 "Hello\n"
(gdb) 

同学认为既然能正确返回,那就能用这种方法在函数中创建一个局部变量的数组并返回。写了一段代码重复输出yes的代码,认为数据是安全的。即使我不断的循环也没有改变数值,编译器会保护数据不被覆盖。

#include <stdio.h>
int * fun(void)
{
	int arr[3] = {1, 2, 3};
	int *p = arr;
	
	return p;
}

int main(void)
{
	int i;
	int * d = &fun()[1];

	for (i = 0; i < 100; i++)
	{
		if (*d == 2)
		{
			int j[100] = {1};
			printf("YES");
		}
			//保存函数回返的地址。
			//在循环中不断创建变量,比较和解引用证明数据是安全的。
	}
		
	return 0;
}


我认为只是没有足够的数值刚好覆盖到变量地址,并且编译器可能做了优化数组没有覆盖到数据并写了如下代码

#include <stdio.h>
int * func();
int * funca();
int main(void)
{
    int * p = func();
    printf("func return address:\t%p\nfunc return data:\t%d\n", p, *p);
    
    int *pp = funca();
    printf("funca return address:\t%p\nfunc return data:\t%d\n", pp, *pp);

    printf("func return address:\t%p\nfunc return data:\t%d\n", p, *p);
    return 0;
}

int * func()
{
    int abc[2]= {1, 2};
    int *p = abc;

    return p;
}
int * funca()
{
    int abc[2]= {2, 1};
    int *p = abc;

    return p;
}

程序运行结果:

func return address:	0x7ffe968f2a70 
func return data:	1
funca return address:	0x7ffe968f2a70
func return data:	2
func return address:	0x7ffe968f2a70
func return data:	2

可以直观看出func和funca两个不同的函数返回同一个地址,后者会覆盖掉前者的数据,不安全的返回局部变量很容易被未知操作覆盖掉数据。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值