据我所知,目前几乎没有什么资料可以帮助人们理解 MATLAB 的错误信息。大多数语法错误其实不难修复,只要你知道它们的成因。因此,这篇指南的目的是帮助识别并修复 MATLAB 代码中的错误。

这里还列出了警告信息,因为它们常常会在后续导致错误。

算术错误

通常这些错误都比较直观。以下是一些无法执行的常见运算,以及 MATLAB 的返回结果(并伴有警告):

  • a / 0:若 a > 0,则返回 Inf;若 a < 0,则返回 -Inf;若 a = 0,则返回 NaN。

  • log(0):返回 -Inf。

  • MATLAB 将 0^0 定义为 1。

  • NaN 通常会导致错误或无效结果,除非你采取措施防止其传播。

错误示例:

??? Error using ==> minus
Matrix dimensions must agree.

这表示矩阵维度不一致。检查表达式中所有项的维度是否一致。通常是索引错误导致了维度不一致。如果你使用的是幂运算,可能需要在参数后加一个点(.),比如:

y = x.^2  % 正确
y = x^2   % 错误(x 为数组时)

矩阵乘法要求第一个矩阵的列数等于第二个矩阵的行数,否则会报错:

??? Error using ==> mtimes
Inner matrix dimensions must agree.

与前一个错误不同,这个错误也可能是你本来想做元素乘法(点乘)但忘了加 .

对奇异矩阵求逆会得到一个警告,并返回一个包含 Inf 的矩阵。建议先计算行列式,或者更好的是使用不需求逆的数值稳定方法。

对非方阵进行幂运算会报错:

??? Error using ==> mpower
Matrix must be square.

这通常是因为你本来想用逐元素幂运算,却忘了加点 .^


数组索引错误

数组索引是 MATLAB 的关键特性之一。注意变量和函数名是区分大小写的,且变量可以覆盖内置函数名或用户自定义函数名。例如,如果你定义了一个数组 abs,然后调用 abs(1),MATLAB 会返回数组 abs 的第一个元素,而不是绝对值函数的结果。MATLAB 不会报错,因为它无法判断你是否是故意覆盖函数名的。所以千万不要使用已有函数名作为变量名。

MATLAB 提供的函数非常多,无法全部记住,因此在定义变量或函数前,如果不确定一个名字是否已被使用,可以使用 which name 检查。新版 MATLAB 支持命令补全,在输入左括号或 Tab 时会显示简要说明,有助于避免命名冲突。

常见错误还包括:

访问未定义元素

A = [1, 3];
A(3)

错误信息:

??? Index exceeds matrix dimensions.

如果你在循环中根据索引访问数组,但循环超过了数组范围,或者某个操作结果为空数组,再访问其元素,就会出现这个错误。

使用非法索引

A(-1)
A(i)
A(1.5)
A(0)

错误信息:

??? Subscript indices must either be real positive integers or logicals.

MATLAB 是从 1 开始索引的,不支持 0 或负数。索引必须为实数正整数或逻辑值。

表达式中如果涉及非法索引,MATLAB 可能会告诉你具体哪一个非法:

y = 3 * A(-1)

错误信息:

Attempted to access A(-1); index must be a positive integer or logical.

如果你使用逻辑索引,比如 A(0),会被解析为逻辑下标。逻辑 0 表示 false,对应为空返回:

A(A == 3)

是合法并有意义的表达方式。

使用错误语法

A(2::, 2)

错误信息:

??? A(2::, 2)
        |
Error: Unexpected MATLAB operator.

正确做法应为:

A(2:end, 2)

赋值错误

赋值是使用 = 给变量或数组元素赋值。

常见错误:

a = 2;
if a = 3

错误信息:

Error: The expression to the left of the equals sign is not a valid target for an assignment.

这是因为你想比较 a 是否等于 3,但写成了赋值。应改为:

if a == 3
end

你不能用不同数据类型混合定义普通数组。例如:

A = @(T) (1+T);
A(2) = 3;

错误信息:

??? Conversion to function_handle from double is not possible.

如果你需要混合数据类型,应使用 cell 数组或 struct 数组。

这是个容易出错的地方。来看下面这段代码:

>> A = [1,2,3;4,5,6;7,8,9];
>> A(2,:) = [3,5];
??? Subscripted assignment dimension mismatch.

>> A(2,:) = [1,4,5,6];
??? Subscripted assignment dimension mismatch.

>> A(1:2, 1:2) = [1,2,3,4];
??? Subscripted assignment dimension mismatch.

这里到底发生了什么?在这三种情况中,仔细比较左右两边的维度。

  • 第一个例子中,左侧是一个 1x3 的数组,而右侧是 1x2。

  • 第二个例子中,左侧还是 1x3,右侧是 1x4。

  • 第三个例子中,左侧是 2x2,而右侧是 1x4。

三种情况中,维度不一致。如果你想替换已有变量中的一部分,左右两侧的维度必须一致。数据点数量是否一致无关紧要(第三个例子就说明了这一点);维度必须一致。唯一的例外是,当一边是 1×n 向量,另一边是 n×1 向量时,MATLAB 会自动转置并进行替换:

