函数参数的传递问题(一级指针和二级指针)

函数参数的传递问题(一级指针和二级指针) [转]

原以为自己对指针掌握了,却还是对这个问题不太明白。请教!  
程序1:  
void  myMalloc(char  *s)  //我想在函数中分配内存,再返回  
{  
     s=(char  *)  malloc(100);  
}  
 
void  main()  
{  
     char  *p=NULL;  
     myMalloc(p);    //这里的p实际还是NULL,p的值没有改变,为什么?  
     if(p)  free(p);  
}  
程序2:void  myMalloc(char  **s)  
{  
     *s=(char  *)  malloc(100);  
}  
 
void  main()  
{  
     char  *p=NULL;  
     myMalloc(&p);    //这里的p可以得到正确的值了  
     if(p)  free(p);  
}  
程序3:  
#include<stdio.h>  
 
void  fun(int  *p)  
{  
       int  b=100;  
       p=&b;  
}  
 
main()  
{  
       int  a=10;  
       int  *q;  
       q=&a;  
       printf("%d/n",*q);  
       fun(q);  
       printf("%d/n",*q);  
       return  0;  
}  
结果为  
10  
10  
程序4:  
#include<stdio.h>  
 
void  fun(int  *p)  
{  
       *p=100;  
}  
 
main()  
{  
       int  a=10;  
       int  *q;  
       q=&a;  
       printf("%d/n",*q);  
       fun(q);  
       printf("%d/n",*q);  
       return  0;  
}  
结果为  
10  
100  
为什么?  
 
 
 
 
---------------------------------------------------------------  
 
1.被分配内存的是行参s,p没有分配内存  
2.被分配内存的是行参s指向的指针p,所以分配了内存  
---------------------------------------------------------------  
 
不是指针没明白,是函数调用的问题!看看这段:  
 
7.4指针参数是如何传递内存的?  
           如果函数的参数是一个指针,不要指望用该指针去申请动态内存。示例7-4-1中,Test函数的语句GetMemory(str,  200)并没有使str获得期望的内存,str依旧是NULL,为什么?  
 
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"函数参数的传递问题(一级指针和二级指针);            //  运行错误  
}  
示例7-4-1  试图用指针参数申请动态内存  
 
毛病出在函数GetMemory中。编译器总是要为函数的每个参数制作临时副本,指针参数p的副本是  _p,编译器使  _p  =  p。如果函数体内的程序修改了_p的内容,就导致参数p的内容作相应的修改。这就是指针可以用作输出参数的原因。在本例中,_p申请了新的内存,只是把_p所指的内存地址改变了,但是p丝毫未变。所以函数GetMemory并不能输出任何东西。事实上,每执行一次GetMemory就会泄露一块内存,因为没有用free释放内存。  
如果非得要用指针参数去申请内存,那么应该改用“指向指针的指针”,见示例7-4-2。  
 
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);              
}  
示例7-4-2用指向指针的指针申请动态内存  
 
由于“指向指针的指针”这个概念不容易理解,我们可以用函数返回值来传递动态内存。这种方法更加简单,见示例7-4-3。  
 
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);              
}  
示例7-4-3  用函数返回值来传递动态内存  
 
用函数返回值来传递动态内存这种方法虽然好用,但是常常有人把return语句用错了。这里强调不要用return语句返回指向“栈内存”的指针,因为该内存在函数结束时自动消亡,见示例7-4-4。  
 
char  *GetString(void)  
{  
           char  p[]  =  "hello  world";  
           return  p;            //  编译器将提出警告  
}  
void  Test4(void)  
{  
char  *str  =  NULL;  
str  =  GetString();            //  str  的内容是垃圾  
cout<<  str  <<  endl;  
}  
示例7-4-4  return语句返回指向“栈内存”的指针  
 
用调试器逐步跟踪Test4,发现执行str  =  GetString语句后str不再是NULL指针,但是str的内容不是“hello  world”而是垃圾。  
如果把示例7-4-4改写成示例7-4-5,会怎么样?  
 
