【问题标题】:New to C, Return pointer to 2D arrayC新手,返回指向二维数组的指针
【发布时间】:2015-11-05 11:48:19
【问题描述】:

我一直在尝试将程序从 Java 转换为 C,它是手表的模拟器并显示我正在使用 Ascii 艺术的时间。我已将所有数字 (0-9) 存储在 2D 字符数组 (fx. 9) 中:

char nine[7][5] = {
    { '0', '0', '0', '0' },
    { '0', ' ', ' ', '0' },
    { '0', ' ', ' ', '0' },
    { '0', '0', '0', '0' },
    { ' ', ' ', ' ', '0' },
    { ' ', ' ', ' ', '0' },
    { ' ', ' ', ' ', '0' }
};

我现在有一个函数,它的任务是转换存储在 int 数组中的时间(fx. 22:04:59,将在数组中存储为 220459)。该函数应该为每个数字返回相应的 Ascii 艺术,以便我最终可以调用打印时间(以 ascii 形式)的函数,该函数采用 6 个 char[][] 参数。

所以简而言之,我需要知道用哪 6 个参数来调用这个函数:

void printScreen(char hourFirstDigit[7][5], char hourSecondDigit[7][5], char minuteFirstDigit[7][5], char minuteSecondDigit[7][5], char secFirstDigit[7][5], char secSecondDigit[7][5])

在 java 中,我的解决方案是简单地创建一个返回 char[][] 数组的函数,然后是 10 种情况 (0-9) 的 switch 语句,(这里是前几行):

