matlab 变长参数,变长参数函数的概念
分享一個2015年華為筆試知識點:變長參數函數
變長參數的函數即參數個數可變、參數類型不定 的函數。
設計一個參數個數可變、參數類型不定的函數是可能的,最常見的例子是printf函數、scanf函數和高級語言的Format函數。在C/C++中,為了通知編譯器函數的參數個數和類型是可變的(即是不定的、未知的),就必須以三個點結束該函數的聲明。
int?printf(const?char?*?_Format,?...);
int?scanf(const?char?*?_Format,?...);
int?func(int?a,int?b,...);
上面func函數的聲明指出該函數至少有兩個整型參數和緊隨其后的0個或多個類型未知的參數。在C/C++中,任何使用變長參數聲明的函數都必須至少有一個指定的參數(又稱強制參數),即至少有一個參數的類型是已知的,而不能用三個點省略所有參數的指定,且已知的指定參數必須聲明在函數最左端。
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 ):
//訪問可變參數流程
va_list?args;?//定義一個可變參數列表
va_start(args,arg);//初始化args指向強制參數arg的下一個參數;
va_arg(args,type);//獲取當前參數內容并將args指向下一個參數
...//循環獲取所有可變參數內容
va_end(args);//釋放args
含有變長參數的函數是怎么實現的呢?變長參數函數的實現其實關鍵在于怎么使用參數,指定了的參數好說,直接使用指定的參數名稱訪問,但未指定的參數呢?我們知道函數調用過程中參數傳遞是通過棧來實現的,一般調用都是從右至左的順序壓參數入棧,因此參數與參數之間是相鄰的,知道前一個參數的類型及地址,根據后一個參數的類型就可以獲取后一個參數的內容。對于變長參數函數,結合一定的條件,我們可以根據最后一個指定參數獲取之后的省略參數內容。如,對于函數func,我們知道了參數b的地址及類型,就可知道第一個可變參數的棧地址(如果有的話),如果知道第一個可變參數的類型,就可知道第一個可變參數的內容和第二個可變參數的地址(如果有的話)。以此類推,可以實現對可變參數函數的所有參數的訪問。
//sum為求和函數,其參數類型都為int,但參數個數不定
//第一個參數(強制參數)n指定后面有多少可變參數
int?sum(unsigned?int?n,...)
{
int?sum=0;
va_list?args;
va_start(args,n);
while(n>0)
{
//通過va_arg(args,int)依次獲取參數的值
sum+=va_arg(args,int);
n--;
}
va_end(args);
return?sum;
}
那么,要怎么指定上訴的“一定的條件”呢?最簡單的方法就像printf等函數一樣,使用格式化占位符。分析格式化字符串參數,通過事先定義好的格式化占位符可知可變參數的類型及個數,從而獲取各個參數內容。一般對于可變參數類型相同的函數也可直接在強制參數中指定可變參數的個數和類型,這樣也能獲取各個參數的內容。
無論哪種,都涉及對棧地址偏移的操作。結合棧存儲模式和系統數據類型的字長,我們可根據可變參數的類型很容易得到棧地址的偏移量。這里簡單介紹使用va_start、va_arg、va_end三個標準宏來實現棧地址的偏移及獲取可變參數內容。這三個宏定義在stdarg.h頭文件中,他們可根據預先定義的系統平臺自動獲取相應平臺上各個數據類型的偏移量。
//?ConsoleApplication13.cpp?:?定義控制臺應用程序的入口點。
//
#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);
}
運行結果:
對于可變參數函數的調用有一點需要注意,實際的可變參數的個數必須比前面強制參數中指定的個數要多,或者不小于,也即后續參數多一點不要緊,但不能少,如果少了則會訪問到函數參數以外的堆棧區域,這可能會把程序搞崩掉。前面強制參數中指定的類型和后面實際參數的類型不匹配也有可能造成程序崩潰。
擁有變長參數的函數在聲明定義時其參數個數與類型是不定的,在運行調用時參數的狀態則是一定的。而默認參數函數在聲明定義時其參數類型與個數都是一定的,只是后面部分參數指定了默認值,可通過省略(不指定)部分參數調用這個默認參數函數。但是默認參數函數還是使用了聲明中指定的全部參數,只不過編譯器做了個順水人情,自動給后部分參數賦了默認值;而變長參數函數則僅僅使用了運行調用時提供的參數。
在matlab中這一概念是如何體現的呢?
matlab中varargin簡介
varargin可以看做“Variable length input argument list”的縮寫。在matlab中, varargin提供了一種函數可變參數列表機制。 就是說, 使用了“可變參數列表機制”的函數允許調用者調用該函數時根據需要來改變輸入參數的個數。
matlab中很多內建函數和工具箱函數都使用了這種機制。 比如圖像處理工具箱中的imshow函數。 該函數允許我們根據圖像數據特點來調用:
比如, 顯示一張真彩色位圖, 我們可以簡單的使用:
imshow(RGB), 其中RGB是通過imread函數讀取圖像獲得的圖像數據。這里我們只給了一個參數。
但是在顯示索引圖像時, 因為索引圖像使用了調色板,因此為了正確顯示圖像, 除了圖像數據外, 我們還要額外指定顯示圖像所使用的調色板(一般也由imread函數獲得),這樣就出現了以下的調用格式:
imshow(X, map)
那么, 這種機制是怎么實現的呢? 借助于varargin。
相關: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
這里定義了一個函數, 利用了可變參數列表。然后我們這樣調用這個函數:
>> 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的二維矩陣, 這個矩陣即我們調用這個函數時傳入的參數列表。
通過size(varargin, 2)獲得的varargin第二維的尺寸(即varargin的列數)就是我們傳入的參數個數。
stdargin =nargin- optargin;這一句是獲取可變參數列表從第幾個參數開始的。 其中,nargin也是matlab中的, 不能拼錯了, nargin的
值即傳入的所有參數個數。
也許你會問, 咦? 這不就是size(varargin, 2)嗎?
對于本例,的確這樣子。
但是有的函數,參數列表是這樣的:
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
這次我們調用:
>> vartest_2(1, 2, 3)
Number of inputs: 3
Inputs from individual arguments: 2
1: 3
你會看到, 由于vartest_2的第一二個參數不是可變參數列表的一部分, 可變參數列表從第三個參數開始。因此
nargin等于3, 而size(varargin, 2) 等于1。
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的matlab 变长参数,变长参数函数的概念的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: php基础标签大全,HTML基础之HTM
- 下一篇: php模型分页代码,ThinkPHP6.