You are on page 1of 13

第十七章

M 檔案

本章重點

以 MATLAB 程式碼所撰寫的檔案通常以「m」為
副檔名,所以這些檔案又稱為「M 檔案」( M-
files)。M 檔案又分兩類:

l 底稿(Scripts)

l 函式(Functions)

本章將對這兩類 M 檔案作一詳細介紹。
第一章

MATLAB 程式設計與應用

17-1 底稿

簡單地說,底稿(Scripts)即是一個副檔名為 m 的檔案,其內包含了
MATLAB 的各種指令,我們可以在 MATLAB 指令視窗下直接輸入此
檔案的主檔名,MATLAB 即可逐一執行在此檔案內的所有指令,就彷
彿我們在 MATLAB 指令視窗逐列輸入這些指令一般。例如:假設在
目前目錄下有一個M檔案「script1.m」,我們可用 type 指令顯示其內
容,如下:

>> type script1.m


clear all %清除所有變數
x = [1 4 -2 3 -1 -5];
for i = 1:length(x),
if x(i)>0,
fprintf('x(%g) = %g is positive\n', i, x(i));
else
fprintf('x(%g) = %g is negative or zero\n', i, x(i));
end
end

欲執行 script1.m,直接在 MATLAB 指令視窗下輸入 script1 即可:

>> script1
x(1) = 1 is positive
x(2) = 4 is positive
x(3) = -2 is negative or zero
x(4) = 3 is positive
x(5) = -1 is negative or zero
x(6) = -5 is negative or zero

執行此程式底稿的效應,相當直接在 MATLAB 指令視窗下直接下達


script1.m 裡的每一列指令,所產生的變數也都存放在 MATLAB 的基
本工作空間(Base Workspace),可驗證如下:

17-2
MATLAB系列叢書Œ
Chapter 17 M檔案

>> whos
Name Size Bytes Class

i 1x1 8 double array


x 1x6 48 double array

Grand total is 7 elements using 56 bytes

提示:
8 您也可在一函式中呼叫一程式底稿,此時所產生的變數即會放在該函式的工作
空間中。

程式底稿最適用於對付簡單但重複性高的程式碼,但他並不支援輸入
及輸出引數(Input/Output Arguments),而且由於所產生的變數均出
現在基本工作空間,容易造成變數的互相覆蓋而造成程式錯誤的產
生。欲改良這些底稿的缺點,可改用函式,將在下節介紹。

然而,底稿也有他的優點:由於所產生的變數均保留在基本工作空間
中,所以很容易進行變數檢視及除錯。

M 檔案是一個文字檔,所以您可以用各種文字編輯器去修改他,但記
得 在 儲 存 檔 案 時 , 必 需 以 文 字 模 式 儲 存 。 此 外 , MATLAB 在
Win95/98/NT 及 Mac 的平台上,亦提供了一個內建的 M 檔案編輯器
(M-File Editor),您可以點選 MATLAB 指令視窗的 file/open 下拉式
選單,來開啟 M 檔案編輯器,另一種更快的方法,則是在 MATLAB 指
令視窗只接鍵入「edit filename.m」 或是「open filename.m」。例如 ,
欲開啟 Script1.m,可輸入如下:

>> edit script1.m

此時即可開啟 M 檔案編輯器:

17-3
清 蔚 出 版
第一章

MATLAB 程式設計與應用

M 檔案編輯器會以不同的顏色來顯示註解、關鍵字、字串、及一般程
式碼,在使用上相當方便。

提示:
8 事實上,M 檔案編輯器也是一個除錯器(Debugger),欲使用其除錯功能,
可詳見本書第十九章「程式偵錯」。

17-2 函式

函式(Functions)也是 M 檔案的一種,他可以接受輸入變數,並將運
算結果送至輸出變數,運算過程所產生的變數都存放在函式本身的工
作空間,並不會和 MATLAB 基本工作空間的變數相互覆蓋。因此,

17-4
MATLAB系列叢書Œ
Chapter 17 M檔案

