c++用参数返回堆上的空间
2015-03-14 20:13
127 查看
《高质量c++和c编程》7.4 指针参数是如何传递内存的一节中写道:
无法返回内存,可以用如下方式
个人的理解就是,实际上指针传递仍然是一种值传递,只不过在参数是指针的时候,传递的是指针的副本,这样你在地址上的操作实际就反映到了内存中,举个例子来说,假设有一个函数
当用调用时fun(q),会产生实参的一个副本设为_p,函数体为副本_p分配了内存,实际上并未改变实参p,这就是GetMemory没有成功的原因。相反,如果我们有如下函数
在这个函数中,当发生实参调用的时候,仍然会产生实参的副本,但是注意这里不是改变副本,而是改变副本指向的内存中的内容,这里p是一个整形指针,在内存中占四个字节,副本和实参指向同一片内存,所以当你
在以副本为地址的内存内赋值3,实际也就是改变了实参指向的内存中的内容。
总结一下就是:指针传递仍然是值传递,所以我们在函数体内只有操作*p才会达到我们的指针传递要求,而不是操作p,这样操作只在副本上,实际并不反映到实参指向的内存。
书中另一种方法是:
实际是将堆的特性和return相结合,堆上分配的内存在函数不会释放,而return实际返回的p的一个副本,但是这里的副本是一个指针,简单的说是一个内存地址,而这个地址在函数结束后并没有释放,所以,我们可以继续使用。如果是普通的局部变量,return返回它的一个副本,随后局部变量随着函数的结束而被释放,这在某些时候会引起麻烦,比如
至于return似乎还有东西说,一时想不起。。。
事情总有例外,今天小妞找我调试程序,发现了一件很奇特的事情,看代码
这个程序可以正确编译执行。而下面代码:
这个代码确实在运行时出错
分析了一下,个人认为虽然两个函数的参数都是char **s,但是一个在main()中先分配,一个直接在getArray中分配,原因就在于此,getarray函数在main函数中先分配了内存,然后传递给它,虽然仍然是值传递,但是s的元素是指针,getarray函数中在main函数分配的内存上完成了操作,所以当函数结束时,所有操作仍然保留下来。getarray1函数不同,它是在函数体内完整分配内存,然后施加操作的,相当于都在副本上,所有操作都不会在函数结束后保留下来。
这是个人的一点理解,如有不对的地方还请指教。
[code]void GetMemory(char *p, int num) { p = (char *)malloc(sizeof(char) * num); } void Test(void) { char *str = NULL; GetMemory(str, 100); // str 仍然为 NULL strcpy(str, "hello"); // 运行错误 }
无法返回内存,可以用如下方式
[code]void GetMemory2(char **p, int num) { *p = (char *)malloc(sizeof(char) * num); } void Test2(void) { char *str = NULL; GetMemory2(&str, 100); // 注意参数是 &str ,而不是str strcpy(str, "hello"); cout<< str << endl; free(str); }
个人的理解就是,实际上指针传递仍然是一种值传递,只不过在参数是指针的时候,传递的是指针的副本,这样你在地址上的操作实际就反映到了内存中,举个例子来说,假设有一个函数
[code]void fun(int *p) { p = new int; }
当用调用时fun(q),会产生实参的一个副本设为_p,函数体为副本_p分配了内存,实际上并未改变实参p,这就是GetMemory没有成功的原因。相反,如果我们有如下函数
[code]void fun(int *p) { *p = 3; }
在这个函数中,当发生实参调用的时候,仍然会产生实参的副本,但是注意这里不是改变副本,而是改变副本指向的内存中的内容,这里p是一个整形指针,在内存中占四个字节,副本和实参指向同一片内存,所以当你
在以副本为地址的内存内赋值3,实际也就是改变了实参指向的内存中的内容。
总结一下就是:指针传递仍然是值传递,所以我们在函数体内只有操作*p才会达到我们的指针传递要求,而不是操作p,这样操作只在副本上,实际并不反映到实参指向的内存。
书中另一种方法是:
[code]char *GetMemory3(int num) { char *p = (char *)malloc(sizeof return p; } void Test3(void) { char *str = NULL; str = GetMemory3(100); strcpy(str, "hello"); cout<< str << endl; free(str); }
实际是将堆的特性和return相结合,堆上分配的内存在函数不会释放,而return实际返回的p的一个副本,但是这里的副本是一个指针,简单的说是一个内存地址,而这个地址在函数结束后并没有释放,所以,我们可以继续使用。如果是普通的局部变量,return返回它的一个副本,随后局部变量随着函数的结束而被释放,这在某些时候会引起麻烦,比如
[code]char *GetString(void) { char p[] = "hello world"; return p; // 编译器将提出警告 } void Test4(void) { char *str = NULL; str = GetString(); // str 的内容是垃圾 cout<< str << endl; }
至于return似乎还有东西说,一时想不起。。。
事情总有例外,今天小妞找我调试程序,发现了一件很奇特的事情,看代码
[code]void getArray(char **s, int N) { std::ifstream in("test.txt"); if (!in.is_open()) { std::cout<<"error"<<std::endl; } int i = 0; while(i < N) { s[i] = (char*)malloc(sizeof(char)*100); in.getline(s[i], 100); ++i; } in.close(); } int main() { char **s = (char **)malloc(sizeof(char) * 4); getArray(s, 4); for (int i=0; i<4; i++) { std::cout<<s[i]<<std::endl; } return 0; }
这个程序可以正确编译执行。而下面代码:
[code]void getArray1(char **s, int N) { // s = (char **)malloc(sizeof(char) * 4); s = new char*[4]; std::ifstream in("test.txt"); if (!in.is_open()) { std::cout<<"error"<<std::endl; } int i = 0; while(i < N) { // s[i] = (char*)malloc(sizeof(char)*100); s[i] = new char[100]; in.getline(s[i], 100); ++i; } in.close(); } int main() { char **s; getArray1(s, 4); for (int i=0; i<4; i++) { std::cout<<s[i]<<std::endl; } return 0; }
这个代码确实在运行时出错
分析了一下,个人认为虽然两个函数的参数都是char **s,但是一个在main()中先分配,一个直接在getArray中分配,原因就在于此,getarray函数在main函数中先分配了内存,然后传递给它,虽然仍然是值传递,但是s的元素是指针,getarray函数中在main函数分配的内存上完成了操作,所以当函数结束时,所有操作仍然保留下来。getarray1函数不同,它是在函数体内完整分配内存,然后施加操作的,相当于都在副本上,所有操作都不会在函数结束后保留下来。
这是个人的一点理解,如有不对的地方还请指教。
相关文章推荐
- c++用参数返回堆上的空间
- c++用参数返回堆上的空间
- c++ 命名空间 以及 作用域 函数参数 面向对象实验报告
- [C++] C++中const修饰指针,变量, 函数参数和函数返回值的用法总结
- C++函数参数传值OR传引用_C++函数返回值返回对象OR对象引用
- C++利用不完全实例化来获得函数模板参数的返回值和参数
- C++利用不完全实例化来获得函数模板参数的返回值和参数
- visual studio 指针操作含参数返回,指针返回时最好开辟空间。
- c++函数在传入对象参数和返回对象时候的内存调用情况
- C++ Name Mangling 为什么不编码返回值参数
- 常量函数、常量引用参数、常量引用返回值[C++]
- C++:建立一个被称为sroot()的函数,返回其参数的二次方根。重载sroot()3次,让它返回整数、长整数与双精度的二次方根
- 常量函数、常量引用参数、常量引用返回值[C++]
- C++函数返回多个参数
- C++ 参数传递,定义与声明,命名空间等基本知识
- C++获取Lua全局变量和执行Lua多参数多返回值函数
- C++中函数的参数是传值还是传址?return返回的变量是传值还是传址?
- C++ 多维数组作为函数的返回值和参数
- C++利用不完全实例化来获得函数模板参数的返回值和参数
- C# 调用C/C++ Dll(参数含char*指针,返回char*指针)