char  *GetString2(void)  
{  
           char  *p  =  "hello  world";  
           return  p;  
}  
void  Test5(void)  
{  
           char  *str  =  NULL;  
           str  =  GetString2();  
           cout<<  str  <<  endl;  
}  
示例7-4-5  return语句返回常量字符串  
 
函数Test5运行虽然不会出错,但是函数GetString2的设计概念却是错误的。因为GetString2内的“hello  world”是常量字符串,位于静态存储区,它在程序生命期内恒定不变。无论什么时候调用GetString2,它返回的始终是同一个“只读”的内存块。  
 
---------------------------------------------------------------  
 
看看林锐的《高质量的C/C++编程》呀,上面讲得很清楚的  
---------------------------------------------------------------  
 
对于1和2:  
如果传入的是一级指针S的话,  
那么函数中将使用的是S的拷贝,  
要改变S的值,只能传入指向S的指针,即二级指针  
 
---------------------------------------------------------------  
 
程序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:  
void  myMalloc(char  *s)  //我想在函数中分配内存,再返回  
{  
     s=(char  *)  malloc(100);//传过来的是P所指的地址,并不是P的地址,所以改变S不会改变P  
}  
 
void  main()  
{  
     char  *p=NULL;  
     myMalloc(p);    //这里的p实际还是NULL,p的值没有改变,为什么?  
     if(p)  free(p);  
}  
程序2:void  myMalloc(char  **s)  
{  
     *s=(char  *)  malloc(100);//S指向的是P的地址,所以改变了P所指的内存单元.  
}  
 
void  main()  
{  
     char  *p=NULL;  
     myMalloc(&p);    //这里的p可以得到正确的值了  
     if(p)  free(p);  
}  
程序3:  
#include<stdio.h>  
 
void  fun(int  *p)  
{  
       int  b=100;  
       p=&b;  
}  
 
main()  
{  
       int  a=10;  
       int  *q;  
       q=&a;  
       printf("%d/n",*q);  
       fun(q);道理同第一个程序.  
       printf("%d/n",*q);  
       return  0;  
}  
结果为  
10  
10  
程序4:  
#include<stdio.h>  
 
void  fun(int  *p)  
{  
       *p=100;//参数P和实参P所指的内存单元是相同的.所以改变了参数P的内存单元内容,就改变了实参  
                     //的内存单元内容  
}  
 
main()  
{  
       int  a=10;  
       int  *q;  
       q=&a;  
       printf("%d/n",*q);  
       fun(q);  
       printf("%d/n",*q);  
       return  0;  
}  
结果为  
10  
100  
为什么?  
---------------------------------------------------------------  
 
void  main()  
{  
     char  *p=NULL;  
     myMalloc(p);    //这里的p实际还是NULL,p的值没有改变,为什么?  
     if(p)  free(p);  
}  
 
 
void  myMalloc(char  *s)  //我想在函数中分配内存,再返回  
{  
     s=(char  *)  malloc(100);  
}  
 
myMalloc(p)的执行过程:  
分配一个临时变量char  *s,s的值等于p,也就是NULL,但是s占用的是与p不同的内存空间。此后函数的执行与p一点关系都没有了!只是用p的值来初始化s。  
然后s=(char  *)  malloc(100),把s的值赋成malloc的地址,对p的值没有任何影响。p的值还是NULL。  
注意指针变量只是一个特殊的变量,实际上它存的是整数值,但是它是内存中的某个地址。通过它可以访问这个地址。  
 
程序2:void  myMalloc(char  **s)  
{  
     *s=(char  *)  malloc(100);  
}  
 
void  main()  
{  
     char  *p=NULL;  
     myMalloc(&p);    //这里的p可以得到正确的值了  
     if(p)  free(p);  
}  
程序2是正确的,为什么呢?看一个执行过程就知道了:  
myMalloc(&p);将p的地址传入函数,假设存储p变量的地址是0x5555,则0x5555这个地址存的是指针变量p的值,也就是Ox5555指向p。  
调用的时候同样分配一个临时变量char  **s,此时s  的值是&p的值也就是0x5555,但是s所占的空间是另外的空间,只不过它所指向的值是一个地址:Ox5555。  
*s=(char  *)  malloc(100);这一句话的意思是将s所指向的值,也就是0x5555这个位置上的变量的值赋为(char  *)  malloc(100),而0x5555这个位置上存的是恰好是指针变量p,这样p的值就变成了(char  *)  malloc(100)的值。即p的值是新分配的这块内存的起始地址。  
 
