各位先看一下下面的题目,看看能否给出答案以及真正了解原因。
#include "stdio.h" #include "string.h" #include "malloc.h" void swap(int a,int b){ int temp; temp = a; a = b; b = temp; } int get_int(int a){ int i = 1 + a; return i; } char* get_memory0(){ char *p = (char *)malloc(sizeof(char) * 20); strcpy(p,"hello world"); return p; } char* get_memory1(){ char *p = "hello world"; return p; } char* get_memory2(){ char p[] = "hello world"; return p; } int main(){ int x=4,y=3; swap(x,y); int z=x-y; printf("z = %d\n",z);//问题1 z=get_int(z); printf("z = %d\n",z);//问题2 char* c0 = get_memory0(); printf("c0 = %s\n",c0);//问题3 const char* c1 = get_memory1(); printf("c1 = %s\n",c1);//问题4 char* const c2 = get_memory2(); printf("c2 = %s\n",c2);//问题5 }
问题1的答案:z=1,,对于这个答案,相信很多人都不会答错,都知道a和b没有发生交换。但是理解其中的原因吗?
swap(int a,int b)是一个参数传值得函数,这就意味着函数体内的a和b是参数int a和int b的实参在函数内的 一份局部拷贝,所以a和b实际可以看成是局部变量,它们的值是由int a和int b传的实参复制而来的。函数内a和b的值得改变只在函数体内部有效,当函数体内的a和b变量离开函数作用域的时候,a和b变量就被销毁了。函数的实参值并没有发生改变,或者说自始至终没有改变过,改变的只是它们在函数体内的一份局部拷贝a和b。
问题2的答案:z=2
int get_int(int a)属于返回值是传值的函数,这就意味着函数int get_int(int a)会在函数返回处产生一个临时对象,用户存放局部变量i的值的一份拷贝(变量i的右值的拷贝),临时对象是没有名称的,这份没有名称的对象的值(右值)会存储在调用者的“栈”中。所以当i作为局部变量离开作用域后,虽然被销毁了,但它的拷贝仍然存在,并在函数返回时作为“右值”赋给“左值z”。
问题3的答案:c0=“ hello world”
函数返回的是指向“堆”内存的在指针。程序中malloc()是用于分配“堆”内存的库函数,而对于“堆”内存,只要程序中没有调用free()库函数去释放该“堆”内存,那么在程序运行期间,malloc()库函数分配的“堆”内存将一直存在。char* get_memory0()会在函数返回处产生一个队返回变量p的“左值”的拷贝,也就是在“左值”的拷贝中存储了指向“堆”的地址。作为局部变量的p,在离开了函数作用域的时候,虽然被销毁了,但函数返回的“左值”的拷贝是存在的,该拷贝存储了指向“堆”的地址,而该“堆”的值是“hello
world”。
问题4的答案:c1="hello world"
在char* p = “hello world”中,左值是 局部指针变量p,存储于函数栈上,右值是字符串常量“hello world”,存储于常量存储区。
char* get_memory 1()属于返回值是传指针的函数,这就意味着函数char* get_memory 1()会在函数返回处产生一个对返回对象的“左值”的拷贝,也就是在“左值”拷贝中存储了指向字符串常量“hello world”的地址。作为局部变量的p,在离开函数作用域的时候虽然被销毁了,但 函数返回的“左值“拷贝仍然存储了指向常量存储区的字符串常量”hello world“的地址。
问题5的答案:c2=未知
返回值是传指针,会在函数返回时产生”左值“拷贝。
函数返回的”左值“拷贝指向的是局部变量数组p[12]的首地址。当局部数组p[12]离开作用域后会被自动销毁。这时,函数返回的”左值“拷贝指向的是一个被销毁的局部变量地址。