【问题标题】:Pass a 2D char array to a function in C将二维字符数组传递给 C 中的函数
【发布时间】:2023-03-06 07:36:01
【问题描述】:

我是一名初级程序员,对将二维数组传递给函数感到困惑。我认为这可能只是一个简单的语法问题。我一直在寻找答案,但我发现似乎没有任何帮助,或者超出我的水平而无法理解。

我将main函数中的数组和函数标识为,初始化后尝试调用:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

int const ROWS = 8;
int const COLS = 8;

int main(int argc, char** argv) {

char board[ROWS][COLS];

bool canReach(char board[][], int i, int j);

//initialize array

//values of i and j given in a for loop

canReach(board, i, j);

return (EXIT_SUCCESS);
}

在主函数之外编写函数时,我对它的定义与我在主函数中所做的完全相同。

bool canReach(char board[][], int i, int j){
//Functions purpose
}

当我尝试构建程序时,我两次收到此错误并且程序没有构建:

error: array has incomplete element type 'char[][]'
bool canReach(char board[][], int i, int j)
                        ^

请注意,我试图将整个数组传递给函数,而不仅仅是单个值。我能做些什么来解决这个问题?如果它不必使用指针,我将不胜感激,因为我发现它们很混乱。此外,我试图遗漏一些我认为不重要的东西,但我可能错过了我需要的东西,或者保留了我不需要的东西。感谢您花时间帮助这位初级程序员!

【问题讨论】:

  • 在 C 中,常量实际上是程序员保证不会改变的变量。对于诸如您的数组大小,将#define它们作为宏是更好的方法。请注意,这与 C++ 不同。
  • 请正确格式化您的代码。
  • 错误是指第二个[] 的数组(事物有多大)。因此,您必须至少为第一个[] 指定数组的大小。或者,您可以传递一个指向 0,0 和 2 个大小的指针。
  • 数组索引的类型应该是size_t

标签: c arrays multidimensional-array


【解决方案1】:

您可以将数组作为函数参数传递并定义其大小。

bool canReach(char board[ROWS][COLS], int i, int j);

当大小未知时,指针就是办法。

bool canReach(char* board, int i, int j);

你应该知道,数组!=指针但是指针可以存储数组的地址。

【讨论】:

  • 从我对 C 类的记忆中,指针是需要掌握的最重要的东西之一......
  • @LaurentS.: 是的,如果你对 C 语言中的指针不完全了解,你甚至不应该考虑编写旨在实际使用的代码。
  • 我认为这条评论帮助我更好地理解了指针。如果我要使用指针方法,那么在函数中,我是否会像在主函数中那样调用数组中的特定位置,即。 board[i][j];
  • 通过指针,您可以获得数组中第一个元素的地址。现在您必须进行一维工作,但要知道:所有元素都在行中。 F.e.给定数组 x[2][3] 在内存中 x[0][0], x[0][1], x[0][2], x[1][0], x[1][1 ], x[1][2].
  • @Youka 你的意思是在第二个例子中:bool canReach(char** board, int i, int j);bool canReach(char* board[], int i, int j);?使用char *board,您无法访问这样的二维数组board[0][0]
【解决方案2】:

这是一个演示程序

#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>

bool canReach( int n, int m, char board[][m] )
{
    for ( int i = 0; i < n; i++ )
    {
        for ( int j = 0; j < m; j++ )
        {
            board[i][j] = 0;
        }
    }

    return printf( "Hello SaarthakSaxena" );
}    

int main( void )
{
    const int ROWS = 8;
    const int COLS = 8;

    char board[ROWS][COLS];

    canReach( ROWS, COLS, board );

    return EXIT_SUCCESS;
}

它的输出是

Hello SaarthakSaxena