>> A(2,:) = [1;2;3]
A =   1     2     3
      1     2     3
      7     8     9

如果你不想发生自动转置,要特别留意!


结构体数组错误(Struct Array Errors)

结构体数组较为复杂,MATLAB 对它们的操作有严格规定。先来看结构体数组的索引。

假设你定义了变量 cube,并希望记录两个立方体的边长和体积,可以这样写:

>> cube(1).side = 1;
>> cube(1).volume = 1;
>> cube(2).side = 2;
>> cube(2).volume = 8;

这是一种常用的数据存储方式。但如果你想提取所有 volume 并存入一个数组,下面这种做法是不行的:

>> volumes = cube.volume
??? Illegal right hand side in assignment. Too many elements.

你会注意到,若你直接输入 cube.volume,MATLAB 会显示所有值,但会分别赋值给 ans,因为它被视为多个独立值。要避免这个错误,你必须在赋值时把 cube.volume 包装成数组:

>> volumes = {cube.volume}

当然你也可以为每个元素单独赋值,但这种写法更适合处理大量结构体。

就像提取数据一样,向结构体中添加字段时,即便内容相同,也需要逐个添加。例如:

>> cube.volForm = @(S) (S^3)
??? Incorrect number of right hand side elements in dot name assignment. Missing [] around left hand side is a likely cause.

>> cube(:).volForm = @(S) (S^3)
??? Insufficient outputs from right hand side to satisfy comma separated list expansion on left hand side. Missing [] are the most likely cause.

实际上错误并不是因为缺少 [],而是因为你不能一次性将相同值赋给所有结构体字段,必须逐个赋值:

>> for ii = 1:2
>>   cube(ii).volForm = @(S) (S^3);
>> end

结果:

>> cube
ans = 1x2 struct array with fields:
  volume
  side
  volForm

此时两个结构体中都包含同一个体积计算公式。为了避免这种必须用循环的情况,建议不要拆分结构体根字段。比如可以这样写:

>> shapes.cubeVol = @(S) (S^3);
>> shapes.cube(1).vol = 1;
>> shapes.cube(2).vol = 8;

这样就不需要为每个子结构体单独设置公式。


语法错误(Syntax Errors)

括号错误(Parenthesis Errors)

与 C++ 不同,MATLAB 中不需要以特殊符号结束每一行,只要有换行即可。但你仍需遵循语法规则,尤其是括号的位置要特别注意。

下面是一个常见错误:

