matlab 变长参数,变长参数函数的概念
分享一個2015年華為筆試知識點:變長參數(shù)函數(shù)
變長參數(shù)的函數(shù)即參數(shù)個數(shù)可變、參數(shù)類型不定 的函數(shù)。
設(shè)計一個參數(shù)個數(shù)可變、參數(shù)類型不定的函數(shù)是可能的,最常見的例子是printf函數(shù)、scanf函數(shù)和高級語言的Format函數(shù)。在C/C++中,為了通知編譯器函數(shù)的參數(shù)個數(shù)和類型是可變的(即是不定的、未知的),就必須以三個點結(jié)束該函數(shù)的聲明。
int?printf(const?char?*?_Format,?...);
int?scanf(const?char?*?_Format,?...);
int?func(int?a,int?b,...);
上面func函數(shù)的聲明指出該函數(shù)至少有兩個整型參數(shù)和緊隨其后的0個或多個類型未知的參數(shù)。在C/C++中,任何使用變長參數(shù)聲明的函數(shù)都必須至少有一個指定的參數(shù)(又稱強制參數(shù)),即至少有一個參數(shù)的類型是已知的,而不能用三個點省略所有參數(shù)的指定,且已知的指定參數(shù)必須聲明在函數(shù)最左端。
int?func(...);//wrong
int?func(...,int?a);//wrong
Variadic functions are functions (e.g. std::printf) which take a variable number of arguments.
To declare a variadic function, an ellipsis is used as the last parameter, e.g. int printf(const char* format, ...);. See Variadic arguments for additional detail on the syntax, automatic argument conversions and the alternatives.
To access the variadic arguments from the function body, the following library facilities are provided(Defined in header ):
//訪問可變參數(shù)流程
va_list?args;?//定義一個可變參數(shù)列表
va_start(args,arg);//初始化args指向強制參數(shù)arg的下一個參數(shù);
va_arg(args,type);//獲取當前參數(shù)內(nèi)容并將args指向下一個參數(shù)
...//循環(huán)獲取所有可變參數(shù)內(nèi)容
va_end(args);//釋放args
含有變長參數(shù)的函數(shù)是怎么實現(xiàn)的呢?變長參數(shù)函數(shù)的實現(xiàn)其實關(guān)鍵在于怎么使用參數(shù),指定了的參數(shù)好說,直接使用指定的參數(shù)名稱訪問,但未指定的參數(shù)呢?我們知道函數(shù)調(diào)用過程中參數(shù)傳遞是通過棧來實現(xiàn)的,一般調(diào)用都是從右至左的順序壓參數(shù)入棧,因此參數(shù)與參數(shù)之間是相鄰的,知道前一個參數(shù)的類型及地址,根據(jù)后一個參數(shù)的類型就可以獲取后一個參數(shù)的內(nèi)容。對于變長參數(shù)函數(shù),結(jié)合一定的條件,我們可以根據(jù)最后一個指定參數(shù)獲取之后的省略參數(shù)內(nèi)容。如,對于函數(shù)func,我們知道了參數(shù)b的地址及類型,就可知道第一個可變參數(shù)的棧地址(如果有的話),如果知道第一個可變參數(shù)的類型,就可知道第一個可變參數(shù)的內(nèi)容和第二個可變參數(shù)的地址(如果有的話)。以此類推,可以實現(xiàn)對可變參數(shù)函數(shù)的所有參數(shù)的訪問。
//sum為求和函數(shù),其參數(shù)類型都為int,但參數(shù)個數(shù)不定
//第一個參數(shù)(強制參數(shù))n指定后面有多少可變參數(shù)
int?sum(unsigned?int?n,...)
{
int?sum=0;
va_list?args;
va_start(args,n);
while(n>0)
{
//通過va_arg(args,int)依次獲取參數(shù)的值
sum+=va_arg(args,int);
n--;
}
va_end(args);
return?sum;
}
那么,要怎么指定上訴的“一定的條件”呢?最簡單的方法就像printf等函數(shù)一樣,使用格式化占位符。分析格式化字符串參數(shù),通過事先定義好的格式化占位符可知可變參數(shù)的類型及個數(shù),從而獲取各個參數(shù)內(nèi)容。一般對于可變參數(shù)類型相同的函數(shù)也可直接在強制參數(shù)中指定可變參數(shù)的個數(shù)和類型,這樣也能獲取各個參數(shù)的內(nèi)容。
無論哪種,都涉及對棧地址偏移的操作。結(jié)合棧存儲模式和系統(tǒng)數(shù)據(jù)類型的字長,我們可根據(jù)可變參數(shù)的類型很容易得到棧地址的偏移量。這里簡單介紹使用va_start、va_arg、va_end三個標準宏來實現(xiàn)棧地址的偏移及獲取可變參數(shù)內(nèi)容。這三個宏定義在stdarg.h頭文件中,他們可根據(jù)預(yù)先定義的系統(tǒng)平臺自動獲取相應(yīng)平臺上各個數(shù)據(jù)類型的偏移量。
//?ConsoleApplication13.cpp?:?定義控制臺應(yīng)用程序的入口點。
//
#include?"stdafx.h"
#include?
#include?
void?simple_printf(const?char*?fmt...)
{
va_list?args;
va_start(args,?fmt);
while?(*fmt?!=?'\0')?{
if?(*fmt?==?'d')?{
int?i?=?va_arg(args,?int);
std::cout?<
}
else?if(*fmt=='c')
{
int?c?=?va_arg(args,?int);
std::cout?<(c)?<
}
else?if?(*fmt?==?'f')?{
double?d?=?va_arg(args,?double);
std::cout?<
}
++fmt;
}
va_end(args);
}
int?main()
{
simple_printf("dcff",3,'a',1.999,42.5);
}
運行結(jié)果:
對于可變參數(shù)函數(shù)的調(diào)用有一點需要注意,實際的可變參數(shù)的個數(shù)必須比前面強制參數(shù)中指定的個數(shù)要多,或者不小于,也即后續(xù)參數(shù)多一點不要緊,但不能少,如果少了則會訪問到函數(shù)參數(shù)以外的堆棧區(qū)域,這可能會把程序搞崩掉。前面強制參數(shù)中指定的類型和后面實際參數(shù)的類型不匹配也有可能造成程序崩潰。
擁有變長參數(shù)的函數(shù)在聲明定義時其參數(shù)個數(shù)與類型是不定的,在運行調(diào)用時參數(shù)的狀態(tài)則是一定的。而默認參數(shù)函數(shù)在聲明定義時其參數(shù)類型與個數(shù)都是一定的,只是后面部分參數(shù)指定了默認值,可通過省略(不指定)部分參數(shù)調(diào)用這個默認參數(shù)函數(shù)。但是默認參數(shù)函數(shù)還是使用了聲明中指定的全部參數(shù),只不過編譯器做了個順水人情,自動給后部分參數(shù)賦了默認值;而變長參數(shù)函數(shù)則僅僅使用了運行調(diào)用時提供的參數(shù)。
在matlab中這一概念是如何體現(xiàn)的呢?
matlab中varargin簡介
varargin可以看做“Variable length input argument list”的縮寫。在matlab中, varargin提供了一種函數(shù)可變參數(shù)列表機制。 就是說, 使用了“可變參數(shù)列表機制”的函數(shù)允許調(diào)用者調(diào)用該函數(shù)時根據(jù)需要來改變輸入?yún)?shù)的個數(shù)。
matlab中很多內(nèi)建函數(shù)和工具箱函數(shù)都使用了這種機制。 比如圖像處理工具箱中的imshow函數(shù)。 該函數(shù)允許我們根據(jù)圖像數(shù)據(jù)特點來調(diào)用:
比如, 顯示一張真彩色位圖, 我們可以簡單的使用:
imshow(RGB), 其中RGB是通過imread函數(shù)讀取圖像獲得的圖像數(shù)據(jù)。這里我們只給了一個參數(shù)。
但是在顯示索引圖像時, 因為索引圖像使用了調(diào)色板,因此為了正確顯示圖像, 除了圖像數(shù)據(jù)外, 我們還要額外指定顯示圖像所使用的調(diào)色板(一般也由imread函數(shù)獲得),這樣就出現(xiàn)了以下的調(diào)用格式:
imshow(X, map)
那么, 這種機制是怎么實現(xiàn)的呢? 借助于varargin。
相關(guān):varargout、nargin
下面我們來看一個簡單的例子,(本例子參考了matlab中varargin文檔)
function retvar = vartest(varargin)
optargin = size(varargin, 2); % number of inputs.
ndims(varargin)
varargin
stdargin =nargin- optargin; % 'nargin' in matlab means number of input arguments.
fprintf('Number of inputs: %d\n',nargin);
fprintf('Inputs from individual arguments: %d\n', stdargin)
for k = 1:size(varargin, 2)
fprintf('%d: %d\n', k, varargin{k});
end
end
這里定義了一個函數(shù), 利用了可變參數(shù)列表。然后我們這樣調(diào)用這個函數(shù):
>> vartest(1, 2, 3)
ans = 2
varargin =
[1] [2] [3]
Number of inputs: 3
Inputs from individual arguments: 0
1: 1
2: 2
3: 3
我們看到, 這里varargin是一個1*3的二維矩陣, 這個矩陣即我們調(diào)用這個函數(shù)時傳入的參數(shù)列表。
通過size(varargin, 2)獲得的varargin第二維的尺寸(即varargin的列數(shù))就是我們傳入的參數(shù)個數(shù)。
stdargin =nargin- optargin;這一句是獲取可變參數(shù)列表從第幾個參數(shù)開始的。 其中,nargin也是matlab中的, 不能拼錯了, nargin的
值即傳入的所有參數(shù)個數(shù)。
也許你會問, 咦? 這不就是size(varargin, 2)嗎?
對于本例,的確這樣子。
但是有的函數(shù),參數(shù)列表是這樣的:
function vartest_2(arg1, argb, varargin)
optargin = size(varargin, 2); % number of inputs.
stdargin =nargin- optargin; % 'nargin' in matlab means number of input arguments.
fprintf('Number of inputs: %d\n',nargin);
fprintf('Inputs from individual arguments: %d\n', stdargin)
for k = 1:size(varargin, 2)
fprintf('%d: %d\n', k, varargin{k});
end
end
這次我們調(diào)用:
>> vartest_2(1, 2, 3)
Number of inputs: 3
Inputs from individual arguments: 2
1: 3
你會看到, 由于vartest_2的第一二個參數(shù)不是可變參數(shù)列表的一部分, 可變參數(shù)列表從第三個參數(shù)開始。因此
nargin等于3, 而size(varargin, 2) 等于1。
與50位技術(shù)專家面對面20年技術(shù)見證,附贈技術(shù)全景圖總結(jié)
以上是生活随笔為你收集整理的matlab 变长参数,变长参数函数的概念的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: php基础标签大全,HTML基础之HTM
- 下一篇: matlab人脸追踪,求大神帮助我这个菜