函式特別適用於大型程式碼,他會使您的程式碼模組化
(Modularized)並易於維護與改進。

舉例來說,func1.m 就是筆者所撰寫的一個小函式,他的功能是算出
一向量的平均值,我們可用 type 指令顯示其內容:

>> type func1.m


function average = func1(vector)
average = sum(vector)/length(vector); % 計算平均值

此函式的第一列為函式定義列(Function Definition Line),定義了此


函式的名稱(即func1,最好和檔案的主檔名相同)、輸入引數(即
vector)、輸出引數(即 average),而function則為關鍵字,代表此M
檔案為一函式。第二列則為函式主體(Function Body),規範函式的
運算過程,並指定輸出引數的值。欲呼叫此函式,可輸入如下:

>> vec = [1 5 3];


>> ave = func1(vec)
ave =
3

欲加上函式的線上輔助說明(On-line Help),可在函式定義列下直接
加入註解,例如在函式 func2.m,我們已加上了線上輔助說明::

>> type func2.m


function average = func(vector)
% FUNC2 A simple function with a single help line.
%
% Usage of this function:
% output = func2(input)
% "output" is the average of the input vector "input".

% Roger Jang, 19991123.

average = sum(vector)/length(vector); % 計算平均值

17-5
清 蔚 出 版
第一章

MATLAB 程式設計與應用

在函式定義列之後的連續註解(以「%」開頭),即為函式的線上輔
助說明,若在 MATLAB 輸入「help 函式主檔名」,即可看到這些輔
助說明,例如:

>> help func2


FUNC2 A simple function with a single help line.

Usage of this function:


output = func2(input)
"output" is the average of the input vector "input".

因此,您可以將所有有關此函式的說明,包含用法、演算法、參考資
料、最後修改日期、作者等,全部寫入線上輔助說明,以利使用者(可
能就是您自己)查看。

提示:
8 在上例中,「Roger Jang, 19991023」並未呈現在 func2 的函式的線上輔助
說明,這使因為此列和前面的註解已分離,並不屬於「連續」的註解。

在一函式的線上輔助說明裡,最重要的就是第一列,這一列又稱為「H1
輔助說明」(H1 Help),當您使用「lookfor keyword」去查詢 MATLAB
指令時,MATLAB 事實上就是以所給的關鍵字和搜尋路徑上所有的
MATLAB 函式的「H1 輔助說明」進行一一比對,以找出相關的指令。
例如:

>> lookfor 'help line'


FUNC2 A simple function with a single help line.

17-6
MATLAB系列叢書Œ
Chapter 17 M檔案

提示:
8 當您安裝了很多工具箱,或是您的搜尋路徑很長時,lookfor 指令的執行時間就
可能會較長。

若您有很多和某應用相關的函式,您可以將這些函式存放於一子目錄
內,並將此目錄加入搜尋路徑,使 MATLAB 在任何目錄內,均可執
行此目錄內的函式。 欲加入路徑,可用 addpath 指令,欲移除路徑,
可用rmpath指令,在此不在贅述。此外,您也可以建立一目錄的線上
輔助說明,只需在此目錄下加入一特定檔案「 Contents.m」,此檔案
只能包含輔助說明文字,同時每列均需以「%」開頭,MATLAB 會在
您輸入「help 目錄名稱」時,顯示在「目錄名稱」下的 Contents.m 的
輔助說明。

MATLAB 的函式名稱和變數名稱都有相同的限制:只接受前 31個字


母,而且必需以英文字母作為開頭。此外,當檔案名稱和函式名稱不
同時,我們仍可依檔案名稱呼叫檔案,函式名稱將被忽略。

一個函式可以有多輸入及輸出,例如:func3.m 可接受兩個輸入並產
生兩個輸出,這兩個輸出分別是兩個輸入向量的平均值,其程式碼可
顯示如下:

>> type func3.m


function [ave1, ave2] = func3(vector1, vector2);
ave1 = sum(vector1)/length(vector1);
ave2 = sum(vector2)/length(vector2);

