这一章在干嘛?
前两章你只在「命令行」里和 MATLAB 一问一答地算题。第 3 章开始把多行命令保存成 脚本(script),让程序能反复跑、能从键盘和文件读数据、能画带标签的图,最后写出第一个自己定义的 函数(function)。整个第 6 章会展开,这里只挑最常用的一小块。学完这章,你能把「算圆的面积」从一行交互式命令升级成「输入半径 → 算出面积 → 输出完整句子」的可重用程序。
3.1 算法与脚本:先把思路画出来
关键词
算法(algorithm)、自顶向下设计(top-down design)、模块化程序(modular program)
写代码之前,先把要做什么、做到什么程度、按什么顺序做,写成一步一步的描述——这就是「算法」。原书把「算圆的面积」拆成三步:
- 输入(input):拿到半径。
- 计算(calculate):面积 = π × 半径²。
- 输出(output):把结果打印给用户。

图 3.1:MATLAB 编辑器界面
上方是 HOME 工具栏(左侧的「New Script」就是新建脚本的入口),左下角是 Current Folder(当前文件夹),下面就是 Editor(编辑器)。脚本文件必须保存在「当前文件夹」里,MATLAB 才能直接用文件名运行它,不必写完整路径。
这三步对几乎所有程序都适用。即使算法这么简单,每一步还能继续往下拆——比如「输入」就要再拆成「提示用户输入」和「把用户输入读进来」。这就是自顶向下设计:从粗到细、层层拆解,直到每一步都小到能直接写代码。
为什么不在编辑器里直接写代码?
因为写程序 = 把脑子里「怎么算」的思路翻译成「怎么写」的两件事。如果一上来就敲代码、边写边想思路,思路会被零碎的语言细节带跑。养成「先列步骤、再敲代码」的习惯,能在第 5 章之后遇到更难的题时省下大量返工时间。
3.2 MATLAB 脚本:把命令存到文件里
MATLAB 用 脚本文件(.m 文件) 保存一段命令序列。.m 是 MATLAB 默认的文件后缀,俗称「M 文件」。在编辑器里输入下面这段,保存为 script1.m:
% 文件:script1.m
% 计算一个圆的面积
radius = 5
area = pi * (radius ^ 2)保存后,命令行敲 script1(不带 .m)就能运行:
>> script1
radius =
5
area =
78.5398也可以先用 type script1 让 MATLAB 在命令行把文件内容回显出来,再确认要不要执行。修改文件就双击 Current Folder 里的文件名——编辑器和命令行是双向打通的。
3.2.1 注释与 help 命令
% 在 MATLAB 里表示「单行注释(comment)」,从 % 到行尾的所有字符在运行时被完全忽略。注释是给读代码的人看的,机器看不见。
「 H1 行(H1 line)」:文件第一行连续的注释块,是
help 文件名唯一会显示的内容。lookfor命令也只在 H1 行里搜索关键字,所以这一行要写成一句话的功能描述。
% 文件:circlescript.m
% This script calculates the area of a circle
% First the radius is assigned
radius = 5
% The area is calculated based on the radius
area = pi * (radius ^ 2)>> help circlescript
This script calculates the area of a circle注意 help 只显示了第一行——第二行因为前面有空行隔开,被认为不属于「连续的注释块」了。需要更长的多行注释,用 %{ ... %}(注释块,comment block),两个标记必须各自独占一行:
%{
本块用于长注释
可以写很多行
直到遇到配对的 %}
%}常见坑:函数体里忘了写分号
脚本里的赋值语句如果不加分号,每次运行都会把中间结果「喧哗」地打印出来,干扰最终输出。所以函数和脚本里的赋值语句几乎永远要加分号;打印交给专门的
disp或fprintf来做。
3.2.2 文件名的命名规则
.m 文件名必须遵守 MATLAB 变量名规则:以字母开头,后面只能跟字母、数字、下划线,不能有空格、连字符或中文。和变量一样,MATLAB 大小写敏感:Script1.m 和 script1.m 是两个完全不同的文件。养成「全程小写 + 下划线分隔单词」的好习惯,例如 circle_io.m 比 CircleIO.m 更耐看。
3.3 输入与输出:让脚本与人对话
光会算不行,还得能接受输入、产生输出,这就是 I/O(input/output)。MATLAB 默认的输入设备是键盘,默认的输出设备是屏幕。
3.3.1 input:键盘录入
input 把用户在命令行敲的内容读成 MATLAB 的变量。最简单的用法是读一个数:
>> rad = input('Enter the radius: ')
Enter the radius: 5
rad =
5如果想让用户输入字符串而不是表达式,必须加第二个参数 's'(意思是 “string”):
>> letter = input('Enter a char: ', 's')
Enter a char: g
letter =
'g'常见坑:
input('prompt', 's')与裸input的本质区别
- 不加
's'时,MATLAB 把用户输入当作 MATLAB 表达式:输入5得到数 5,输入t会去找变量 t,输入pi得到 π。- 加
's'时,用户输入原文照搬地存成字符串,包括空格、引号都被吃进变量里。漏写
's'是初学者最常遇到的字符输入 bug。如果用户输错了,MATLAB 还会再抛一次Undefined function or variable 'xxx'错误,更让人误以为是自己代码错了。
3.3.2.1 prompt 的写法细节
提示文本末尾通常加一个冒号 + 空格(': ')再让用户敲输入,这样光标和提示语之间有一格距离,看起来不那么拥挤。教材里反复出现的 'Enter the radius: ' 就是这个习惯的典型。读向量也一样——input('Enter a vector: ') 让用户输 [3 8 22] 或 1:2:10,MATLAB 都按合法语法解析:
>> v = input('Enter a vector: ')
Enter a vector: [3 8 22]
v =
3 8 223.3.2 disp:最简单的输出
disp 是「display」的缩写,把字符串或表达式的值打到屏幕上,不会自动保存到 ans,也没有格式化能力:
>> disp('Hello')
Hello
>> disp(4^3)
64打印矩阵、向量时 disp 特别干净:
>> mat = [15 11 14; 7 10 13];
>> disp(mat)
15 11 14
7 10 133.3.3 fprintf:格式化输出
要想在输出里夹数字、控制小数位数、对齐字段,就要请出 fprintf。它和 C 语言的 printf 是同一个套路:第一个参数是格式字符串,后面是要打印的值。
>> fprintf('The value is %d, for sure!\n', 4^3)
The value is 64, for sure!
>>格式字符串里的「占位符(conversion character)」决定下一个值怎么被打印:
| 占位符 | 含义 |
|---|---|
%d | 十进制整数(decimal integer) |
%f | 浮点数(real number) |
%c | 单个字符 |
%s | 字符串 |
末尾的 \n 是「换行符(newline character)」——不写它,下一条 >> 提示符会黏在同一行末尾,特别难看。
常见坑:忘了
\n
disp会自动换行,fprintf不会。每次fprintf末尾都补一个\n,是写 MATLAB 程序的基本礼貌。
**字段宽度(field width)**让数字对齐:%5d 表示总占 5 列、%6.2f 表示总共 6 列(含小数点和 2 位小数)。宽度太窄会自动撑开:
>> fprintf('%3.2f\n', 1234.5678) % 宽度 3 不够,MATLAB 会扩成 7
1234.57更精细的格式:左对齐用 %-5d、字符串截断用 %.2s。常用转义还有 \t(制表符)、\\(打印单个反斜杠)、''(打印单个单引号,因为字符串本身是用单引号包的)。
3.3.4 打印向量和矩阵
fprintf 把向量按列优先顺序「拆开」:
>> vec = 2:5; % 2 3 4 5
>> fprintf('%d\n', vec)
2
3
4
5矩阵更明显——按列依次打印:
>> mat = [5 9 8; 4 1 10]; % 2×3
>> fprintf('%d %d %d\n', mat)
5 4 9 % 第一列两个元素横着打
1 8 10 % 第二列两个元素横着打要想保留原本「一行一行」的样子,转置一下再打:
>> fprintf('%d %d %d\n', mat')
5 9 8
4 1 10经验之谈
临时调试矩阵用
disp(mat);要写文件、固定位数才用fprintf。
3.3.5 在 prompt 里用换行
input 的提示字符串里可以塞 \n 实现换行——这是唯一一个被 input 接受的格式字符,其它 %d、\t 都会被原样打印:
>> x = input('Enter the \nx coordinate: ');
Enter the
x coordinate: 43.3.6 vsprintf 家族:fprintf 的两个近亲
除了 fprintf(打印到屏幕或文件),MATLAB 还提供两个不常被提到但用起来很顺手的姊妹:
sprintf:把格式化结果塞回一个字符串变量,不打印任何东西。常用于生成文件名、拼接 SQL、构造图表标题。disp:不接受格式串,但会自动在末尾加换行、且不会污染ans,适合一次性把矩阵或字符串怼到屏幕上。
举例感受一下:
>> s = sprintf('Result = %.3f', sqrt(2));
>> s
s = 'Result = 1.414'
>> disp(['Hello, ' 'world']) % disp 接受字符串拼接
Hello, world3.4 完整的 I/O 脚本示例
把上面所有东西拼起来,就是一个真正有用的脚本 circleIO.m:
% 文件:circleIO.m
% 这个脚本计算并打印一个圆的面积
% 它会向用户询问半径,然后输出包含单位和说明的完整句子
fprintf('Note: the units will be inches.\n')
radius = input('Please enter the radius: ');
area = pi * (radius^2);
% 按句子格式打印所有变量
fprintf('For a circle with a radius of %.2f inches,\n', radius)
fprintf('the area is %.2f inches squared\n', area)运行一次:
>> circleIO
Note: the units will be inches.
Please enter the radius: 3.9
For a circle with a radius of 3.90 inches,
the area is 47.78 inches squared注意:每个赋值语句末尾的 ; 把中间结果压住,最终输出完全由两条 fprintf 控制——这就是「脚本控制输出格式」的范本。
常见坑:
%到底是注释还是占位符?在 MATLAB 代码行首的
%是注释;在fprintf的格式字符串内部,%d、%f里的%是占位符——这两件事毫无关系。新手看到fprintf('%d', x)时常怀疑自己写错了,其实完全正确。
3.5 用脚本画图并美化
MATLAB 自带强大的绘图能力,把多步绘图保存成脚本才是日常用法。plot(x, y, '...') 是最基础的命令:第三个参数是 LineSpec 字符串,描述颜色、线型、点型,三类属性可以自由组合。
3.5.1 颜色、线型、点型
| 类别 | 取值(单字符) |
|---|---|
| 颜色 | r 红、g 绿、b 蓝、k 黑、y 黄、m 品红、c 青、w 白 |
| 点型 | . 实点、* 星号、o 圆圈、+ 加号、x 叉号、s 方块、d 菱形、^ 上三角、v 下三角 |
| 线型 | - 实线、: 点线、-. 点划线、-- 虚线,不写则只画点 |
例如 'r*' 表示「红色星号」,'ko' 表示「黑色圆圈」。
3.5.2 第一个画图脚本:单点
% 文件:plotonepoint.m
% 一个非常简单的「只画一个点」的脚本
% 创建坐标,画一颗红星
x = 11; y = 48;
plot(x, y, 'r*')
% 改坐标轴范围并打标签
axis([9 12 35 55])
xlabel('Time')
ylabel('Temperature')
% 加标题
title('Time and Temp')axis([xmin xmax ymin ymax]) 一次性设置坐标范围,默认坐标轴没有任何标签,所以 xlabel、ylabel、title 三件套是标配。

图 3.2:用 plot 画出的一个点
注意坐标轴是
axis([9 12 35 55])手动指定的,否则 MATLAB 会按数据范围自动收缩,第一/最后点会贴在边框上看不清。
3.5.3 折线图:传两个等长向量
>> x = 1:6;
>> y = [1 5 3 9 11 8];
>> plot(x, y)
图 3.3:plot(x, y) 把两组数据点连成折线
默认没有 LineSpec 时画的是「实线连接的折线」,坐标轴范围是数据范围自动算出来的。如果
x就是1:n,可以直接plot(y),MATLAB 会用索引当 x 轴。
3.5.4 多图与图例
下面这个脚本一次开两个 Figure,第一个放柱状图,第二个把两条曲线叠在一起,并加网格和图例:
% 文件:plot2figs.m
% 演示多窗口、hold、legend、grid
clf
x = 1:5;
y1 = [2 11 6 9 3];
y2 = [4 5 8 6 2];
% Figure 1:柱状图
figure(1)
bar(x, y1)
% Figure 2:两条曲线叠在一起
figure(2)
plot(x, y1, 'k')
hold on
plot(x, y2, 'ko')
grid on
legend('y1', 'y2')
图 3.4 (A):bar 函数画柱状图
bar(x, y1)是柱状图的标配,barh是横过来的柱状图。

图 3.4 (B):hold on 把两条曲线叠在同一坐标系
hold是「冻结」切换开关:hold on之后再plot,新曲线叠在旧曲线上而不替换;hold off关闭。legend按plot的调用顺序把字符串和曲线配对,grid加底纹。
3.5.5 画图脚本里其它常用小函数
除了 plot,脚本里还经常配合下面几个帮手:
clf:清空当前 Figure 窗口的所有内容,从头再来。figure(n):打开编号为 n 的 Figure(不存在就创建)。多窗口并存时用figure(1)、figure(2)切换。hold on/off:冻结/解冻当前图,新plot是否叠加。legend('A','B', ...):在角落加图例框,字符串顺序必须对应 plot 调用顺序。grid on/off:开关网格线。bar(x, y):柱状图;barh是横向版本。axis([xmin xmax ymin ymax]):硬性指定坐标范围(解决边点贴边的问题)。
画图脚本的标准范式:先准备 x、y 数据 → plot → axis 调范围 → xlabel/ylabel/title 三件套 → 有多条曲线就 legend。每幅图都按这个流程写,画出来的图就「能直接放进报告」。
把连续函数画出来更直观。MATLAB 的便利之处在于:把向量传给函数(如 sin)时,函数会对向量的每个元素分别计算——这就是所谓「向量化(vectorization)」:
% 文件:sinncos.m
% 在 [0, 2π] 范围内同时画 sin 和 cos
clf
x = 0: 2*pi/40: 2*pi;
y = sin(x);
plot(x, y, 'ro')
hold on
y = cos(x);
plot(x, y, 'b+')
legend('sin', 'cos')
xlabel('x')
ylabel('sin(x) or cos(x)')
title('sin and cos on one graph')
图 3.5:sin 与 cos 同图对比
步长
2*pi/40表示每 1/20 个周期取一个点,已经足够平滑。也可以一行写完:plot(x, sin(x), x, cos(x)),免去hold on。
3.6 文件读写:load 与 save
实际工程数据不会让人一行一行敲,最常见的是从 .dat 或 .txt 文件里读数字,或者把计算结果写出去。
3.6.1 save:把变量写入文件
>> mymat = rand(2,3)
mymat =
0.4565 0.8214 0.6154
0.0185 0.4447 0.7919
>> save testfile.dat mymat -ascii文件 testfile.dat 里写的是文本形式的数字(-ascii 强制用 ASCII),可以用 type testfile.dat 看:
4.5646767e-001 8.2140716e-001 6.1543235e-001
1.8503643e-002 4.4470336e-001 7.9193704e-001常见坑:save 默认是二进制
不带
-ascii,save 会写二进制.mat文件——人能读懂的是文本数字,机器读的是结构化数据。给同伴共享或用其他软件读时,几乎一定要-ascii。
3.6.2 -append:在文件尾追加
>> save testfile.dat mat2 -ascii -append追加写入仍然受「每行列数相同」这条潜规则约束——以后才能再 load 回矩阵。行列数不一致的数据需要第 9 章的低级 I/O 函数。
3.6.3 load:把文件读成变量
>> load testfile.dat
>> who % 列出当前工作区所有变量
Your variables are:
testfile % load 自动用「文件名(不含扩展名)」作为变量名
>> testfile
testfile =
0.4565 0.8214 0.6154
0.0185 0.4447 0.7919
0.9218 0.4057 0.4103
0.7382 0.9355 0.8936
0.1763 0.9169 0.0579如果想把读出来的数据放到指定变量名,用函数式:points = load('pointcoords.dat')。
常见坑:
load不是万能文件读取器它要求文件里每一行的元素个数完全一致,否则会按「字符串」或者乱七八糟的结构读进来。读混合类型(既有数字又有表头文字)的 CSV、读非矩形的实验记录、读带分隔符的 JSON 之类,都得用第 9 章的
fopen/fscanf/fgetl低级 I/O——load只适合规规矩矩的「数字矩阵文件」。
3.6.4 实例 —— 读温度文件并画图
假设 timetemp.dat 里两行数据:第一行是时间(小时),第二行是对应温度:
0 3 6 9 12 15 18 21
55.5 52.4 52.6 55.7 75.6 77.7 70.3 66.6下面这个脚本读入数据、按行拆成时间和温度两个向量、用 k*(黑色星号)画出散点:
% 文件:plottemp.m
% 从文件读入下午的时间和温度数据,画图
load timetemp.dat
% 第一行是时间,第二行是温度
time = timetemp(1, :);
temp = timetemp(2, :);
% 画图 + 标注
plot(time, temp, 'k*')
xlabel('Time')
ylabel('Temperature')
title('Temperatures one afternoon')
图 3.6:从文件读取并绘制的温度散点图
数据本身就是文本,直接用编辑器新建文件、键入数字、保存为
timetemp.dat即可——不必先在 MATLAB 里建矩阵再 save 出去。
更典型的应用是「两家公司、两组数据,画到同一张图上做对比」。假设 salesfigs.dat 里两行数据分别存 A、B 两个部门四个季度的销售额:
1.2 1.4 1.8 1.3
2.2 2.5 1.7 2.9下面的脚本把它读成矩阵,按行拆成两条曲线,再用不同的点型区分:
% 文件:plotsales.m
load salesfigs.dat
% 第一行是部门 A,第二行是部门 B
divA = salesfigs(1, :);
divB = salesfigs(2, :);
quarter = 1:4;
plot(quarter, divA, 'ko', quarter, divB, 'k*')
legend('Division A', 'Division B')
xlabel('Quarter')
ylabel('Sales (billions)')
title('ABC corporation sales: 2013')
图 3.7:双部门销售额散点对比
注意
plot(x, y1, 'ko', x, y2, 'k*')这种「多组数据一次画」的写法比hold on链式叠两次更紧凑,也是工业代码里最常见的范式。
文件顺序乱了怎么办?
如果文件的行序和你想要的顺序相反,
flipud(矩阵)可以把矩阵上下翻转,列顺序也跟着翻——这是处理实验数据时最常用的「数据纠错」函数:matlab correctorder = flipud(expresults); save neworder.dat correctorder -ascii
3.7 用户自定义函数:返回值的那种
到现在为止我们只用 MATLAB 自带的函数(sin、pi、length 等)。这一节学自己写函数。
关键词
函数(function)、函数头(function header)、输入参数(input argument)、输出参数(output argument)、函数体(function body)、局部变量(local variable)、作用域(scope of variables)
3.7.1 函数定义的四要素
function 输出参数 = 函数名(输入参数1, 输入参数2, ...)
% 紧贴函数头的注释块 = help 命令显示的内容
% 也叫 H1 行 + 详细说明
...函数体(计算过程)...
输出参数 = ... % 必须给输出参数赋值
end第一行(函数头)约定返回值类型、函数名和入口参数;下面紧跟注释块是 help 的输出;中间是函数体;结尾 end 收口(早期版本必须有,现在省略也能跑,但写上更稳)。
3.7.2 第一个自定义函数
把「算圆的面积」抽成函数 calcarea.m:
function area = calcarea(rad)
% calcarea calculates the area of a circle
% Format of call: calcarea(radius)
% Returns the area
area = pi * rad * rad;
end调用方式与内置函数一致:
>> calcarea(4) % 不写赋值,结果丢给 ans
ans =
50.2655
>> area = calcarea(5) % 自己接住返回值
area =
78.5398
>> mya = calcarea(5.2); % 加分号,运行时啥都不打印命名铁律: 函数名 = 文件名。
calcarea函数必须存在calcarea.m里,否则 MATLAB 会找不到或猜错同名文件。
3.7.3 函数的「副作用」—— 传向量时记得用 .*
如果传入向量而函数体里用 * 而不是 .*,会触发「矩阵乘法维数不匹配」:
>> calcarea(1:3)
Error using *
Inner matrix dimensions must agree.把 * 改成 .* 就能支持向量(元素逐个相乘):
function area = calcareaii(rad)
% calcareaii 返回一个圆的面积
% 输入参数可以是向量
% 调用格式:calcareaii(radiiVector)
area = pi * rad .* rad; % 标量 × 元素逐乘
end>> calcareaii(1:3)
ans =
3.1416 12.5664 28.27433.7.4 一个完整的「程序」= 脚本 + 函数
第 3 章专门把「脚本调用函数」叫作一个程序(program)——这是教材的术语约定,本书后文都用这层意思。下面这个 circleCallFn.m 调用 calcarea.m,两个文件必须放在同一当前文件夹:
% 文件:circleCallFn.m
% 输入半径,调用 calcarea 算面积,再打印结果
radius = input('Please enter the radius: ');
area = calcarea(radius);
fprintf('For a circle with a radius of %.2f, ', radius)
fprintf('the area is %.2f\n', area)>> circleCallFn
Please enter the radius: 5
For a circle with a radius of 5.00, the area is 78.54
图 3.8:一个简单程序的标准结构
脚本负责「输入 → 调用 → 打印」的编排工作,函数只关心算法实现。这种「主线在脚本、细节在函数」的分层写法,是后面所有中等规模程序的骨架。
3.7.5 多输入参数:圆锥体积
圆锥体积 ,需要半径和高度两个参数:
function outarg = conevol(radius, height)
% conevol calculates the volume of a cone
% Format of call: conevol(radius, height)
% Returns the volume
outarg = (pi/3) * radius .^ 2 .* height;
end调用时实参顺序必须对应形参顺序:
>> conevol(4, 6.1)
ans =
102.2065
>> fprintf('The cone volume is %.2f\n', conevol(3, 5.5))
The cone volume is 51.84.^ 和 .* 同时出现,是为了兼容「传向量」——半径向量平方后再和高度向量元素逐乘,前提是两个向量长度相同。
3.7.6 局部变量与作用域
函数里临时用的中间变量叫局部变量(local variable),只在该函数运行期间存在。看下面这个算封闭圆柱材料成本的函数 cylcost.m:
function outcost = cylcost(radius, height, cost)
% cylcost 计算制作封闭圆柱所用材料的总成本
% 调用格式:cylcost(radius, height, cost)
% radius/height 单位是英寸,cost 单位是美元/平方英尺
% 1. 算总表面积(平方英寸)
surf_area = 2 * pi * radius .* height + 2 * pi * radius .^ 2;
% 2. 换算成平方英尺,并向上取整
surf_areassf = ceil(surf_area / 144);
% 3. 乘以单价
outcost = surf_areassf .* cost;
end>> cylcost(32, 73, 4.50)
ans =
661.5000surf_area、surf_areassf 在函数返回后立即消失,在命令行敲会报「未定义」。
常见坑:脚本 vs. 函数的作用域
脚本里的变量和命令行共享同一个工作区(base workspace),脚本跑完变量还在;函数有自己的工作区,函数跑完除了返回的输出参数,其它变量都不可见。这点对刚接触 MATLAB 的人最反直觉——函数就像一个密封的工厂,原料(输入参数)从厂门进,成品(输出参数)从厂门出,里面用啥临时设备,外面一概不知。
3.8 命令与函数的等价写法
MATLAB 有些命令是「命令式(command syntax)」——直接敲名字+参数,不加括号、不接返回值,比如 type、save、load。它们的本质其实是函数,MATLAB 允许两种写法等价:
>> type script1 % 命令式
>> type('script1') % 函数式上面两条完全等价。
特别提一下 load:用命令式时,MATLAB 会默认用文件名做变量名。想自己起名,用函数式最方便:
>> points = load('pointcoords.dat') % 直接存到 points
points =
3.3000 1.2000
4.0000 5.3000命令式 vs. 函数式的取舍
命令式短,敲着省事,但没有返回值、没有变量名可指定。任何需要把结果送进后续计算的场合,都优先用函数式。教材后文凡是要把文件内容塞进特定变量的,都会写成
data = load('xxx.dat')、info = type('xxx.m')这种形式。
本章回顾:常见的小题目类型
学完这一章,你应该有能力做下面这几类小题。每一题都对应了原书 3.x 节后的 Practice 题目,先看思路再写代码:
① 输入 + 计算 + 输出三件套
例如求三角形面积、球的体积、抛物线在某个 x 处的 y 值。关键套路:先把所有变量从键盘收齐 → 算 →
fprintf一句话输出,保留合适的小数位。
② 一组输入走两条分支
例如「输入英尺或米,统一输出米」:先用
input(..., 's')收单位字符,再if strcmp(unit, 'm')决定要不要换算。这是第 4 章选择结构的预演。
③ 读数据文件 → 拆向量 → 画图
例如从
.dat读两列数据画成散点图。注意先验证数据:load完用disp(data)或size(data)看看行列数对不对,再继续画图,否则调试时根本不知道是哪一步出问题。
④ 写一个返回单值的小函数
例如把摄氏度转华氏度、
mwh_to_gj(兆瓦时转吉焦)、已知长宽求矩形面积。函数体常常只有一行加end,但H1 注释块和命名一致性要做到位,这是后面所有大程序的「基本工」。
本章小结
本章通关标准:
- 能把「输入 → 计算 → 输出」三步法写成一个有
input+fprintf的完整脚本。- 看见
%d / %f / %s / %c / %5d / %.2f就知道怎么选。- 知道
script与function的差别:脚本共享 base workspace,函数有自己的工作区。- 能写出
function out = foo(in)形式、文件名与函数名一致的函数,并能用.*兼容向量入参。
常见坑:把 3 条最容易踩雷总结一下
- 字符与字符串输入忘了加
's':导致用户输入被当作 MATLAB 表达式解读,字母就报错,变量名就会被替换。fprintf末尾忘\n:下一次提示符黏在上一行末尾,屏幕看起来乱七八糟。- 函数名和文件名不一致:脚本能跑,函数调用就报「Undefined function」。
进阶坑:input 输入变量名时被「吃掉」
>> t = 11; >> num = input('Enter a number: ') Enter a number: t num = 11因为没加
's',MATLAB 把t当变量名解读,把它的值 11 取进来。这其实是一个合法但易混的副作用:想要「字符串」必须显式's',否则用户输入永远是「表达式」。
进阶坑:
disp与fprintf混用错位
disp不需要\n——它每次调用都自动换行。fprintf必须靠\n换行;混用容易出现「disp 完后留下空白行」「fprintf 不换行导致下一条命令黏住」的怪现象。- 一段输出里全用
fprintf最稳;disp只在你只想要「最快打印一个东西」时再用。
1. 写一个脚本
trianglearea.m,从键盘输入三角形的底和高,输出「The area of the triangle is X.XX square units.」用两个
input(其中一个提示加单位),加一条fprintf,格式化保留 2 位小数。别忘了赋值语句加分号。
2.
fprintf('%.4f\n', 1/3)会打印什么?改成fprintf('%8.4f\n', 1/3)又会怎样?第一条
0.3333;第二条0.3333前面补 4 个空格凑成 8 列宽,前导空格用 x 标出来就是xxxx0.3333。
3. 写一个函数
calcrectarea(len, wid),返回矩形面积,并把结果用于fprintf('We need %d sq in.\n', ceil(calcrectarea(3.1, 4.4)))。函数体一行
out = len .* wid;,ceil(13.64) = 14,输出We need 14 sq in.。
4. 看这段代码:
matlab if x = 5; disp('yes'); end能不能运行?为什么?不能。条件里用了单等号 =(赋值),正确写法是双等号 ==(相等比较)。MATLAB 在条件位置不识别
x = 5为合法表达式,会直接报错。
5.
load sales.dat之后为什么多出一个名叫sales的变量?
load命令式用法规定:文件名去掉扩展名后,自动成为变量名。要避免这种「文件名强加变量名」的副作用,改用函数式:data = load('sales.dat')。
,下面两种写法哪个对?为什么?
A = input('Enter vec: ') % 写法 1 B = input('Enter vec: ', 's') % 写法 2写法 1 正确:用户输入
[1 3 5 7]被当作 MATLAB 表达式解析,A 得到[1 3 5 7]数值向量;写法 2 把整段字符(包括方括号和空格)当成字符串'[1 3 5 7]',不能直接当数值用。
7. 写一个
cylvol(r, h)函数:输入半径和高度,返回圆柱体积。要求函数能接受向量入参。function v = cylvol(r, h) v = pi * r .^ 2 .* h; end关键在
.*和.^:传向量时是元素逐乘;如果漏掉点号,会触发「内矩阵维度必须一致」错误。
下一章预告
第 4 章开始学「选择结构(selection statements)」——
if、if-else、elseif、switch、以及一堆isxxx函数。掌握了这一章的脚本和函数基础,下一章才能真正写出「根据输入决定做什么」的程序。