char timeToAsciiArt[][](int digitNumber, int small) {
switch (timeRightNow[digitNumber]) {
    case 0:
    return zero;
}

可能的解决方案: 我已经读到那里至少有两种可能的问题解决方案(通常),1.用指向数组的指针替换。 2. 用结构包装。

我的想法: 1.我真的不知道如何返回一个指向数组的指针(有人可以解释一下如何以 case 0: 为例吗?:)

【问题讨论】:

  • char (*timeToAsciiArt(int, int))[7][5] {switch(/**/){case 0: return &zero;}}。或者:char (*timeToAsciiArt(int, int)[5] {switch(/**/){case 0: return zero;}}
  • 非常感谢,我最终使用了您的解决方案 :)。

标签: c arrays pointers return-type


【解决方案1】:

据我了解,您希望:

  • 为您的 ASCII 艺术提供某种存储方式;
  • 一个函数,它接收一个数字并将一些指针返回到相应的 ASCII 艺术存储;
  • 接收一组 ASCII 艺术并打印它们的函数。

存储 ASCII 艺术

将您的 ASCII 艺术包装到一个结构中可能是明智的,因为您可以存储更多关于它的数据。也许将来你会想要一个更薄的1 数字;您需要存储有关每个 ASCII 艺术作品大小的数据:

struct ascii_digit {
    unsigned int width;
    unsigned int height;
    char[MAX_HEIGHT][MAX_WIDTH] art; //Here you could instead use a pointer
                                     //instead of storing directly
}

当然,如果您绝对不打算使用固定大小以外的东西,那么数组就可以了。


找到正确的 ASCII 艺术作品

在 C 中传递数组时,通常不会直接传递数组:通常使用指向它的指针。所以你的函数的正确原型不会是

char time_to_ascii_art[][](int digit_number, int small);

但是,如果你使用结构

struct ascii_digit* time_to_ascii_art(int digit_number, int small);

请注意,我们返回一个指向结构的指针。虽然绝对可以直接传递结构,但这可能不是一种好的做法,因为它会根据结构的大小产生一些开销。

或者您可以使用指向 char 的指针的简单方法:

char* time_to_ascii_art(int digit_number, int small);

请注意,如果您有一个指向二维数组的 char* 指针,则在尝试访问其内容时必须自己进行数学运算。例如,访问xth 行的yth 成员:array[width * x + y]。为了避免这样做,您可以使用指向数组的指针:

char (*time_to_ascii_art)(int digit_number, int small)[ASCII_ART_WIDTH];

在此函数中,您可以像在 Java 中那样使用 switch … case 语句(使用结构的示例):

// Let's say that your structures are declared in the global scope as ascii_zero, ascii_one…
struct ascii_digit* time_to_ascii_art(int digit_number, int small)
{
    switch(digit_number) {
        case 0:
          return ascii_zero;
        case 1:
          return ascii_one;
        default:
          return NULL;
    }
}

或者你可以——这在 Java 中也可能是一个好主意——有一个包含你的 ASCII 艺术或指向它们的指针的数组,索引以便访问 nth 成员将为你提供数字的 ASCII 艺术n

// Let's now say you have an ascii_digits array of structs containing your digits
struct ascii_digit* time_to_ascii_art(int digit_number, int small)
{
    return ascii_digits + digit_number; // You should handle bad values.
    // ascii_digits being an array, it is implicitly cast to a pointer here.
}

将 ASCII 艺术传递给显示函数

现在要将您的 ASCII 艺术传递给您的显示函数,您可以(取决于您选择的数据类型)使用指向结构的指针:

void print_screen(struct ascii_digit* hour_first_digit, …);

指向char的指针:

void print_screen(char* hour_first_digit, …);

或指向字符数组的指针:

void print_screen(char (*hour_first_digit)[ASCII_ART_WIDTH], …);

【讨论】:

    【解决方案2】:

    我建议采用以下方法。

    定义一个函数,该函数将包含具有静态存储持续时间的图像数组。

    例如

    char ( * )[7][5] get_image( size_t i )
    {
        static char images[10][7][5] = 
        {
            //...
            {
                { '0', '0', '0', '0' },
                { '0', ' ', ' ', '0' },
                { '0', ' ', ' ', '0' },
                { '0', '0', '0', '0' },
                { ' ', ' ', ' ', '0' },
                { ' ', ' ', ' ', '0' },
                { ' ', ' ', ' ', '0' }
            }
        };
    
        const size_t N = sizeof( images ) / sizeof( *images );
    
        return i < N ? images[i] : NULL;
    }
    

    或者如果函数有返回类型char ( * )[5]可能会更好

    例如

    char ( * )[5] get_image( size_t i )
    {
        static char images[10][7][5] = 
        {
            //...
            {
                { '0', '0', '0', '0' },
                { '0', ' ', ' ', '0' },
                { '0', ' ', ' ', '0' },
                { '0', '0', '0', '0' },
                { ' ', ' ', ' ', '0' },
                { ' ', ' ', ' ', '0' },
                { ' ', ' ', ' ', '0' }
            }
        };
    
        const size_t N = sizeof( images ) / sizeof( *images );
    
        return i < N ? images[i][0] : NULL;
    }
    

    然后编写一个函数,该函数将在一个结构中返回一个包含 6 个元素和相应数字的数组。这些元素将作为调用函数get_image的参数。

    这就够了。

    【讨论】:

      【解决方案3】:

      在 C 中,数组一个指针。当你传递一个参数时,它总是通过副本,所以当你“发送”一个数组时,你发送的是指针的副本,而不是数组的副本。

      结构是按值复制的(如intfloat...),并且可以包含在静态数组中:

      typedef struct {
        char tab[7][5];
      }Digit;
      

      因此您可以创建变量:Digit zero, one, two… 并为其设置值:zero.tab[0][0] = ' ';。你可以将它传递给函数或返回它,它会被复制。

      现在处理指针(我认为更好,因为您不需要 复制这些数组):数组仍然是指针。但是“静态”二维数组有点奇怪(它不是数组数组)。正如 EOF 在评论中提到的那样,您的数组实际上是 (*)[5]。所以导致匹配所有类型有点复杂:

      char (*select_digit(int val))[5] {
        if (value == 0) return zero;
        if (value == 1) return one;
        …
      }
      

      你的printScreen 函数是一样的。 要存储此 select_digit 函数返回的指针,您必须像这样声明它:

      char (*tmp)[5];
      tmp = select_digit(5);
      printScreen(tmp, …);
      

      【讨论】:

        【解决方案4】:

        您使用数组和指针的想法或多或少会转化为:

        char (* timeToAsciiArt(unsigned timeNow[6], unsigned digitNumber) )[5] {
            static char asc0[7][5] = { //fill in };
            static char asc1[7][5] = { //fill in };
            switch (timeNow[digitNumber]) {
            case 0:
                return asc0;
            case 1:
                return asc1;
            ...
         }
        

        然后您可以将返回的艺术传递给print_screen by

        unsigned timeNow[] = {1, 2, 3, 4, 5, 6};
        char (*first_digit)[5] = timeToAsciiArt(timeNow, 0);
        printScreen(first_digit, ... , );
        

        或直接

        printScreen( timeToAsciiArt(timeNow, 0) , ...);
        

        最后,这说明用struct 包装会获得更易读的代码。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-06-11
          • 1970-01-01
          • 2021-08-23
          • 1970-01-01
          • 1970-01-01
          • 2016-05-08
          • 1970-01-01
          相关资源
          最近更新 更多