指针作为形参进行传递注意事项
来源:互联网 发布:网络 英文单词 编辑:程序博客网 时间:2024/06/13 23:44
一个例子
参考:http://blog.csdn.net/sszgg2006/article/details/9037675
#include<iostream>using namespace std;int m_value = 1;void func(int *p){ p = &m_value;}int main(int argc, char *argv[]){ int n = 2; int *pn = &n; cout << *pn << endl; func(pn); cout << *pn << endl; return 0;}
运行结果:
2
2
修改func函数如下
void func(int *p){ /*p = &m_value;*/ *p = 3;}
运行结果:
2
3
修改func函数如下:
void func(int *p)
{
/p = &m_value;/
//*p = 3;
int a = 3;
*p =a;
}
依然是2,3
修改func函数如下:
void func(int *p){ /*p = &m_value;*/ //*p = 3; int a = 3; p =&a;}
结果是2,2
解释:
编译器总是要为函数的每个参数制作临时副本,指针参数p的副本是 _p,编译器使 _p = p。
如果函数体内的程序修改了_p所指向的内容,就导致参数p的内容作相应的修改。把_p所指的内存地址改变了,那么 _p指向的内存块,和p指向的内存块就不一样了。所以对p毫无影响。只要程序里不改变 _p的指向, _p和p就是一样的,操作 _p内容,就是操作p的内容。
下面常用的交换程序:
#include <stdio.h>int *swap(int *px, int *py){ int temp; temp = *px; *px = *py; *py = temp; return px;}int main(void){ int i = 10, j = 20; int *p = swap(&i, &j); printf("now i=%d j=%d *p=%d\n", i, j, *p); return 0;}
结果:
now i=20 j=10 *p=20
进一步思考
函数里面分配内存
void myMalloc(char *s) //我想在函数中分配内存,再返回 { s = (char *)malloc(100);}void main(){ char *p = NULL; myMalloc(p); //这里的p实际还是NULL,p的值没有改变,为什么? if (p) { cout << "p不为空" << endl; free(p); } else cout << "p为空" << endl;}
结果
p为空
看另一个例子:
void myMalloc(char **s) //我想在函数中分配内存,再返回 { *s = (char *)malloc(100);}void main(){ char *p = NULL; myMalloc(&p); //传递的是p的地址,这里的p可以得到正确的值了 if (p) { cout << "p不为空" << endl; memcpy(p, "Hello",6);//如果拷贝5个的话,最后一个'\0'没有拷贝过去,输出p会出现Hello,烫烫烫... strcpy(p, "hello"); cout << p << endl; free(p); } else cout << "p为空" << endl;}
结果:
p不为空hello
解释:
1.被分配内存的是形参s,p没有分配内存
2.被分配内存的是形参s指向的指针p,所以分配了内存
第三个小例子:
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"); // 运行错误 }
道理一样。
所以要想借助函数进行分配内存,需要传递的是“指针的指针”,就是第一个例子。
void GetMemory2(char **p, int num) { *p = (char *)malloc(sizeof(char) * num); }
另外还可以:用函数返回值来传递动态内存
char *GetMemory3(int num) { char *p = (char *)malloc(sizeof(char) * num); return p; } void Test3(void) { char *str = NULL; str = GetMemory3(100); strcpy(str, "hello"); cout<< str << endl; free(str); }
输出结果:hello
注意这里函数返回值传递的动态内存,必须是在“堆上”申请的内存!!!
不要用return语句返回指向“栈内存”的指针,因为该内存在函数结束时自动消亡
char *GetString(void) { char p[] = "hello world"; return p; // 编译器将提出警告 } void Test4(void) { char *str = NULL; str = GetString(); // str 的内容是垃圾 cout<< str << endl; }
但是下面的又会让人疑惑:
char *GetString2(void) { char *p = "hello world"; return p; } void Test5(void) { char *str = NULL; str = GetString2(); cout<< str << endl; }
这个能运行,输出:hello world
函数Test5运行虽然不会出错,但是函数GetString2的设计概念却是错误的。因为GetString2内的“hello world”是常量字符串,位于静态存储区,它在程序生命期内恒定不变。无论什么时候调用GetString2,它返回的始终是同一个“只读”的内存块。
char *pp = "wocao!"; pp[0] = '1';//这样赋值是错误的。
所以上述测试时:
多加一句是会报错的
void main(void){ char *str = NULL; str = GetString2(); cout << str << endl; str[0] = '1';//报错}
<高质量C C++编程指南>这本书上说: 指针p 指向常量字符串(位于常量存储区),常量字符串的内容是不可以被修改的,企图修改常量字符串的内容而导致运行错误。所以这个问题出现的原因是char*p=”abcdefghi”,赋值的是字符串常量,存储在常量存储区,而常量存储区的内容是无法修改的。
如果使用数组来代替的话,数据就存储在堆栈空间,堆栈空间的内容是可以修改的,就不会出现运行时错误。
另外再加一个小总结:
程序1:void myMalloc(char *s) //我想在函数中分配内存,再返回{ s=(char *) malloc(100); // s是值参, 函数返回后就回复传递前的数值,无法带回分配的结果}这个和调用 void func (int i) {i=1;}; 一样,退出函数体,i指复原的程序2:void myMalloc(char **s){ *s=(char *) malloc(100); // 这个是可以的}等价于void int func(int * pI) {*pI=1;} pI指针不变,指针指向的数据内容是变化的值参本身不变,但是值参指向的内存的内容发生了变化。程序3:void fun(int *p){ int b=100; p=&b; // 等同于第一个问题, b的地址并没有被返回}程序4:void fun(int *p){ *p=100; // okay}结论:1.函数的返回值是指针类型的,检查是静态内存指针还是堆内存指针还是栈内存指针,栈内存指针是绝对要不得滴!2.函数需要使用指针参数进行传入传出的,在函数中只能对指针的指向的值(*p)进行修改,而不能修改指针指向,也就是指针地址!(函数中不得修改指针参数的地址,否则请使用指针的指针!)
推荐好的总结:
http://blog.chinaunix.net/uid-20788636-id-1841283.html
其中总结非常棒:
一般在函数中定义一个对象有两种方法: 1、在栈上建立局部变量。注意,在栈上时!栈用于函数是为了返回时找得到调用点(在调用时压入栈的),那么,返回时要POP才能得到。函数体中建立的任何东西都消失了(返回值除外),你返回的指针指向的内容现在不知被用作什么用途了,如果你还要修改的话,那么后果不能确定。 2、在堆中分配。返回时不会摧毁,因为堆是全局存在的。但函数的调用者要记得delete回来的指针。
指针的引用
void func(int *&p){ p = &m_value; // 也可以根据你的需求分配内存 /*p = new int; *p = 5;*/}int main(int argc, char *argv[]){ int n = 2; int *pn = &n; cout << *pn << endl; func(pn); cout << *pn << endl; return 0;}
结果是:2,1
此时传递过去就是指针p,因为引用!
看一下func(int *&p)方法
p: 是指针的引用,main()方法里的 *pn
*p:是main()方法里的pn指向的内容。
- 指针作为形参进行传递注意事项
- 数组指针作为形参传递
- 二维数组作为形参进行传递
- 数组名在作为形参传递时的注意事项
- 数组指针,指针数组,函数指针,指针作为形参和返回值的注意事项
- 数组指针,指针数组,二维数组作为参数传递给以指针的指针作为形参的函数
- 指针和引用作为形参传递下去的区别
- 指针作为参数传递
- 指针作为参数传递
- 指针作为参数传递
- 指针作为形参
- 指针作为函数参数传递
- 指针作为函数参数传递
- 指针作为函数参数传递
- 指针作为函数参数传递
- 指针作为函数参数传递
- 指针作为函数参数传递
- 指针作为函数参数传递
- vue笔记----组件
- Tomcat启动报错或警告: org.apache.catalina.webresources.Cache.getResource Unable to add the resource
- tomcat启动时8080端口被占用的解决办法
- 统计字符频率
- 解档归档直接copy我就好了
- 指针作为形参进行传递注意事项
- Shell comm比较文件命令的使用
- (¥######非常全好)十分钟搞定pandas(#########非常全好)
- Java异常捕获之try-catch-finally-return的执行顺序
- 点击input,value值消失
- 【OpenCV入门指南】第四篇 图像的二值化
- jar命令(一)-jar打包class文件
- 禁止vim生成 un~文件
- Bean实例化问题