MATLAB学习笔记3:MATLAB编程基础(前半)

阅读前请注意:

1. 该学习笔记是华中师范大学HelloWorld程序设计协会2021年寒假MATLAB培训的学习记录,是基于培训课堂内容的总结归纳、拓展阅读。博客内容由 @K2SO4钾 撰写、编辑,发布于 @K2SO4钾 的个人投稿与华中师范大学HelloWorld程序设计协会CSDN官方账号 @CCNU_HelloWorld注意,如需转载需得到作者 @K2SO4钾 的同意与授权!

2. 学习笔记基于 《MATLAB R2018a完全自学一本通》(刘浩, 韩晶) 1 ,笔记中增加了很多程序示例和笔者个人的思考。学习笔记面向刚接触MATLAB的新手,内容偏基础。学习前请自行下载安装MATLAB。笔记中示例用MATLAB版本为MATLAB R2019a

3. 请谅解笔记可能会出现的错误,欢迎指正讨论;由于MATLAB更新导致的旧代码无法使用的情况,也欢迎讨论交流。


3.0 MATLAB笔记:传送门汇总


3.0.1 MATLAB学习笔记:传送门汇总


MATLAB学习笔记0:学习须知

MATLAB学习笔记1:MATLAB概述

MATLAB学习笔记2:MATLAB基础知识(上)

MATLAB学习笔记2:MATLAB基础知识(中)

MATLAB学习笔记3:MATLAB编程基础(前半)

MATLAB学习笔记3:MATLAB编程基础(后半)

MATLAB学习笔记5:绘图基础与数据可视化(上)

MATLAB学习笔记5:绘图基础与数据可视化(中)


3.0.2 MATLAB拓展学习:传送门汇总


MATLAB拓展学习T1:匿名函数和内联函数

MATLAB拓展学习T2:程序性能优化技术

MATLAB拓展学习T3:histogram函数详解

MATLAB拓展学习T4:数据导入


3.0.3 MATLAB专题博客:传送门汇总


MATLAB-S1:元胞自动机原理及MATLAB实现

MATLAB-S2:图像处理技术


3.0.4 MATLAB应用实例:传送门汇总


MATLAB应用实例:Floyd算法

MATLAB应用实例:简单数字滤波技术的MATLAB实现

MATLAB应用实例:无限脉冲响应数字滤波器


施工中~请耐心等待





3.1 变量


变量,通常由用户定义,用于保存、处理数据,是内存中的一段可操作内存的符号化表示。定义变量时,编译器会根据变量的数据类型,来为其分配相应大小的内存空间,编写程序时,程序可以通过引用变量名来访问这一段内存空间。


3.1.1 变量命名


和C语言一样,MATLAB中变量命名有一定的规范。变量不需要提前声明就可以直接进行赋值,其遵循以下4个命名规范:

1. 变量名和函数名对字母大小写敏感。

例如abc和ABC是不同的变量,虽然end是关键字,但不妨碍End可以作为一个变量。

2. 变量名必须以字母开头,其后可以是任意字母、数字或下划线,但是不能有空格、中文标点。

例如teaching_1、example_a是合法的变量名,而_stuname、stu.name、3part、class info就是不合法的变量名,在MATLAB中会报错。

3. 不能使用MATLAB关键字作为变量名,不推荐命名与 MATLAB 中的函数重名。(3.1.2中会介绍关键字)

4. 变量名最多可包含63个字符,从第64个字符之后的字符将被忽略。


MATLAB中提供了检验是否为合法变量名称的isvarname函数,其调用方式为isvarname(‘str’),str是待判断的变量名称,如果是合法变量名则返回1,否则返回0。

isvarname

clc,clear all,close all
res1=isvarname('teaching_1')
res2=isvarname('example_a')
res3=isvarname('_stuname')
res4=isvarname('stu.name')
res5=isvarname('3part')
res6=isvarname('class info')
res7=isvarname('try')
res8=isvarname('end')
res8=isvarname('End')


3.1.2 关键字


关键字是MATLAB中常用的流程控制变量,共20个。在命令行窗口输入iskeyword按下回车,MATLAB会返回这20个关键字。关键字不能用以做变量名!

查看关键字

iskeyword

iskeyword还可以用于判断变量名称是否是关键字,调用方式为iskeyword(‘str’),str是待判断的变量名称,如果是关键字则返回1,否则返回0。

iskeyword('str')

iskeyword('try')
iskeyword('A')
iskeyword('end')



3.1.3 默认特殊变量


MATLAB中的默认特殊变量具有系统默认的含义并且已经预设了值。在不对它们的值进行修改时,它们固定为默认值。

