【问题标题】:Getting input for a 2 dimensional array in C在 C 中获取二维数组的输入
【发布时间】:2014-02-15 00:26:25
【问题描述】:

我是一个完整的 C 初学者,一两个星期前刚开始,我主要使用“C:现代方法”一书,我真的非常非常纠结于指针, 我正在尝试编写一个函数,提示用户逐行输入矩阵,即用户输入第 1 行,按 Enter 键等。

这是我目前的代码:

    for(int (*p)[M] = &a[0][0]; p <= &a[N-1][M-1]; p++)
    {
        scanf("%d", p);
    }

在过去的 5 个小时里,我一直在努力解决这个问题,我查看了许多网站,但找不到任何帮助。 新线的东西会影响这个吗? scanf 让我很困惑。 是否可以修改此代码以避免用户输入矩阵的维度?它可以以某种方式检测到换行符吗?

我知道错误肯定在于我对指针的理解,所以如果您对我可以用来全面研究它们的来源有任何建议,我将非常感激。 提前致谢。

【问题讨论】:

  • 是的,就是那个。我应该在明年的一门课程中学习 C(我是 EE 的大一新生),但这不符合我的学位计划。这是课程使用的书。
  • 仔细阅读第 11 章和第 12 章。他解释得很好。
  • 我知道是的,到目前为止我已经阅读了 2 遍,但我想这是因为我总是在 12 小时以上的天后这样做。谢谢。
  • scanf() 是正确使用的比较棘手的函数之一;它是微妙的,而且是无穷无尽的。您是否自己提出了问题中的代码?使用指向数组的指针是一项非常重要的练习,我认为您的代码应该在编译时带有一些关于类型不匹配的警告(在for 行和scanf() 行中)。
  • 这是我自己的,是的。编译器给了我一堆警告,我一直在尝试修复它们,但我并不真正理解这些警告,我只是对指针感到困惑。

标签: c arrays matrix scanf


【解决方案1】:

鉴于文件xx.c 中的以下代码(非常接近您在问题中显示的内容):

#include <stdio.h>

int main(void)
{
  enum { M = 4, N = 5 };
  int a[N][M];

  for(int (*p)[M] = &a[0][0]; p <= &a[N-1][M-1]; p++)
  {
    scanf("%d", p);
  }
  return 0;
}

GCC 4.8.2 编译器(在 Ubuntu 12.04 衍生版本上运行)说:

$ gcc -g -O3 -std=c99 -Wall -Wextra -Werror -c xx.c
xx.c: In function ‘main’:
xx.c:8:21: error: initialization from incompatible pointer type [-Werror]
   for(int (*p)[M] = &a[0][0]; p <= &a[N-1][M-1]; p++)
                     ^
xx.c:8:33: error: comparison of distinct pointer types lacks a cast [-Werror]
   for(int (*p)[M] = &a[0][0]; p <= &a[N-1][M-1]; p++)
                                 ^
xx.c:10:5: error: format ‘%d’ expects argument of type ‘int *’, but argument 2 has type ‘int (*)[4]’ [-Werror=format=]
     scanf("%d", p);
     ^
cc1: all warnings being treated as errors
$

第一个错误是因为p 是一个指向大小为M 的数组的指针,而&amp;a[0][0] 只是一个指向int 的指针。比较失败是类似的。你可以写:

for (int (*p)[M] = &a[0]; p < &a[N]; p++)

然后留下scanf() 错误待解决。问题在于您将指向数组的指针传递给需要指向int 的指针的函数。此外,由于数组指针增量的工作方式,您正试图为整行数据读取一个数字。如果你沿着这条路前进,你需要一个嵌套循环:

    for (int *q = &(*p)[0]; q < &(*p)[M]; q++)
        if (scanf("%d", q) != 1)
            ...process data format error...

另一方面,您可以通过以下方式简化您的生活:

for (int *p = &a[0][0]; p < &a[N][M]; p++)
    if (scanf("%d", p) != 1)
        ...process data format error...

如果您需要使用指针(指向int),我建议您采用这种方式。应尽可能避免使用指向数组的指针,这几乎是所有时间。

这两个变体在这里被封装到一个程序中,以及使用数组索引的代码(由comment 中的Jim Balter 建议),这是最简单且最难出错的:

#include <stdio.h>

extern void error(const char *msg);

int main(void)
{
  enum { M = 4, N = 5 };
  int a[N][M];

  // Pointers to arrays - nasty
  for (int (*p)[M] = &a[0]; p < &a[N]; p++)
  {
    for (int *q = &(*p)[0]; q < &(*p)[M]; q++)
    {
      if (scanf("%d", q) != 1)
        error("Bother");
    }
  }

  // Pointers to int - OK
  for (int *p = &a[0][0]; p < &a[N][M]; p++)
  {
    if (scanf("%d", p) != 1)
      error("Bother");
  }

  // Array indices - can't go wrong easily!
  for (int n = 0; n < N; n++)
  {
    for (int m = 0; m < M; m++)
    {
      if (scanf("%d", &a[n][m]) != 1)
        error("Bother");
    }
  }

  return 0;
}

【讨论】:

  • 我只是想用指针来做,因为有人特别告诉我,我已经知道如何用索引来做,而且要容易得多。非常感谢,它工作得很好,它帮助我更好地理解了指针。
  • 还有一件事是使用printf("name = %p", name); 来表示“名称”的各种值(例如指针p&amp;(*p)[M]),以确保您了解正在使用的值。此外,打印p+1(当p 是指向数组的指针时)可能很有见地;您还将在此主题上打印 a&amp;a&amp;a[0]&amp;a[0][0] 和其他变体。绘制数组a 的图片并确保您了解每个循环的工作原理。
猜你喜欢
  • 2021-12-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多