跳转到内容

MATLAB 编程/错误消息

来自维基教科书,开放的书籍,开放的世界



据我所知,很少有资料可以帮助人们解读 MATLAB 的错误消息。大多数语法错误一旦你知道原因就不难修复,因此本指南旨在帮助识别和修复 MATLAB 代码中的错误。

警告也在这里显示,因为它们通常会导致以后出现错误。

算术错误

[编辑 | 编辑源代码]

通常这些是自我解释的。作为提醒,以下是一些常见的无法执行的函数以及 MATLAB 返回的内容(以及每个函数的警告)

a/0 = Inf if a > 0, -Inf if a < 0, and NaN if a = 0.
log(0) = -Inf
MATLAB defines 0^0 to be 1.

NaN 经常会导致错误或无用的结果,除非采取措施避免传播它们。

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

因此,检查表达式中所有项的维度。通常是索引错误导致项大小不同。如果你使用的是幂函数,你可能会在参数后添加一个点。即 y=x.^2 而不是 y=x^2

矩阵乘法要求第一个矩阵的列数等于第二个矩阵的行数。否则,你会收到以下消息

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

注意此错误与上一个错误的区别。此错误通常发生是因为索引问题,或者因为你打算使用逐元素乘法,但忘记了点。

尝试对奇异矩阵求逆将导致警告和一个 Inf 矩阵。在尝试求逆之前明智的做法是计算行列式,或者更好的是,使用不需要求逆的方法,因为求逆在数值上不稳定。

尝试对非方阵求幂将导致以下错误

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

这通常是因为你打算使用逐元素求幂,但忘记了点。

数组索引错误

[编辑 | 编辑源代码]

数组索引是 MATLAB 的关键组成部分。一项功能是变量和函数的名称区分大小写,并且可以将内置或用户编写的函数与相同名称的变量别名。因此,如果你创建一个名为 abs 的数组,并尝试调用函数 abs(1),MATLAB 将返回数组 abs 中的第一个值,而不是值 1。MATLAB 不会为此返回错误,因为它无法确定函数的别名是否为有意为之。因此,永远不要将你的变量命名为与现有 MATLAB 函数相同。不幸的是,基础产品加上已安装的工具箱中有如此多的提供函数,记住所有这些是不可能的,所以如果你有任何疑问,该名称可能在定义新数组或函数之前已经使用过,请使用which proposedname。较新版本的 MATLAB 具有命令完成功能,将在打开括号或制表符完成选项后显示简短的帮助信息,使用该功能将有助于在执行过程中避免此类错误,因为不会在以后创建别名。

有些事情是相当明显的,但需要一些实践来避免

你无法尝试访问尚未存在的数组部分。

>> A = [1,3];
>> A(3)
??? Index exceeds matrix dimensions.

不幸的是,如果有多个变量,MATLAB 不会告诉你超过维度的哪个变量,所以你必须检查它。例如,如果你使用循环来更改访问数组的哪一部分,但循环没有在到达数组末尾之前停止,就会经常发生这种情况。如果你最终得到一个空矩阵作为某个操作的结果,然后尝试访问其中的元素,也会发生这种情况。

你无法尝试访问数组的负数、复数、非整数或零部分;如果你这样做,你会收到以下消息

>> 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. 

后者是一个表达式,解析方式不同,因此在错误消息中具有实际的数组。

还要注意,如果 0 是一个逻辑 0(假),那么语句 A(0) 将不是索引错误,而是一个逻辑下标表达式。在这种情况下,返回值将是空[]数组,因为在已定义的 [1 2] 集合中没有匹配假的下标,因为 A 已经在上面定义了。一个更有用的表达式类似于

>> A(A==3)

尝试在你的索引中使用非标准 MATLAB 语法,通常会导致以下错误

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

上面的代码可能是试图访问 A 的第一个之后的所有行和第二列,在这种情况下,你应该使用“end”语法,例如

>> A(2:end, 2)
ans = 3

赋值错误

[编辑 | 编辑源代码]

啊,赋值,就是使用 = 符号为变量或数组的某些元素赋予特定值。

让我们从一个经典的错误开始

>> a = 2;
>> if a = 3
??? if a = 3
         |
Error: The expression to the left of the equals sign is not a valid target for an assignment.

此错误发生是因为你本来是想查看“a”是否等于 3,但你告诉 MATLAB 将“a”的值设置为 3。你不能在 if/while 语句所在同一行上执行此操作。正确的语法是