默认特殊变量描述
ans系统默认的用于保存运算结果的变量名(一般不建议用户将变量命名为“ans”)
beep使计算机发出声音
pi圆周率
eps机器零阈值,在2.1.2.3节中有介绍
inf无穷大值
NaN或nan不定数值
i或j虚数
nargin针对当前正在执行的函数,返回函数调用中给定函数输入参数的数目(仅在函数体内)
nargout针对当前正在执行的函数,返回函数调用中指定的函数输出参数的数目(仅在函数体内)
varargin可变的函数输入参数个数,是函数定义语句中的一个输入变量
varargout可变的函数输出参数个数,是函数定义语句中的一个输出变量
realmin可用的最小实数,双精度形式的最小标准正浮点数
realmax可用的最大实数,双精度形式的最大有限浮点数
intmax指定整数类型的最大值,默认为int32,以intmax(‘classname’)的方式调用来查看其它整数类型

clc,clear all,close all
% 计算圆的面积,圆半径为3
format long
%% 用pi的默认值来计算
r=3;
ans1=pi*r*r
%% 将pi设置为3.1416计算
pi=3.1416;
ans2=pi*r*r

在这里插入图片描述



3.1.4 变量的类型


3.1.4.1 局部变量

MATLAB中每个函数都有自己的局部变量,这些变量 存储在该函数独立的工作区中与其它函数的工作区、主工作区的变量分开存储调用结束后,这些变量随即删除。 局部变量生存的时间即该函数开始到该函数结束的时间。

局部变量

clc,clear all,close all
A=[3,2,4;5,1,7;4,1,4]; % 输入一个3*3的矩阵
B=func(A) % 调用func函数,处理结果返回B

%% 这是一个子函数,其功能如注释所述
function R=func(X) % 这里的X相当于主函数的A(后面会讲)
a=X(1,:);
a=sin(a); % 将矩阵的第一行取sin
b=X(2,:);
b=cos(b); % 将矩阵的第二行取cos
c=X(3,:);
c=tan(c); % 将矩阵的第三行取tan
R=[a,b,c]; % 将a、b、c拼接好,返回R至主函数
end

如上面一段代码和图片所示,如果想要查看子函数中的工作区,可以使用断点调试的方式,在子函数开始的位置设置断点,然后以步进的方式运行(也可以在函数尾放置一个断点,让MATLAB直接运行到该断点处),右侧工作区在子函数运行过程中就会显示该函数的工作区。该函数执行完成后,这些变量会被销毁。

例如你把上面那段代码运行后,再在命令行窗口中输入a敲下回车,编译器一定会报错,提示你未定义函数或变量 ‘a’。这就是因为你想访问的a变量在函数func执行完成后就已经销毁了。

因此既然局部变量生存的时间即该函数开始到该函数结束的时间,那么在主函数、不同的子函数中,你可以定义相同名称的变量。这些变量存储的工作区不同,因此不会产生冲突。(当然实际编程中还是建议区分开)


子函数中的A、B与主函数、其它子函数不冲突

clc,clear all,close all
A=[3,2,4;5,1,7;4,1,4]; % 输入一个3*3的矩阵
B=func1(A) % 调用func1函数
B=func2(B) % 调用func2函数

%% 子函数中的AB与主函数、其它子函数不冲突
function A=func1(B)
B=sin(B);
A=B';
end

%% 子函数中的AB与主函数、其它子函数不冲突
function B=func2(B)
B=cos(B);
end

3.1.4.2 全局变量

全局变量在定义该变量全部工作区中均有效。其中一个工作区内改变该变量的值时,其它工作区内的值也会改变 全局变量的作用是减少数据传递的次数

全局变量以关键字global来定义,定义的位置在需要用到该全局变量的函数体的开头

clear all可以清除掉全局变量。(一定记得 是clear all不是clear!!)

需要注意的是,由于全局变量的性质,使用全局变量有一定风险,不仅容易造成全局变量、普通变量和局部变量的混乱,也容易对其它程序造成影响,使用时要谨慎!在MATLAB中会将全局变量标记为绿色,起到提醒用户的效果,在变量备注中也会标明global。


☆ 例3-1:将下面两段代码分别复制进两个不同的M文件中(这里以eg1.m、eg2.m来举例),按要求操作,观察现象。

% 将这段代码复制进eg1.m
clc,clear all,close all
global p; % 定义p是全局变量
p=0; % p初始化
for i=1:5
    result=global_p(); % 调用5次函数global_p
end

function y=global_p() % 该函数作用是让全局变量自增
    global p; % 因为子函数需要用到全局变量p,因此需要声明p是全局变量
    p=p+1 % 对全局变量p的操作
    y=1;
end
% 将这段代码复制进eg2.m
global p
p=p+3

Q3-1-1 运行1次eg1.m,观察p的值。

Q3-1-2 运行1次eg2.m,观察p的值。再运行1次eg2.m,观察p的值。

Q3-1-3 在命令行窗口输入“clear”,再运行1次eg2.m,观察p的值。在命令行窗口输入“clear all”,再运行1次eg2.m,观察p的值。执行完成后,运行clc,clear all,close all以防止这个全局变量对后续运行的内容造成影响。

