函數參數的傳遞問題(一級指針和二級指針)

函數參數的傳遞問題(一級指針和二級指針)?[轉]

原以為自己對指針掌握了,卻還是對這個問題不太明白。請教!??
程序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.pswp.cn/news/254701.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/254701.shtml
英文地址,請注明出處:http://en.pswp.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…