func3.m 的典型呼叫方式如下:

>> [a, b] = func3([1 2 3], [4 5 6 7 8])


a =
2
b =
6

17-7
清 蔚 出 版
第一章

MATLAB 程式設計與應用

此外,在一函式中,我們可用內建變數 vargin 及 vargout 來決定此函


式的實際輸入和輸出變數的個數,其主要功能為:

l 設定未被指定之輸入引數的預設值。
l 避免計算未被用到的輸出引數,以節省計算時間。

例如:上述函式 func3.m 可改寫成 func4.m,其內容如下:

>> type func4.m


function [ave1, ave2] = func3(vector1, vector2);

if nargin == 1, % 只有一個輸入變數
ave1 = sum(vector1)/length(vector1);
end

if nargout == 2, % 有兩個輸出變數
ave1 = sum(vector1)/length(vector1);
ave2 = sum(vector2)/length(vector2);
end

此時 func4.m 就可以接受一個或兩個輸入變數:

>> [a, b] = func4([1 2 3], [4 5 6 7 8])


a =
2
b =
6
>> c = func4([1 3 5 7 9])
c =
5

MATLAB 的函式亦可傳送不定數目的輸入引數和輸出引數,但由於實
際應用機會不多,故在此不再贅述,有興趣的讀者,可參考 varagin 和
varagout 的線上輔助說明。

17-8
MATLAB系列叢書Œ
Chapter 17 M檔案

提示:
8 從外表上來看,MATLAB 函式的變數傳遞方法是所謂的“Call by Value”,
亦 即 在 函 式 的 工 作 空 間 中 , 所 有 的 輸 入 變 數 均 是 父 工 作 空 間 ( Parent
W orkspace)的一份拷貝本,因此在函式中更改這些輸入變數,並不會影響原
先父工作空間的變數。在實際運作上,若輸入變數未被修改,則 MATLAB 採
用“Call by Reference”,否則,則採用“Call by Value”。
8 要在函式內知道此函式的檔案名稱,可用「mfilename」指令。
8 要在函式內知道此函式的輸入變數名稱,可用「inputname」指令。

17-3 次函式與私有化目錄

一個 M 檔案可以包含一個以上的函式,其中有一個主函式(Primary
Function),其他則為次函式(Subfunctions),這些次函式只能被同
檔案中的函式(可能是主函式或次函式)呼叫,但不可被不同檔案的
其他函式呼叫。在一個 M 檔案中,主函式必需出現在最上方,其後即
可接上任意數目的次函式,而且次函式的次序並無任何限制。例如:
func5.m 包含一個主函式及一個次函式,次函式的功能是計算倒數向
量,此 M 檔案的內容可顯示如下:

>> type func5.m


function out = func5(x)
recip = reciproc(x);
out = sum(recip);

% Definition for subfunctions


function output = reciproc(input)
output = 1./input;

17-9
清 蔚 出 版
第一章

MATLAB 程式設計與應用

此函式可呼叫如下:

>> func5([1 2 3])


ans =
1.8333

此外,您可以在一目錄中建立一個名稱為「private」的私有化目錄
(Private Directory),來存放與這目錄相關的函式。例如,假設您有
一個目錄 mydir,您可以在 mydir 之下建立一個名為 private 的目錄,
那麼 mydir 中的 M 檔案(無論底稿或函式)即可呼叫 private 之下的任
何函式,而不必再定義其他搜尋路徑。在目錄 private 之下的函式,只
能被其父目錄的函式所呼叫,而不能被其他目錄的函式來呼叫。

當您從 M 檔案呼叫一個函式時,MATLAB 搜尋此函式的次序如下:

l 檢查此函式是否為次函式
l 檢查此函式是否為私有化目錄的函式
l 從所設定的搜尋路徑找尋此函式

在此搜尋過程中,MATLAB 只要找到第一個檔名相符的函式,即會
立即取用,而不再繼續搜尋。