Q3-1-4 将下面这段代码复制入eg1.m,运行之前先思考一下p最终结果是多少。再运行代码,将其与Q3-1-1比较。

% 将这段代码复制进eg1.m
clc,clear all,close all
p=0; % p初始化,p是普通变量
result=global_p(); % 调用1次函数global_p
p

function y=global_p() % 该函数作用是让全局变量自增
    p=10;
    p=p+1 % 对局部变量p的操作
    y=1;
end

分析:


A3-1-1 主函数和子函数如果需要使用全局变量,都应先对其进行声明。主函数调用了5次子函数,p=p+1执行5次。

A3-1-1


A3-1-2 由于没有进行工作区清除,全局变量在所有工作区中仍有效。执行这段代码后,p在原先的执行结果上又被加上了3,再次执行,又被加上了3。

A3-1-2

A3-1-3 使用clear all才能达到清除全局变量的效果。

A3-1-3

A3-1-4 运行结果中,第一个p=11是子函数运行过程中输出的值,这个p是一个局部变量,生存期仅在子函数内,对于主函数的p是没有影响的。第二个p=0是主函数中变量p的输出。这再次证明了不同函数中的变量所存储的工作区是分开的

A3-1-4

3.1.4.3 永久变量(了解)

永久变量persistent 在函数文件中使用,在脚本中定义无效。它可以把 在函数中声明的局部变量保存到内存,供以后调用该函数使用。与全局变量不同,persistent变量只能被定义该永久变量的函数使用,以防止被其他函数或其他命令所改变。persistent变量只有在m文件被改变或被从内存中清除(clear all)时才被清除。

下面这个例子能帮助你更好地理解永久变量。


☆ 例3-2:新建一个函数M文件,把下面这段代码复制在该文件中,保存,并记录该文件的名称(本例中使用的名称是eg4.m)。

function GetInfo(A)
    persistent Info
    persistent counter
    if isempty(Info)
        Info=[];
    end
    if isempty(counter)
        counter=0;
    end
    [L,W]=size(A);
    Max=max(max(A));
    Min=min(min(A));
    Sum=sum(sum(A));
    Avg=mean(mean(A));
    disp('该矩阵的基础信息:')
    Info=[L,W,Max,Min,Sum,Avg]
    counter=counter+1;
    disp('您已经调用该函数的次数:')
    disp(counter)
end

新建一个脚本M文件,将下面这段代码复制在该文件中,并将这段代码中的“eg4”修改为刚刚让你记录的文件名称。

clc,clear all,close all
A=rand(3,4);
eg4(A)
B=[1,3,2;3,1,2;2,3,1];
eg4(B)
C=12;
eg4(C)

多次运行这段代码,观察一下运行结果。将下面这段代码复制进命令行窗口,敲下回车,再观察运行结果。

A=rand(3,4);
eg4(A)
B=[1,3,2;3,1,2;2,3,1];
eg4(B)
C=12;
eg4(C)

例3-2



3.2 MATLAB的控制流


MATLAB中的程序控制流包含6种,用于实现多元化的编程功能。以下将具体介绍


3.2.1 顺序结构


顺序结构中,代码依照其先后顺序依次执行。顺序结构可单独作为一个完整的程序,也可以作为其它复杂程序的一部分。以“步进”方式运行顺序结构,可以观察到代码一行一行的顺序执行。


☆ 例3-3:一般来说,MATLAB中简单的绘图就是一个顺序结构。新建一个脚本文件或实时脚本文件,将下面这段代码复制入文件并运行,观察运行结果中几段输出的文字和图片对应在代码段中的位置。

clc,clear all,close all

% 第一部分
t=0:4*pi/1000:4*pi;
y=2/3*exp(-t/2).*cos(3/2*t);
plot(t,y,'b')
grid on
fprintf('第一张图是一条曲线')

% 第二部分
x=sin(t);
y=cos(t);
plot(t,x,'b+',t,y,'r-')
text(0,-0.8,'+: y=sinx')
text(0,-0.9,'*: y=cosx')
fprintf('第二张图是sin曲线和cos曲线')

% 第三部分
x=-4*pi:0.1:4*pi;
y=2.*exp(-0.5.*x).*sin(2.*pi.*x);
ymax=2.*exp(-0.5.*x);
ymin=-2.*exp(-0.5.*x);
plot(x,y,'-b',x,ymax,':r',x,ymin,'-.m')
grid on
title('函数及其包络线')
text(4,-1000,'实线:原函数')
text(4,-1200,'虚线线:上包络线')
text(4,-1400,'点划线:下包络线')
fprintf('第三张图是振荡函数和它的包络线')