>> if a == 3
>> end

这不会产生任何错误(并且你可以在条件中放入你想要的任何内容)。

你不能在普通数组中包含两种不同类别的数据。例如,

>> A = @(T) (1+T)
A = 
   @(T) (1+T)
>> A(2) = 3
??? Conversion to function_handle from double is not possible.

为此目的,你应该使用元胞数组或结构体数组。

这是最棘手的。看看下面的代码

>> 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。在这三个例子中,维度不匹配。如果你想替换现有变量的特定部分,它们必须匹配。并不重要,只要它们具有相同数量的数据点(如第三个例子所示);维度也必须相同,例外是如果你在一侧有一个 1xn 数组,而在另一侧有一个 nx1 数组,MATLAB 将自动转置并为你替换

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

如果你不希望这样,请注意它!

结构体数组错误

[编辑 | 编辑源代码]

结构体数组相当复杂,它们对你可以做和不能做的事情有一套严格的规则。让我们首先处理结构体数组中的索引。假设你定义变量“cube”,并希望在一个结构体数组中存储两个不同立方体的体积和一侧的长度。这可以通过以下方式完成

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

这似乎是存储数据的不错方法,而且对于某些目的来说确实如此。但是,假设你想要从结构体中提取体积并将它们存储在一个数组中。你无法以这种方式执行此操作

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

你会注意到,如果你告诉 MATLAB 显示cube.volume,它会显示这两个值,但在每次重新分配变量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;

这样可以避免使用循环来输入对所有立方体都通用的公式。

语法错误

[编辑 | 编辑源代码]

括号错误

[编辑 | 编辑源代码]

与 C++ 不同,您不需要在每行代码的末尾添加任何东西,只需要换行符。但是,您仍然需要遵循语法规则。在 MATLAB 中,您必须格外小心地放置括号,以确保 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 会尝试告诉您缺少的括号应该放在哪里,但它并不总是正确。因此,对于复杂的表达式,您必须仔细检查才能找到您的拼写错误。一个有用的技巧是尝试在出错行之后设置一个断点。在纠正错误之前,它不会变红,因此请不断尝试纠正错误并保存文件,直到该断点变红。当然,之后您必须确保括号的放置合理,否则您可能会遇到其他与无效索引或无效函数调用相关的错误。

字符串错误

[编辑 | 编辑源代码]

您可以通过两种方式创建字符串:使用 '字符串' 语法,或者在两个词之间只添加空格(不包括换行符),例如

>> save file.txt variable

在这行代码中,file.txtvariable 被作为字符串传递给 save 函数。偶尔会忘记括号,并意外地尝试将字符串传递给不接受字符串作为输入的函数,这会导致错误

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

这些错误应该很容易发现,因为字符串是用紫色颜色编码的。如果取消注释一行文本并忘记更改它,就会发生这种情况。

在另一种字符串语法中,忘记关闭 ' 会导致明显的错误

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

未终止的字符串用红色颜色编码,以便让您知道它没有终止,因为很容易忘记。

使用字符串时,一个常见的错误是尝试使用 '==' 运算符比较它们。如果字符串的长度不同,这将不起作用,因为字符串是字符数组,要使用 '==' 比较数组,它们的大小必须相同。要比较两个字符串,必须使用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 文件。例如,在德国,“ä, ü 或 ö”。请确保您的 m 文件只使用常见的字母,并且不要使用大写字母。

函数调用错误

[编辑 | 编辑源代码]

您很有可能尝试调用一个不存在的函数,例如

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

这可能是因为您不知道执行预期操作的函数的名称(例如,如果您想计算矩阵“samplemat”的特征值,您想调用 eig,而不是 eigen)。打开 MATLAB 的帮助(转到帮助 -> 产品帮助或在命令提示符中键入 doc)并搜索您想要的操作通常很有用。

如果您尝试调用创建的函数,但收到此错误,可能有几个原因

  1. m 文件必须位于文件 -> 设置路径中列出的路径之一中,或者必须位于您的当前目录中
  2. m 文件的名称必须与函数声明中的名称相同。您必须特别注意这一点,尤其是当您更改函数的名称时,您还必须更改文件的名称,否则 MATLAB 找不到正确的函数!