17-4 區域變數與全域變數

每一個函 式在運算 時,均佔 用個別的 一塊記憶 體,此工 作空間 和


MATLAB 的基本工作空間或是其他函式的工作空間是互相獨立的,因
此不同空間的變數是完全獨立,不會相互影響。這些在不同工作空間
的變數,稱為區域變數(Local Variables)。一般而言,使用區域變數
已能滿足一般程式設計的需求,但有時候為了減少變數的傳遞,我們
可用全域變數(Global Variables),在使用全域變數之前,我們必需
先進行變數宣告,其格式如下:

global variable1 variable2 ...

17-10
MATLAB系列叢書Œ
Chapter 17 M檔案

例如:我們在函式 func6.m 宣告了一個全域變數 X,並印出其值,


Func6.m 的內容如下:

>> type func6.m


function func6
global X % 全域變數宣告
X = X + 2;
fprintf('The value of X in "func6" is %g.\n', X);

此函式沒有輸出和輸入,他只是宣告全域變數 X,將 X 的值加 2,並


印出其值。欲測試此函式,可輸入如下:

>> global X % 在基本工作空間進行全域變數 x 的宣告


>> X = 2;
>> fprintf('The value of X in the base workspace is %g.\n', X);
The value of X in the base workspace is 2.

>> func6;
The value of X in "func6" is 4.

>> fprintf('The value of X in the base workspace is %g.\n', X);


The value of X in the base workspace is 4.

由此可知,一旦 X 被宣告為全域變數後,就可以在不同的空間中,存
取或改變同一個全域變數 X 的值。

必需注意的是:請盡量少用全域變數!全域變數會使程式的流程較不
透明,造成程式偵錯或維護的困難。若您一定要用全域變數,請遵循
下列兩原則:

l 在使用前一定要宣告。
l 使用全部大寫,或是較長的變數名稱,以資區別。

另外,在檢視工作空間的變數時,需輸入 whos global,才能顯示全域


變數,例如:

17-11
清 蔚 出 版
第一章

MATLAB 程式設計與應用

>> whos global


Name Size Bytes Class

X 1x1 8 double array (global)

Grand total is 1 elements using 8 bytes

在清除變數時,clear X 只會清除在目前工作空間的全域變數 X,若要


清除所有工作空間的全域變數 X,則必需使用 clear global X。

17-5 程式碼保護:p-code

一般的 M 檔案都是文字檔,因此所有的 MATLAB 原始程式碼都看得


到,若您想要讓別人使用您的程式碼,但卻又不想讓別人看到程式碼
的內容,哪麼就可以使用 pcode 指令將底稿或函式轉成 p-code(即
Pseudo-Code),其格式如下:

pcode filename.m

例如,我們可將函式 func5.m 轉成 p-code:

>> pcode func5.m


>> dir *.p
func5.p

此時檢視 func5 的來源,MATLAB 會以 p-code 的程式碼為優先:

>> which func5


d:\mlbook\examples\func5.p

呼叫 p-code 的函式和一般函式並無兩樣:

17-12
MATLAB系列叢書Œ
Chapter 17 M檔案

>> func5([2 4 8])


ans =
0.8750

除了保護智慧財產權外,pcode 指令的另一個功能是可以提高程式的
效率。當一函式被呼叫時,MATLAB 會載入並剖析(Parse)此函式,
並將剖析結果存放置在記憶體內,因此當下次再呼叫此函式時,就可
以省下剖析所花的時間。pcode 的作用即是將程式碼以剖析後的結果
來儲存,因此如果您的程式碼牽涉到很多 M 檔案時(例如大型的圖形
使用者介面應用程式)
,即可使用 pcode 指令來將程式碼轉成 p-code,
以節省剖析的時間。(由於 MATLAB 花在函式載入及剖析的時間相
當少,因此如果您的程式碼不牽涉到很多 M 檔案,大可不用 pcode 指
令。)

17-13
清 蔚 出 版

You might also like