% 第四部分
t=-3:0.1:3;
x=sin(2*t);
y=cos(2*t);
[x,y]=meshgrid(x,y);
z=x.^2+2*y.^2;
mesh(x,y,z)
grid on
title('三维网格曲面图')
xlabel('axis x')
ylabel('axis y')
zlabel('axis z')
surf(x,y,z)
fprintf('第四张图是三维网格曲面')
grid on
title('三维曲面图')
xlabel('axis x')
ylabel('axis y')
zlabel('axis z')
fprintf('第五张图是三维曲面图')

% 第五部分
x=0:0.01:2;
y=1:0.01:3;
[X,Y]=meshgrid(x,y);
Z=(Y-1).*(Y-1)+(X-2).*(X-2)-1;
mesh(X,Y,Z)
grid on
title('三维网格曲面图')
xlabel('axis x')
ylabel('axis y')
zlabel('axis z')
fprintf('第六张图是三维网格曲面')

例3-3

☆ 例3-4:设r=4。依次输出以r为半径的圆的面积、球的表面积和体积。输出完成后,又设h=3,输出以r为半径、h为高的圆柱的体积。

分析: 代码如下。

clc,clear all,close all
r=4;
R_S=pi*r*r % 圆的面积
S_S=4*pi*r*r % 球的表面积
S_V=4/3*pi*r^3 % 球的体积
h=3;
C_V=pi*r*r*h % 圆柱的体积

在这里插入图片描述



3.2.2 if-else结构


if-else分支结构是选择结构中的一种,每个if-else分支结构需要一个end作为结尾(之后的每一种结构都应以end结尾,从伪代码中即可看出,文字不再赘述)。其结构依需要使用的功能主要分为以下三种。


3.2.2.1 if-end结构

if-end结构适用于只有一组判断条件并且只有当该判断条件成立的时候执行命令组的情况。if后接的条件可有多个,这些条件依照功能逻辑与、逻辑或连接

% 这是一段伪代码
if conditions
        commands
end

伪代码中,若判决条件conditions为真(即值为逻辑1),则执行命令组commands,否则跳过该命令组,执行该结构之后的内容。


☆ 例3-5: 编写程序实现功能:任意设x的值,当 0 ≤ x ≤ 5 0\leq x\leq 5 0x5时,计算 y = x y=\sqrt{x} y=x 输出结果,并输出文字“运行结束”;其它情况,仅输出文字“运行结束”。

分析: 这段代码只需要判断x是否在0到5之间,并且只有在该区间的时候需要执行“输出结果”的命令组,因此用if-end结构即可。 注意表达“ 0 ≤ x ≤ 5 0\leq x\leq 5 0x5”关系的时候需要用到逻辑与,不能直接写“0<=x<=5”!

clc,clear all,close all
x=2; % x的值可任设
if x>=0 && x<=5
    y=sqrt(x)
end
fprintf('运行结束')

在这里插入图片描述


3.2.2.2 if-else-end结构

if-else-end结构适用于有一组判断条件并且该判断条件成立或不成立的时候都有执行命令组的情况。if后接的条件可有多个,这些条件依照功能以逻辑与、逻辑或连接

% 这是一段伪代码
if conditions
        commands_1
else
        commands_2
end

伪代码中,若判决条件conditions为真(即值为逻辑1),则执行命令组commands_1,否则执行commands_2。


