C语言编程不易发现的错误(二)

错误:

  c语言函数返回局部变量地址。

分析:

  c语言函数是不能返回局部变量地址(特指存放于栈区的局部变量地址),除非是局部静态变量地址,字符串或整型常量地址、动态分配地址。其原因是一般局部变量的作用域只在函数内,其存储位置在栈区中,当程序调用完函数后,局部变量会随此函数一起被释放。其地址指向的内容不明(原先的数值可能不变,也可能改变)。而局部静态变量地址,字符串或整型常量地址都是存放在数据区、动态分配地址存放在堆区,函数运行结束后只会释放栈区的内容。

实例及结果:
#include "stdio.h"
//返回局部变量a的地址 
int* f1()
{
	int a = 9;
	int *pa = &a;
	printf("a = %d\t&a = %p \n",a, &a);
	printf("*pa = %d\tpa = %p \n",*pa, pa);
	return pa;
}

int main()
{
	int b = 5;
	int *pb = &b;
	printf("before: b = %d\t&b = %p\n",b, &b);
	printf("before: *pb = %d\tpb = %p\n",*pb, pb);
	pb = f1();
	//printf("after : b = %d\t&b = %p\n",b, &b);
	printf("after : *pb = %d\tpb = %p\n",*pb, pb);
    return 1;
}

C语言编程不易发现的错误(二)

#include "stdio.h"
//返回局部变量a的地址 
int* f1()
{
	int a = 9;
	int *pa = &a;
	printf("a = %d\t&a = %p \n",a, &a);
	printf("*pa = %d\tpa = %p \n",*pa, pa);
	return pa;
}

int main()
{
	int b = 5;
	int *pb = &b;
	printf("before: b = %d\t&b = %p\n",b, &b);
	printf("before: *pb = %d\tpb = %p\n",*pb, pb);
	pb = f1();
	printf("after : b = %d\t&b = %p\n",b, &b);
	printf("after : *pb = %d\tpb = %p\n",*pb, pb);
    return 1;
}

C语言编程不易发现的错误(二)

总结1

  如上2个实例便是在函数中返回局部变量地址。其中第1个例子直接输出*pb,其结果是对的。但若像第2个例子一样,在输出前添加如下语句:
    printf(“after : b = %d\t&b = %p\n”,b, &b);
  其结果是错误的,因为此语句修改栈区内容。所以返回局部变量地址,其结果可能正确,也可能错误,这取决于函数之后的代码是否使用并修改栈区内容。而计算机编程必须确保程序执行正确性和唯一性,任何不确定的运行结果都是错误的。
  
  

#include "stdio.h"
//返回静态局部变量a的地址 
int* f1()
{
	static int a = 9;
	int *pa = &a;
	printf("a = %d\t&a = %p \n",a, &a);
	printf("*pa = %d\tpa = %p \n",*pa, pa);
	return pa;
}

int main()
{
	int b = 5;
	int *pb = &b;
	printf("before: b = %d\t&b = %p\n",b, &b);
	printf("before: *pb = %d\tpb = %p\n",*pb, pb);
	pb = f1();
	printf("after : b = %d\t&b = %p\n",b, &b);
	printf("after : *pb = %d\tpb = %p\n",*pb, pb);
    return 1;
}

C语言编程不易发现的错误(二)

#include "stdio.h"
//返回字符串常量的地址 
char* f1()
{
	int a = 9;
	char *pa = "a";
	printf("a = %d\t&a = %p \n",a, &a);
	printf("*pa = %d\tpa = %p \n",*pa, pa);
	return pa;
}

int main()
{
	int b = 5;
	char *pb = "b";
	printf("before: b = %d\t&b = %p\n",b, &b);
	printf("before: *pb = %d\tpb = %p\n",*pb, pb);
	pb = f1();
	printf("before: b = %d\t&b = %p\n",b, &b);
	printf("after : *pb = %d\tpb = %p\n",*pb, pb);
    return 1;
}

C语言编程不易发现的错误(二)

#include "stdio.h"
//返回整型常量的地址 
int* f1()
{
	int a[3] = {9,6,3};
	int *pa = a;
	printf("a = %d\t&a = %p \n",a[0], a);
	printf("*pa = %d\tpa = %p \n",*pa, pa);
	return pa;
}

int main()
{
	int b = 5;
	int *pb = &b;
	printf("before: b = %d\t&b = %p\n",b, &b);
	printf("before: *pb = %d\tpb = %p\n",*pb, pb);
	pb = f1();
	printf("before: b = %d\t&b = %p\n",b, &b);
	printf("after : *pb = %d\tpb = %p\n",*pb, pb);
    return 1;
}

C语言编程不易发现的错误(二)

#include "stdio.h"
#include "stdlib.h"
//返回动态分配的地址 
int* f1()
{
	int a = 9;
	int *pa = (int*) malloc(8);
	*pa = a;
	printf("a = %d\t&a = %p \n",a, &a);
	printf("*pa = %d\tpa = %p \n",*pa, pa);
	return pa;
}

int main()
{
	int b = 5;
	int *pb = &b;
	printf("before: b = %d\t&b = %p\n",b, &b);
	printf("before: *pb = %d\tpb = %p\n",*pb, pb);
	pb = f1();
	printf("before: b = %d\t&b = %p\n",b, &b);
	printf("after : *pb = %d\tpb = %p\n",*pb, pb);
    return 1;
}

C语言编程不易发现的错误(二)

总结2

  从以上4个例子可看出,返回静态局部变量的地址、常量的地址和动态分配的地址,其结果都是正确的。以上地址指向的内容都不在栈区中,不受释放函数的影响。
  虽然以上3种方式是正确的,但如果不是一定要这样处理,个人不建议在函数中返回任何局部变量的地址。