【讨论】:

    【解决方案3】:

    在 C 中不允许在另一个函数中定义一个函数(此处为:main)。这是某些编译器(例如 gcc)的扩展,但不应使用。

    您必须指定数组的维度。 C 数组没有 HLL 中的隐式大小信息。

    在 C 中使用 const variables 作为数组维度也不是一个好主意。而是

    #define ROWS 8
    #define COLS 8
    

    假设ij是数组中某个元素的索引,可以使用签名:

    bool canReach(size_t rows, size_t cols, char board[rows][cols],
            size_t i, size_t j);
    

    这允许将(运行时)可变大小的数组传递给函数。如果尺寸保证在运行时固定:

    bool canReach(char board[ROWS][COLS], size_t i, size_t j);
    

    但只有在使用上述宏时。它不适用于const 变量

    两个版本都告诉编译器数组有哪个维度,所以它可以计算每个元素的地址。第一个维度可能会被省略,但没有任何收获,它会禁止可选的边界检查(C11 选项)。请注意,一维案例char ca[] 只是此一般要求的特殊版本,您始终可以省略最左(/外)维度。

    注意,我将类型更改为(无符号)size_t,因为这是数组索引的适当类型,如果正确启用(强烈推荐),将生成转换警告。但是,您可以使用int,但必须确保没有值变为负数。

    提示:如果您打算在数组中存储非字符整数或对元素进行算术运算,则应指定 char 类型的有符号性。 char 可以是未签名的或签名的,具体取决于实现。所以使用unsigned charsigned char,这取决于你想要什么。

    【讨论】:

    • enum dim { ROWS=8, COLS=8 }; 更好:gdb 理解枚举并将打印ROWSCOLS 用于声明类型为enum dim 的变量,并执行enum dim x = 20; 行并打印其gdb 中的值将打印(unknown: 20)。作为调试帮助,(unknown: XXX) 输出非常适合捕获错误,例如超出数组末端的写入。
    • @ChronoKitsune: enum 常量默认为int,与枚举本身一样多。我 - 通常 - 不建议将 enum 用于不相关的常量,因为这意味着自然不存在的绑定:C 中的宏没有错;这不是 C++。 size_t 是最适合数组索引的类型。顺便提一句。 gdb 也知道这些简单的宏。您的方法意味着每个维度变量都可以获得ROWSCOLS,因此您实际上必须创建一个每个维度具有单个常量的枚举。不,抱歉,但我不同意。
    • "... 并在 gdb 中打印 its 值将打印..." 你的意思是 x 的“its”?我想我不明白你在这里的实际意思。请详细说明。据我所见,gdb 将为枚举的任何值输出(unknown: ...),没有定义常量。听起来没什么用,因为您不想为 每个 有效的索引值定义一个常量。
    • 假设你有一个 C 文件,里面有enum dim x = ROWS;print x 将显示“ROWS”而不是“8”(如果您愿意,可以使用 print /x ROWS 显示“0x8”)。如果您为x 分配一个未在enum dim 中指定的值,例如20,则print x 将显示(unknown: 20)。我的示例中有一个小缺陷,因为在这种情况下ROWSCOLS 指的是相同的值,但总的来说,当你有不同的常数时它会很好地工作。 #define ROWS 8 不是这种情况,因为print /x ROWS 将打印“当前上下文中没有符号“ROWS”。”
    • 它只会打印维度的精确匹配对于索引 0..7 它只会打印(有效!)值作为越界值。 OTOH,您有一个有符号整数作为维度,而不是无符号整数,因此 gcc 甚至无法警告转换问题。此外,没有人会阻止对索引使用不同的枚举(例如混淆行和列)。对于打印宏:嗯,这行得通,我每天调试我的嵌入式项目时都使用它,例如:print /x *SPI1 - SPI1 是一个宏。也许您只是没有将正确的 ELF 部分添加到您的对象中?
    猜你喜欢
    • 2013-02-27
    • 1970-01-01
    • 2021-05-27
    • 2015-05-27
    • 2021-05-10
    • 1970-01-01
    相关资源
    最近更新 更多