>> A(1
??? A(1
       |
Error: Expression or statement is incorrect--possibly unbalanced (, {, or [.

意思是你缺少一个括号或多加了一个。

另一个类似错误是:

>> A(1))
??? A(1))
        |
Error: Unbalanced or misused parentheses or brackets.

MATLAB 会试图指出缺失括号的位置,但未必准确。复杂表达式中你需要仔细检查。一个实用技巧是:在出错行之后设置断点,直到那行断点变红说明语法修正正确了。当然,修正后还要确保括号使用逻辑正确,否则可能又会报索引或函数调用相关的错误。


字符串错误(String Errors)

你可以通过两种方式创建字符串:使用 '字符串' 的语法,或者输入仅用空格分隔的多个词(不包括换行),例如:

>> save file.txt variable

在这行代码中,file.txtvariable 被作为字符串传给 save 函数。但有时你可能会忘记括号,导致错误地将字符串传给一个不接受字符串的函数:

>> eye 5
??? Error using ==> eye
Only input must be numeric or a valid numeric class name.

这类错误通常很容易发现,因为字符串在 MATLAB 中是紫色高亮的。这种问题经常发生在你取消注释一行文本后却忘记修改它。


如果在字符串另一种语法中忘记闭合引号 ',会产生明显的错误:

>> A = 'hi
??? A = 'hi
        |
Error: A MATLAB string constant is not terminated properly.

未闭合的字符串会被标记为红色,提示你字符串未被正确结束,否则很容易忽略这个错误。

一个常见的字符串错误是试图使用 == 来比较字符串。如果两个字符串长度不同,这将不起作用,因为字符串在 MATLAB 中是字符数组,使用 == 比较数组时要求尺寸一致。正确的方式是使用 strcmp 函数:

>> 'AA' == 'AaA'
??? Error using ==> eq
Matrix dimensions must agree.

>> strcmp('AA', 'AaA')
ans = 0

>> strcmp('A', 'a')
ans = 0

>> strcmp('AA', 'AA')
ans = 1

注意:MATLAB 字符串是区分大小写的,'A' 和 'a' 被视为不同字符串

还需注意的是,字符串的起止符 ' 与转置操作符是同一个字符。如果你关闭了一个字符串却没开启新字符串,MATLAB 可能会认为你在进行转置操作,如果变量未定义就会报错,或者导致其他不可预期的行为。


其他杂项错误

你不能在语句结尾留下未完成的函数或表达式,例如:

>> A = 1+3+
??? A = 1+3+
            |
Error: Expression or statement is incomplete or incorrect.

这种错误通常很容易发现,往往是因为忘了添加续行符 ...

:: 并不是唯一的“意外 MATLAB 运算符”,还有 ...... 等打字错误也会导致此类错误。

如果不小心打了反引号 ` 会报错:

>> `

Error: The input character is not valid in MATLAB statements or expressions.

这通常是因为你想打数字 1 却按错了键。还有一种情况是你给 .m 文件取了计算机不支持的名字,比如德语的 "ä, ü, ö"。请使用常规字母命名文件,并避免使用大写字母。


函数调用错误

你可能会试图调用不存在的函数,比如:

>> samplemat = [1 2; 1 4];
>> A = eigen(samplemat);
??? Undefined command/function 'eigen'.

这可能是因为你不知道该功能的正确函数名。例如,如果你想计算矩阵的特征值,应使用 eig 而不是 eigen。此时使用 MATLAB 帮助文档(菜单:Help → Product Help 或命令行输入 doc)来搜索你想要的功能非常有用。

如果你调用的是你自己写的函数而出错,可能有以下原因:

  1. .m 文件不在当前目录或 MATLAB 路径下(检查 File → Set Path);

  2. .m 文件名必须与函数定义中的名字一致。如果你改了函数名,也必须改文件名,否则 MATLAB 无法正确找到该函数。

MATLAB 找到函数后会尝试运行,但调用函数时还可能遇到以下问题:

  • 必须清楚函数需要的输入输出参数数量和类型。内置函数的说明可以通过如下方式查看:

>> help functionname

你也可以为自己写的函数添加注释,让 help 命令能读取它们。注意:help 只会读取函数定义下方的连续注释

function outvars = myfunc(invars)
% function outvars = myfunc(invars)
% Outputs outvars
% All of this is outputted when you type >> help myfunc 

% 这一行不会显示在 help 中

保存为 myfunc.m 后,运行:

>> help myfunc

将输出你写的注释说明。

大多数函数都至少需要一个输入参数,输入不足会报错:

>> A = ode45()
??? Error using ==> ode45
Not enough input arguments.  See ODE45.

输入过多也会报错:

>> A = plus(1,2,3)
??? Error using ==> plus
Too many input arguments.

输入参数格式必须符合函数预期。比如 ode45 和其他微分方程求解器的第一个参数必须是函数句柄,顺序错误也会报错。

函数输出的变量数量也要注意:

>> A = [1,2;3,4];
>> D = eig(A);          % 一个输出
>> [V,D] = eig(A);      % 两个输出
>> [V,D,Mistake] = eig(A);
??? Error using ==> eig
Too many output arguments.

输出变量数量不能超过函数定义的最大返回数。如果你用这些结果去替换已有数组中的部分元素,还需要注意输出变量的类型是否匹配(详见赋值相关内容)。


控制流错误

最常见的控制流错误是漏写 end。在 M 文件函数中尤其常见,MATLAB 会提示你“至少缺少一个 END”,并试图指出缺失位置。

如果你写了太多的 end,并且一个 M 文件中有多个函数,MATLAB 会报一些莫名其妙的格式错误。这是因为一个 M 文件中的所有函数要么都用 end 结尾,要么都不用。如果某个函数多写了一个 end,MATLAB 会误以为函数提前结束,从而在下一个函数处找不到正确结尾,导致混乱。

如果你在发布(比如生成 HTML 文件)时遇到格式混乱的提示,可能是代码缩进层级不一致。可尝试全选代码后按 Ctrl+I 自动缩进修复。

switch 语句中多写了一个 end,MATLAB 会报“非法使用 case”,因为它以为 switch 已经结束,而 case 在外部是无效的。


其他错误

还有很多不被编译器立即识别的错误,比如调用错误的函数、使用错误的变量、操作错误、进入死循环等。这些错误最难发现,但可以使用 MATLAB 的调试器(Debugger)来排查。参见调试 M 文件(Debugging M Files)部分。


错误预判与规划

无论代码多么严谨,总会有出错的可能。调试技巧非常有用,而在某些情况下预判可能的错误也非常重要。例如:

if x < 5
    % 做某件事
elseif x > 5
    % 做另一件事
end

在循环中加入 if mod(ii, 5) == 0 之类的条件,只在特定迭代中执行某些操作,也有助于提前发现潜在错误。

有些错误直到循环较晚阶段才出现,例如 xy 少一个元素,导致 x .* y 报错。这种错误通常发生在最后一个元素,很难察觉。可以使用 try-catch 结构来处理:

try
    % 执行代码
catch me
    disp(me.getReport)
end

如果错误不是致命的,代码甚至可以继续执行,并通过信息提示或转换为警告。


有用的 MATLAB 工具/函数:

  • warning:生成警告;

  • lastwarn:查看最近警告;

  • disp:打印信息;

  • try-catch:异常处理;

  • dbstack:查看调用栈;

  • rethrowthrowAsCaller:重新抛出异常;

  • MATLAB 帮助文档可查看每个函数的使用方式与优劣。



最后修改: 2025年04月16日 星期三 11:57