☆ 例3-6:编写程序,实现表达式 { x 2 + 5 x + 3 , x ⩾ 0 x 3 + ∣ x ∣ + 7 , x < 0 \left\{\begin{matrix} x^{2}+5\sqrt{x}+3, x\geqslant 0\\ x^{3}+|x|+7, x< 0 \end{matrix}\right. {x2+5x +3,x0x3+x+7,x<0,并且使用一组x数据进行测试。将缺省的代码补全在两行百分号之间。

%% 设置一组测试数据
clc,clear all,close all
test=-10:1:10; % 测试数据可以任意修改
%% 功能实现
num=length(test); % 求测试数据的个数
res=zeros(1,num); % 预设结果矩阵,预分配内存以加快运算速度
for i=1:num % 设置循环,每次循环求得其中一个数据代入表达式后的值
    x=test(i); % 取出一个测试数据x
    y=0; % 请把x代入表达式的结果赋给y,y作为临时存储的变量
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 把你的代码复制在这里,以实现题设表达式功能
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    res(i)=y; % 将计算结果保存在res中
end
%% 展示结果
format compact
fprintf('测试数据依次为:')
test
fprintf('代入表达式后运算结果依次为:')
res

分析: 该表达式需要判断x是否大于等于0,而这个条件是否成立涉及到两个不同的计算方式,因此采用if-else-end结构。这段代码是一段标准的计算分段函数的代码,但是这段代码仍可以在保证功能、保证性能的基础上更简化(这段代码这么写只是为了新手方便理解)。再加强一点编程基础,你能对代码再进行简化吗?

%% 设置一组测试数据
clc,clear all,close all
test=-10:1:10; % 测试数据可以任意修改
%% 功能实现
num=length(test); % 求测试数据的个数
res=zeros(1,num); % 预设结果矩阵,预分配内存以加快运算速度
for i=1:num % 设置循环,每次循环求得其中一个数据代入表达式后的值
    x=test(i); % 取出一个测试数据x
    y=0; % 请把x代入表达式的结果赋给y,y作为临时存储的变量
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    if x>=0
        y=x^2+5*sqrt(x)+3;
    else
        y=x^3+abs(x)+7;
    end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    res(i)=y; % 将计算结果保存在res中
end
%% 展示结果
format compact
fprintf('测试数据依次为:')
test
fprintf('代入表达式后运算结果依次为:')
res

在这里插入图片描述


3.2.2.3 if-elseif-end结构 / if-elseif-else-end结构

该结构适用于有多组判断条件、多条分支的情况。if-elseif-end结构与if-elseif-else-end结构相差不大,按需要使用。

% 这是一段伪代码,if-elseif-end结构
if conditions_1
        commands_1 % 若conditions_1为真,则执行commands_1,执行完成后结束整个结构
elseif conditions_2
        commands_2 % 若conditions_2为真,则执行commands_2,执行完成后结束整个结构

elseif conditions_n
        commands_n % 若conditions_n为真,则执行commands_n,执行完成后结束整个结构
end

% 这是一段伪代码,if-elseif-else-end结构
if conditions_1
        commands_1 % 若conditions_1为真,则执行commands_1,执行完成后结束整个结构
elseif conditions_2
        commands_2 % 若conditions_2为真,则执行commands_2,执行完成后结束整个结构

elseif conditions_n
        commands_n % 若conditions_n为真,则执行commands_n,执行完成后结束整个结构
else
        commands_n1 % 若上述所有判决条件conditions均为假,则执行commands_n1
end


☆ 例3-7:编写程序,实现符号函数 y = s g n ( x ) = { 1 , x > 0 0 , x = 0 − 1 , x < 0 y=sgn(x)=\left\{\begin{matrix} 1, x>0\\ 0, x=0\\ -1, x<0 \end{matrix}\right. y=sgn(x)=1,x>00,x=01,x<0。输入任取。

分析:

clc,clear all,close all
x=2; % x的值可任设
if x>0
    y=1;
elseif x==0
    y=0;
else
    y=-1;
end
fprintf('结果为y=%f',y)

在这里插入图片描述



☆ 例3-8:在两行百分号中间补全代码,实现功能:用户输入成绩数据x,当成绩在 80 < x ⩽ 100 80<x\leqslant 100 80<x100,输出文字“您的成绩为优秀”;成绩在 60 ⩽ x ⩽ 80 60\leqslant x\leqslant 80 60x80,输出文字“您的成绩为良好”;低于60分,输出文字“您的成绩未及格”;对于不合法的输入,输出文字“输入不合法”。

clc,clear all,close all
x=input('请输入您的成绩:'); % 让用户输入成绩数据至x
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 把你的代码复制在这里,以实现功能
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

分析:

clc,clear all,close all
x=input('请输入您的成绩:'); % 让用户输入成绩数据至x
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if x>80 && x<=100
    fprintf('您的成绩为优秀')
elseif x>=60 && x<=80
    fprintf('您的成绩为良好')
elseif x>=0 && x<60 % 需要注意这里,合法的成绩是0-100分,不要漏设x>=0fprintf('您的成绩未及格')
else
    fprintf('输入不合法')
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

在这里插入图片描述


3.2.2.4 if嵌套结构

多个if语句嵌套时,MATLAB会以缩进、标亮的形式来提醒你if、elseif、else、end的配对,也会在你点击代码中if、elseif、else、end以下划线的形式提醒你它们的配对情况。选择结构、循环结构可以相互进行嵌套,用以完成复杂的运算。


☆ 例3-9:将下面的代码复制入脚本文件,输入x值,运行之前先想一想结果会是什么,运行,检验结果是否与预想相符。

clc,clear all,close all
x=input('请输入任意数字:');
if x>0
    fprintf('x>0\n')
    if x>5
        fprintf('x>5\n')
        if x>7 && x<10
            fprintf('7<x<10\n')
        elseif x>20
            fprintf('x>20\n')
        else
            fprintf('a')
        end
    else
        fprintf('b')
    end
else
    fprintf('c')
end

3.2.3 switch-case结构


switch-case结构是选择结构的一种,常与otherwise关键词连用。switch-case结构适用于已知对于判决变量不同的具体值的情况下执行的命令组(而if-else结构适用于已知对于判决条件是否为真的情况下执行的命令组)。

switch-case结构用法如下:

% 这是一段伪代码
switch var % var即是需要判决的标量或字符串
        case value1
                commands1 % 若var与value1相等,则执行命令组commands1,执行后结束此结构
        case value2
                commands2 % 若var与value2相等,则执行命令组commands2,执行后结束此结构

        case valuen
                commandsn % 若var与valuen相等,则执行命令组commandsn,执行后结束此结构
        otherwise
                commandsn1 % 若var与前述所有value的值都不相等,则执行命令组commandsn1,执行后结束此结构
end

% 这是一段伪代码
switch var % var即是需要判决的标量或字符串
        case value1
                commands1 % 若var与value1相等,则执行命令组commands1,执行后结束此结构
        case value2
                commands2 % 若var与value2相等,则执行命令组commands2,执行后结束此结构

        case valuen
                commandsn % 若var与valuen相等,则执行命令组commandsn,执行后结束此结构
end

对于判决变量var,它可以是标量,也可以是字符串注意,不可以是数组或矩阵!)。它是标量时,MATLAB执行var==value以检测判决变量和判决量是否相等;它是字符串时,MATLAB执行strcmp(var,value)来检测二者是否相同。

对于判决量value,它可以是标量、字符串或者元胞数组。当判决变量var等于多个值的情况下需要执行同一组命令时,可以使用元胞数组减少编程。运行时,MATLAB会把var与元胞数组value里的所有元素进行对比,若有一组相同,都会执行case对应的指令。(见例3-11)

MATLAB中的switch语句与C语言中的switch有一定区别(区别主要在于关键字的使用),如果你学过高等程序语言设计C语言,可以自行进行对比,不要把二者搞混淆。


☆ 例3-10:将下面的代码复制入脚本文件,在两行百分号中补充代码,实现以下功能:用户输入产品等级(即x的值),对于不同的产品等级,输出文本“产品已检验,检验结果为x级”,并将产品的等级存入变量P_rank中。等级范围是1-4级(整数),对于其它的输入,应输出文本“输入有误!”,并将NaN赋予变量P_rank。

clc,clear all,close all
fprintf('输入产品等级(1-4的整数),输出文本标签\n')
x=input('请输入产品等级:');
P_rank=0; % 用于保存产品等级
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 把你的代码复制在这里,以实现功能
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

分析: 简单的switch-case结构的使用。

clc,clear all,close all
fprintf('输入产品等级(1-4的整数),输出文本标签\n')
x=input('请输入产品等级:');
P_rank=0; % 用于保存产品等级
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
switch x
    case 1
        P_rank=1;
        fprintf('产品已检验,检验结果为1级')
    case 2
        P_rank=2;
        fprintf('产品已检验,检验结果为2级')
    case 3
        P_rank=3;
        fprintf('产品已检验,检验结果为3级')
    case 4
        P_rank=4;
        fprintf('产品已检验,检验结果为4级')
    otherwise
        P_rank=NaN;
        fprintf('输入有误!')
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

在这里插入图片描述


☆ 例3-11:将下面的代码复制入脚本文件,在两行百分号中补充代码,实现以下功能:检测变量A中的内容。若A为字符串’hello world !’,则输出该字符串;若A为数2、4、6、8其中之一,则输出字符串’even’;若A为数1、3、5、7其中之一,则输出字符串’odd’。其它情况不予输出。

clc,clear all,close all
A=2; % 可以设任何值或字符串
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 把你的代码复制在这里,以实现功能
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

分析: 由于有多个分支都可以输出字符串’even’或’odd’,因此考虑在case后使用元胞数组。由于其它情况没有输出,因此不必加otherwise。

clc,clear all,close all
A=2; % 可以设任何值或字符串
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
switch A
    case {2,4,6,8}
        fprintf('even')
    case {1,3,5,7}
        fprintf('odd')
    case 'hello world !'
        fprintf('hello world !')
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

在这里插入图片描述


对比switch和if语句,能很容易发现二者区别:

  1. switch语句适用于判别相等、条件多且单一的情况,if语句适用于判别表达式真伪、条件复杂的情况。
  2. if语句可进行多层嵌套,功能要多于switch语句。
  3. switch语句可以直接判断字符串是否相同,其它语句需要自行调用strcmp函数。

3.2.4 try-catch结构


try-catch结构也是选择结构之一。它多用于增加代码容错率、减少代码报错的浪费时间等应用场景。其用法如下:

try
        commands1 % 先执行命令组1。若正确执行,执行完成后结束此结构
catch
        commands1 %命令组1执行发生错误时,执行命令组2。若正确执行,执行完成后结束此结构;若命令组2仍执行错误,MATLAB将终止该结构
end

函数lasterr可用于查看命令组1执行过程中发生的错误,若调用lasterr结果为空,则命令组1未发生错误。(注意,该函数可能返回上一段其它代码中产生的错误。重新启动MATLAB即可。


☆ 例3-12:运行下面一段代码,观察运行结果。

clc,clear all,close all
A=[1,2;3,4]; % 可以设任何值或字符串
res=zeros(1,4);
try
    A=A';
    A=reshape(A,[1,4]); % 把矩阵A转换为了行向量
    for i=1:length(A)
        res(i)=tan(A(i)); % 对行向量A中每个元素取tan值,存于res
    end
    fprintf('结果为:')
    res
catch
    A=tan(A); % 不对A进行行向量的转化,直接进行tan运算
    fprintf('结果为:')
    A
end
lasterr

例3-12A

如果将这段代码的第二行换成“A=[1,2,3;4,5,6]; % 可以设任何值或字符串”,观察运行结果。

A=[1,2,3;4,5,6]; % 可以设任何值或字符串

例3-12B


3.2.5 while循环结构


while结构是循环结构的一种,常用于需要重复执行一段命令多次、不确定循环次数的应用场景中。循环进行的条件是while后的判决条件为真。while的用法如下:

% 这是一段伪代码
while conditions % 当conditions为假时,跳过该结构
        commands % 若conditions为真(即值为1时),执行commands,执行完成后返回到while这一行,再次检测conditions,循环往复,直至conditions为假(即值为0时),跳出该结构
end

while后的表达式的值(其结果是标量或矩阵)决定循环是否继续进行。若其逻辑值为1(对于标量)或者矩阵中所有元素非0(对于矩阵),继续执行循环语句;若其逻辑结果为0(对于标量)或者矩阵中至少有一个元素为0,或者矩阵为空矩阵(对于矩阵),则跳出该循环结构。

while对于矩阵

clc,clear all,close all
A=[1,2,3;4,5,6]; % 可以设任何值或字符串
i=1;
while A
    fprintf('循环体被执行%d次\n',i)
    A(i)=0; % 只要矩阵中有一个元素为0,就会跳出循环体
    i=i+1;
end
fprintf('已跳出循环体')

一些应用场景中可能会用到死循环,例如元胞自动机、动态等待用户输入、模拟信号输入检测等。使用while(1) 便可以构造一个死循环,并且死循环常与break、continue指令(这两个指令本章就会讲)结合使用。

例如下面图片中的代码就是元胞自动机的代码,其核心就是红色矩形圈出来的while循环。如果用户不按下“stop”按钮,那么while后的表达式就永远为真,元胞自动机就会永远运行下去。

元胞自动机

while可以嵌套使用,也可以与选择结构、for循环结构嵌套使用。


☆ 例3-13:使用while语句实现表达式 ∑ i = 1 50 ∑ j = 0 100 l n ( i + j ) \sum_{i=1}^{50}\sum_{j=0}^{100}ln(i+j) i=150j=0100ln(i+j)

分析: 需要注意,这里需要使用循环的嵌套。外部共循环50次,外部每循环一次,内部循环101次。因此每次完成一次内部101次循环(内部每次循环中需要把内部循环变量j自增)而跳出内部循环后,不仅需要对外部循环变量i自增,也需要重置内部循环变量

clc,clear all,close all
i=1;
j=0;
res=0; % 设置初始值
while i<=50
    j=0; % 需要在内循环的外部重置循环变量j,(重置内部循环变量)
    while j<=100
        res=res+log(i+j);
        j=j+1; % 在内循环中j需要自加
    end
    i=i+1; % 在外循环中i需要自加
end
res

在这里插入图片描述



☆ 例3-14:这是学习任何编程语言都会遇到的一道经典题。使用while语句实现斐波那契(Fibonacci)数列:

F ( 0 ) = 0 , F ( 1 ) = 1 , F ( n ) = F ( n − 1 ) + F ( n − 2 ) , ( n ≥ 2 , n ∈ N ∗ ) F(0)=0, F(1)=1, F(n)=F(n-1)+F(n-2), (n\geq 2, n\in N^{*}) F(0)=0,F(1)=1,F(n)=F(n1)+F(n2),(n2,nN)

将该数列存放于矩阵F中,该数列最大值不超过30000。


分析: 可以自行思考一下,为什么第五行不可以写成while F(i)<=30000呢?

clc,clear all,close all
F(1)=1;
F(2)=2;
i=2; % i用于寻址矩阵F最新存进去的元素
while F(i)+F(i-1)<=30000 % 不超过30000,就执行循环体
    F(i+1)=F(i)+F(i-1);
    i=i+1;
end
F

在这里插入图片描述



3.2.6 for循环结构


for函数是最常用、对于大型运算最有效的循环结构,常用于需要重复执行一段命令多次、已确定循环次数的应用场景中。循环进行的条件与循环变量所对应的数组有关,以下是它用法的伪代码。

for i=array % 将数组赋予循环变量i
        commands % 循环体执行的次数与数组array的长度(length(array))相同
end

也就是说,循环变量对应的数组长度有多长,该循环就要执行多少次。需要注意的是,每次循环中,循环变量都会依照数组设置,依次赋值。

例如for x=1:10,第一次,x=1,执行循环体;第二次,x=2,执行循环体;……;第10次,x=10,执行循环体;x=11,发现不符合预先设置的数组,因此退出循环,继续执行后面的代码。因此最终,i=11而非10

学过高等程序语言设计C语言的同学需要注意,再次强调一遍,每次循环过程中循环变量 是被赋值,而不像C语言中的for函数“for(i=1;i<=10;i++)”对于循环变量i来说是自增。对比下面两段代码就能知道区别在哪里了。

//这是一段C语言代码
#include<stdio.h>
int main()
{
	int i;
	for(i=1;i<=10;i++)
	{
		i=i-1; //由于更改了i,按照逻辑,这里是一个死循环
		printf("循环被执行了一次\n");
	}
}
% MATLAB代码
clc,clear all,close all
for i=1:10
    i=i-1; % 然而在MATLAB中并不是死循环,是因为MATLABfor循环在每次循环中会给循环变量i赋值
    fprintf('循环被执行了一次\n')
end

在这里插入图片描述


☆ 例3-15:使用for语句实现表达式 ∑ i = 50 100 i i \sum_{i=50}^{100}i^{i} i=50100ii


分析:

clc,clear all,close all
res=0;
for i=50:100
    res=res+i^i;
end
res

在这里插入图片描述



☆ 例3-16:使用for语句实现表达式 ∑ i = 1 50 ∑ j = 0 100 l n ( i + j ) \sum_{i=1}^{50}\sum_{j=0}^{100}ln(i+j) i=150j=0100ln(i+j)


分析: 需要注意,这里需要使用循环的嵌套。利用循环变量是一个数组这一特性,能比while更便捷地写出循环代码。

clc,clear all,close all
res=0; % 设置初始值
for i=1:50
    for j=0:100
        res=res+log(i+j);
    end
end
res

在这里插入图片描述


使用for循环同时也可以对于矩阵内的所有元素进行遍历,也可以依照寻址方式使用for循环对于矩阵的一部分内容进行操作。这是矩阵操作非常重要的一点。while结构同样也有此功能,for与while结构在不同的应用场景中发挥着重要作用。


☆ 例3-17:编程实现以下功能:使用正态分布随机数randn函数构造一个10行20列的矩阵。对于该矩阵右半部分(即第11列至第20列),若元素值大于等于1,则将其值更改为1;若元素值小于等于-1,则将其值更改为-1;其余情况将其值更改为0。

分析: 这里需要使用for循环对矩阵部分元素进行遍历、修改,同时也要用到for和if的嵌套使用。

clc,clear all,close all
fprintf('原矩阵')
X=randn(10,20)
for i=1:10
    for j=11:20
        if X(i,j)>=1
            X(i,j)=1;
        elseif X(i,j)<=-1
            X(i,j)=-1;
        else
            X(i,j)=0;
        end
    end
end
fprintf('处理后的矩阵')
X

在这里插入图片描述


使用for循环同时也可以对于字符串进行操作,方式同矩阵。


☆ 例3-18:使用for语句,将字符串’aaaabcdefghijkbbbbbb’中第5个字母到第14个字母翻转,使之成为’aaaakjihgfedcbbbbbbb’。

分析:

clc,clear all,close all
str='aaaabcdefghijkbbbbbb';
for i=1:4 % 寻址str1
    str1(i)='a';
end
j=5; % 用于str1矩阵的寻址
for i=14:-1:5 % 寻址str,从第14个字母开始,一直到第5个字母
    str1(j)=str(i);
    j=j+1;
end
for i=15:length(str) % 寻址str1
    str1(i)='b';
end
str1

在这里插入图片描述


MATLAB编程基础(后半)中,我们将继续讲到控制程序流的更多命令(重点掌握break、continue),函数与子函数的相关知识,优化代码的相关知识等。



思考题


☆ 思考题3-1:回忆一下变量的命名规则,回忆一下MATLAB中的6种程序流及它们各自的用法,将本章的18个例题动手做一下。相信你对这一章一定会掌握得很好。


☆ 思考题3-2:MATLAB中变量命名有何限制条件?下面这些变量哪些是正确的命名?

① ccnu_helloworld
② 123go123
③ _result
④ x*y
⑤ sum of sin
⑥ Passenger’s
⑦ sin
⑧ while



部分思考题答案


思考题3-2

  1. 有效的变量名称以字母开头,后跟字母、数字或下划线,变量大小写敏感;
  2. 不能超过 MATLAB 的最大名称长度(63个字符),否则将被截断;
  3. 不能以关键词命名(可通过iskeyword查看所有关键词);
  4. 命名时尽量不与 MATLAB 中的函数重名(允许重名,但是不推荐);

①⑦符合条件。


撰写:邓云泽、林耀
审核:华中师范大学HelloWorld程序设计协会工作人员


  1. 刘浩, 韩晶. MATLAB R2018a 完全自学一本通[M]. 北京:电子工业出版社. 2019. ↩︎

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

K2SO4钾

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值