【问题标题】:Can't use scanf in variable 2d array不能在可变二维数组中使用 scanf
【发布时间】:2026-01-12 03:40:01
【问题描述】:

我有一个任务要求我创建一个 N*N 数组,然后用从 1 到 N^2 的数字填充数组。之后我必须检查数组是否是魔方,但这不是我的问题。我已经尝试了所有方法,但无法填充数组; scanf 会一直运行下去。

正如你在截图中看到的,在第一个scanf中,假设我按2回车,变量n变成了2,所以必须创建一个名为msquare[2][2]的数组。但是当涉及到第二个 scanf 时,有些东西不能正常工作,它让我永远打字。我真的很感激一些帮助。另外,如果问题与指针有关,请尽量解释清楚,因为我仍然不熟悉它们并且不能完全理解它们。

这是一个例子:

int n;
int i;
int j;

scanf("%d", &n);

int msquare[n][n];   

for (i=0; i<=n; i++)
    {
        for (j=0; j<=n; j++){
            scanf("%d",msquare[i][j]);
        }
    }

【问题讨论】:

  • 请在此处复制代码并发布一个最小的可执行示例。谢谢。
  • 请不要显示文字图片。改为显示文本。
  • 欢迎来到 *!请在问题本身中将代码作为文本发布。阅读tourHow do I ask a good question? 可能会让您受益
  • 至少scanf("%d", msquare[i][j]) -> scanf("%d", &amp;msquare[i][j])。但是你没有显示的代码可能还有更多问题。
  • 请注意,C 中惯用的 for 循环的形式为 for (int i = 0; i &lt; maximum; i++)。 (如果您需要循环外的变量并预先定义变量,则可以省略 int。)如果您修复了 scanf() 问题,则使用 for (i = 0; i &lt;= n; i++) 的循环将写入数组边界之外,从而造成严重破坏你的程序。

标签: c arrays scanf


【解决方案1】:

您的代码中需要解决三个问题。

第一个是不能基于未初始化的变量创建数组!

例如,你不能这样做:

int main() {
    int n;
    int m[n][n];
    return 0;
}

只需确保在数组声明之前初始化变量,如下所示:

int main() {
    int n = 2;
    int m[n][n];
    return 0;
}

由于您从 scanf 调用中获得了 n 的值,因此您可以简单地这样写:

int main() {
    int n;
    scanf("%d", &n);
    int m[n][n];
    return 0;
}

但如果scanf 因某种原因失败,您可能会遇到麻烦。 处理这个问题的正确方法是检查scanf 的值。

int main() {

    int n;

    if (sscanf("%d", &n) != 1) {
        printf("Failed to get a matrix size from stdin\n");
        return 1;
    }

    int m[n][n];

    return 0;
}

有时将变量初始化为合理的值是个好主意。 在这种情况下,0 将是一个不错的选择。

int main() {

    int n = 0;

    if (scanf("%d", &n) != 1) {
        printf("Failed to get matrix size!\n");
        return 1;
    }

    int m[n][n];

    return 0;
}

虽然在某些情况下保持变量未初始化很有用,但这超出了此答案的范围。

此时添加检查以确保您的第一个输入变量不超过 8 的值可能是个好主意。

第二个问题是你的 for 循环。

你正在循环一个你应该做的额外迭代。

例如这段代码:

int n = 2;
for (int i = 0; i <= n; n++) {
  printf("i = %d and n = %d\n");
}

打印:

0 2
1 2
2 2

看看它是如何进行 3 次而不是 2 次的?您应该使用 &lt; 运算符而不是 &lt;= 运算符来解决此问题。

您的循环(两者)最终应该看起来像这样:

for (int i = 0; i < n; i++) {
    for (int j = 0; j < n; j++) {
    }
}

最后一个问题是您第二次致电scanf。此函数接受一个指针(就像您在第一次调用中所做的那样),但您在第二次调用中将其传递给一个整数。

scanf("%d", m[i][j]);

您需要添加&amp; 使其成为指针。

scanf("%d", &m[i][j]);

修复这些问题,您的代码应该可以正常运行。

【讨论】:

  • int m[n][n]; 被称为 variable length array 并在 C99 中引入,但在 C11 中成为可选功能。 MS Visual C 从未支持它,但显然 OP 的编译器允许它。
  • 啊,我一直以为它是编译器扩展,而不是标准的一部分。
  • 感谢您的帮助,我做了您提到的所有事情,但由于某种原因,我仍然遇到与以前完全相同的问题
  • @WeatherVane 已修复。
  • @tay10r 现在好像可以了,我忘了在 j
【解决方案2】:

请注意,C 中惯用的 for 循环的格式为

for (int i = 0; i < maximum; i++)

(如果您需要循环外的变量并预先定义变量,则可以省略int。)

该问题的某些版本有scanf("%d", msquare[i][j]); 没有&amp;,而某些版本有scanf("%d", &amp;msquare[i][j]);&amp; 的版本是正确的。

scanf() 问题修复后,您的循环使用

for (i = 0; i <= n; i++)

导致代码访问数组边界之外,对您的程序造成严重破坏。记住:如果你声明了一个数组msquare[5][5],那么你可以通过msquare[4][4]访问元素msquare[0][0]——任何比4更大的索引(或负索引)都可以越界访问数组。既然你定义了msquare[n][n],你就不能使用比msquare[n-1][n-1]更大的东西,但是你的循环控制意味着你试图访问msquare[n][n](写成msquare[i][j],但是当i == n || j == n时访问越界)。

您正在调用未定义的行为,所以一切皆有可能。许多可能性之一是您用您的输入之一覆盖n 的值,因此它不是2 而是38 或您输入的任何内容,因此您的循环花费的时间比您预期的要长得多。没有人能确定这就是正在发生的事情——未定义的行为可以做任何事情。但这是一个半合理的解释。

【讨论】:

  • 感谢您的回复,您能否向我解释一下我的循环是如何写到数组边界之外的?我读了你的解释,但还是不明白怎么回事
  • @Thanos 假设您有 3 个抽屉,编号从 0 到 2。如果您尝试将某些东西放入 3 号抽屉会发生什么?
  • 假设您为n 输入8。该数组可以从0 索引到7,但您的循环将它从0 索引到8。有 no 元素 [8].