这个问题理解起来有点绕,关键是理解变量作函数形参调用的时候都是要分配一个副本,不管是传值还是传址。传入后就和形参没有关系了,它不会改变形参的值。myMalloc(p)不会改变p的值,p的值当然是NULL,它只能改变p所指向的内存地址的值。但是myMalloc(&p)为什么就可以了,它不会改变(&p)的值也不可能改变,但是它可以改变(&p)所指向内存地址的值,即p的值。  
 
---------------------------------------------------------------  
 
你要弄清楚的是指针变量和指针所指的变量(可能是一片内存)。  
 
指针变量和普通变量一样存储的,  
 
如int  *p;  int  i;  p和i都是变量,都占用一个字的内存,都可

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/254701.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Win7下使用U盘安装linux Ubuntu16.04双系统图文教程

Win7下使用U盘安装linux Ubuntu16.04双系统图文教程 Ubuntu&#xff08;友帮拓、优般图、乌班图&#xff09;是一个以桌面应用为主的开源GNU/Linux操作系统&#xff0c;Ubuntu 是基于DebianGNU/Linux&#xff0c;支持x86、amd64&#xff08;即x64&#xff09;和ppc架构&#xf…

SynchronizationContext

SendOrPostCallback xxx vg > { Text "内部&#xff1a; "vg.ToString(); };dynamic vx new { a SynchronizationContext.Current, b xxx };Thread td new Thread(x >{dynamic tmp x;// SynchronizationContext ds x as SynchronizationContext;for (in…

CoDeSys的前世今生

&#xfeff;&#xfeff;工作以及网上看到不少人说&#xff0c;CoDeSys和西门子step7&#xff0c;在德国都属于标准过程&#xff0c;牛逼的小朋友都可以用其编程&#xff0c;不知真假&#xff0c;相信无风不起浪&#xff0c;多少有些依据&#xff0c;看看国內清一色的日系编程…

UVALive 7324 ASCII Addition (模拟)

ASCII Addition题目链接&#xff1a; http://acm.hust.edu.cn/vjudge/contest/127407#problem/A Description Nowadays, there are smartphone applications that instantly translate text and even solve math problems if you just point your phone’s camera at them. You…

Eclipse中执行Ant脚本出现Could not find the main class的问题及解

试过了&#xff1a;https://blog.csdn.net/bookroader/article/details/2300337 但是不管用&#xff0c;偶然看到这篇没有直接关系的 https://blog.csdn.net/jiuyueguang/article/details/9350753 联想了一下。项目是JDK1.5&#xff0c;Eclipse是JDK1.8启动&#xff0c;所以在R…

获得变量的名称获得传入参数的参数类型与堆栈中的函数名获得变量的名称

获得变量的名称 获得变量的名称函数 public static string GetVarName(Expression<Func<变量类型, 变量类型>> exp) public static string GetVarName_Int(Expression<Func<int, int>> exp){return ((MemberExpression)exp.Body).Member.Name;}使用时…

视频通话研究002

还是关于视频质量。经測试&#xff0c;在公网server使用SQCIF(128x98)进行视频通话。2个client都是这个设置&#xff0c;感觉不出马赛克&#xff0c;模糊严重&#xff0c;在一个手机client抓包&#xff0c;例如以下&#xff1a; 第1,2行是client发到server的数据&#xff1b;第…

实力打脸: 量子隐形传输与 “瞬间移动” 毫无关系

有两个团队已经在量子隐形传输研究领域创造了新的传输记录&#xff1a;利用深不可测的量子力学知识将一个粒子的量子态迅速从一个位置迁移到另一个位置的粒子上。其中一个团队采用这种方法&#xff0c;运用一种光学纤维将一个光子的量子态穿越加拿大西南部的一个城市&#xff0…

Android初级教程:使用xml序列器

之前备份短信的时候生成xml都是手动拼写的&#xff0c;有一个问题&#xff1a;当短信里面存在</body>这样的标签的时候&#xff0c;最后结果就不是完整的xml文件&#xff0c;显然出错。但是&#xff0c;今天使用序列化器的方式&#xff0c;就能有效的解决上边遇到的问题。…

架构师之我见

架构师之我见 2009-08-06 架构师是一个项目组的灵魂人物&#xff0c;他决定着整个系统的技术选型、整体架构以及模块划分&#xff0c;同时还可能担当与领导层的沟通角色&#xff0c;从某种意义上来说&#xff0c;架构师在很大程度上决定着项目的成败与否&#xff0c;正所谓火车…

KUKA 声明变量时的几点注意

临时变量&#xff1a; 1、src文件中定义的局部变量&#xff0c;该种变量存在于内存中的栈上。子程序调用时&#xff0c;变量在栈上动态生成。调用结束后从栈中自动销毁。 因为存在于栈上的原因&#xff0c;访问该变量需要栈指针&#xff0c;所以该种变量无法在机器人程序运行时…

三个点拟合圆形的函数C#

三个点拟合圆形的函数 函数说明 public void FitCircleFromThreePoints(double 点1X, double 点1Y, double 点2X, double 点2Y, double 点3X, double 点3Y, out double 圆心X坐标, out double 圆心Y坐标, out double 圆形半径大小)public void FitCircleFromThreePoints(doub…

poj3264Balanced Lineup(倍增ST表)

Balanced LineupTime Limit: 5000MS Memory Limit: 65536KTotal Submissions: 52328 Accepted: 24551Case Time Limit: 2000MSDescription For the daily milking, Farmer Johns N cows (1 ≤ N ≤ 50,000) always line up in the same order. One day Farmer John decides to …

LightOJ1283 Shelving Books(DP)

题目 Source http://www.lightoj.com/volume_showproblem.php?problem1283 Description You are a librarian. You keep the books in a well organized form such that it becomes simpler for you to find a book and even they look better in the shelves. One day you ge…

量子传输技术转移一个人需要4500万亿年

看过《星际迷航》的朋友一定不会忘记这句经典的台词&#xff1a;斯科蒂&#xff0c;将我传输过去&#xff01;其中涉及到量子隐形传输的技术&#xff0c;可以把物体从三维时空一处传输到另一处。但可惜的是&#xff0c;这种看着非常炫的技术或许根本无法实现。 到目前为止&…

使用OutputDebugString帮助调试

使用OutputDebugString帮助调试 前面我已经介绍了使用TRACE来帮助我们调试&#xff0c;但使用TRACE有一个限制&#xff0c;只能在将程序DEBUG编译状态下才能使用&#xff0c;下面我们介绍OutputDebugString函数&#xff0c;通过它&#xff0c;可以在在DEBUG或RELEASE情况也可以…

leetcode-551-Student Attendance Record I(判断是否出现连续几个相同字符)

题目描述&#xff1a; You are given a string representing an attendance record for a student. The record only contains the following three characters: A : Absent.L : Late.P : Present.A student could be rewarded if his attendance record doesnt contain more t…

简单实现

1.创建接口和实现类 &#xff08;模拟实现查询天气&#xff09; 接口&#xff1a; package com.learning.weather;/*** * weather 接口 &#xff1a;实现模拟wsdl*/ public interface WeatherInterface {/*** 查询天气* param name* return*/public String queryWeather(Strin…

halcon联合C#测量十字Mark中心

halcon联合C#测量十字Mark中心 函数说明 public void FitRectangleMeasure(HWindow 窗口句柄, HImage 图像, out double 中心Y坐标, out double 中心X坐标)操作步骤&#xff0c;首先绘制两个矩形测量框&#xff1b;之后就可进行自动计算。 public void FitRectangleMeasure(…

x264 struct 学习

x264_t结构体维护着CODEC的诸多重要信息其中成员frames是一个指示和控制帧编码过程的结构。其中current是已经准备就绪可以编码的帧&#xff0c;其类型已经确定&#xff1b;next是尚未确定类型的帧&#xff1b;unused用于回收不使用的frame结构体以备今后再次使用。 structx26…