如果 MATLAB 找到了函数,它将尝试运行它。但是,在调用函数时,有几个潜在的陷阱需要避免。为了调用函数,您需要了解给定函数的输入和输出参数的性质。对于 MATLAB 的内置函数,此信息可在文档中找到,或者通过键入

>> help functionname

最好设置一些注释,以便帮助函数也能读取您自己的代码中的注释,这样您就可以快速参考所有函数的工作原理以及它们的作用。为此,请注意,帮助函数只读取函数声明下方的注释块,因此,例如,如果您编写这样的函数

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

% But this wouldn't be

将函数保存为“myfunc.m”,然后键入

>> help myfunc

它将输出

>> function outvars = myfunc(invars)
Outputs outvars
All of this is outputted when you type >> 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 和其他 ODE 求解器中的第一个参数必须是函数句柄;如果您以错误的顺序传递参数,您将收到一条关于此错误的信息。

您可以使用方括号符号选择想要从可用输出参数中获取的输出参数数量。您可以选择保存比函数提供的更少的输出参数,但您不能分配比函数能输出的参数更多的变量

>> A = [1,2;3,4]
D = eig(A); %one output argument
[V,D] = eig(A); %two output arguments
[V,D,Mistake] = eig(A);
??? Error using ==> eig
Too many output arguments.

如果您要替换已存在数组的部分内容,则所有分配的输出参数也必须具有正确的类(有关此内容的更多信息,请参阅关于赋值的部分)。如果您使用输出创建新变量,这不是问题。

控制流错误

[编辑 | 编辑源代码]

迄今为止最常见的一个是,如果您忘记了 'END',这是 M 文件函数中的一个问题。它会告诉您“至少缺少一个 END”,并尝试告诉您循环或条件语句从哪里开始。

如果您有太多 END 语句,并且在同一个 M 文件中有多个函数,MATLAB 可能会给您一个关于函数格式不正确的模糊消息。这是因为同一个 M 文件中的所有函数必须都以 END 语句结束,或者都不以 END 语句结束。这无关紧要,但是如果您在一个函数中有很多 END 语句,MATLAB 会认为您的函数提前结束了,并且当下一行中的下一个函数在末尾没有 END 语句时,它会感到困惑。因此,如果您收到此令人困惑的消息,请查找额外的 END 语句,它应该可以解决您的问题。如果在发布时显示该消息(例如发布到 HTML 文件),则问题可能是层次结构缩进不规则。尝试选择所有内容,然后按 cntrl-i 以进行自动缩进,以解决问题。

在 'switch' 语句中有一个额外的 END 会导致一条消息,指出您非法使用了 'case' 关键字,因为 MATLAB 认为您提前结束了 switch 语句,并且 'case' 在 'switch' 语句之外没有意义。

其他错误

[编辑 | 编辑源代码]

有许多类型的错误不会从 MATLAB 编译器生成错误,这些错误与调用错误的函数、使用错误的操作、使用错误的变量、引入无限循环等有关。这些错误将是最难修复的,但借助 MATLAB 调试器,将更容易找到它们。有关如何使用调试器的详细信息,请参阅调试 M 文件

检测或计划错误

[编辑 | 编辑源代码]

无论代码多么精确,错误都可能发生。使用调试技术可以提供很大帮助,但计划错误或预计错误也同样宝贵。这包括创建一个可能不需要的 if 块来决定要做什么。例如,如果 x < 5 就执行操作 A,如果 x > 5 就执行操作 B。另外,在大型循环中添加一个带模运算符的 if 块,例如:if not ( mod ( ii , 5 ) ) % 执行操作; end。这样,循环只会在 ii 计数器可以被 5 整除时执行测试。一些语法错误或逻辑错误会在循环运行很长时间后发生,如果发生错误,就会显示错误信息,解释错误发生的位置,但不一定说明错误发生的原因。例如,向量 x 比向量 y 少一个元素,而 x .* y 无法执行。这种错误通常发生在最短向量的最后一个元素上,除非采取措施,否则很难发现。try % 执行操作; catch me me.getReport; 在这种情况下,断点和 even disp(me.getReport) 都会很有帮助。如果错误不是致命的,代码甚至可以继续执行,但会将错误显示为消息或转换为警告。

包含的 Matlab 工具/函数:warning, lastwarn, disp, try catch, dbstack, rethrow, throwAsCaller 和 Matlab 关于上述函数的帮助,以发现每种方法的优缺点。

华夏公益教科书