简体   繁体   English

C的新手,返回指向2D数组的指针

[英]New to C, Return pointer to 2D array

I've been trying to convert a program from Java to C, it's a emulator of a watch and to display the time I'm using Ascii art. 我一直在尝试将程序从Java转换为C,它是手表的模拟器,并显示我使用Ascii艺术的时间。 I have stored all the numbers (0-9) in 2D char arrays (fx. 9): 我已将所有数字(0-9)存储在2D字符数组(fx.9)中:

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

I now have a function which job is to convert the time stored in a int array (fx. 22:04:59, would be stored as 220459 in the array). 我现在有一个函数,其作用是转换存储在int数组中的时间(fx.22:04:59,将在数组中存储为220459)。 The function should return the corresponding Ascii art to each digit, so that I finally can call the function that prints the time (in ascii form) that takes 6 char[][] parameters. 该函数应该将相应的Ascii art返回给每个数字,这样我最终可以调用打印时间(以ascii形式)的函数,该函数需要6个char [] []参数。

So in short, I need to know which 6 parameters to call this function with: 所以简而言之,我需要知道调用此函数的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])

In java my solution was simply to make a function that returned a char[][] array, and then a switch statement for the 10 cases (0-9), (here's the first few lines): 在java中,我的解决方案只是创建一个返回char [] []数组的函数,然后是10个案例(0-9)的switch语句,(这里是前几行):

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

Possible solution: I've read that there where at least two possible solutions to the problem (in general), 1. Replace by a pointer to an array. 可能的解决方案:我已经读过那里至少有两个可能解决问题的方法(一般来说),1。用指向数组的指针替换。 2. Wrap with a struct. 2.用结构包装。

My thoughts on: 1. I'm really not sure how I would return to a pointer to an array (could someone explain how to do this with case 0: as an example? :) 我的想法:1。我真的不确定如何返回指向数组的指针(有人可以用案例0来解释如何做到这一点:作为一个例子吗?:)

I am suggesting the following.approach. 我建议如下。方法。

Define a function that will contain an array of the images with static storage duration. 定义一个函数,该函数将包含具有静态存储持续时间的图像数组。

For example 例如

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;
}

Or maybe it will be better if the function has return type char ( * )[5] 或者如果函数有返回类型char ( * )[5]会更好

For example 例如

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;
}

Then write a function that will return in a structure an array of 6 elements with corresponding digits. 然后编写一个函数,它将在结构中返回一个包含相应数字的6个元素的数组。 These elements will serve as arguments to call function get_image . 这些元素将作为调用函数get_image参数。

That is enough. 足够了。

As I understand, you wish to have : 据我了解,您希望:

  • Some kind of storage for your ASCII art ; 您的ASCII艺术的某种存储;
  • A function which receives a digit and return some pointer to the corresponding ASCII art storage ; 接收数字并返回指向相应ASCII艺术存储的指针的函数;
  • A function which receives a set of ASCII arts and prints them. 一个接收一组ASCII艺术并打印它们的函数。

Storing the ASCII art 存储ASCII艺术

It could be wise to wrap your ASCII art into a structure, since you could then store more data about it. 将ASCII艺术包装到结构中可能是明智之举,因为您可以存储更多关于它的数据。 Perhaps in the future you will want to have a thinner 1 digit ; 也许在将来你会希望有一个更薄的1位数; you would need to store data about the size of each ASCII art : 您需要存储有关每个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
}

Of course if you absolutely don't plan on having something other than a fixed size, arrays are fine. 当然,如果你绝对不打算使用固定大小以外的其他东西,阵列就可以了。


Finding the correct ASCII art 找到正确的ASCII艺术

When passing arrays around in C, you usually do not pass the array directly : you usually use a pointer to it. 在C中传递数组时,通常不直接传递数组:通常使用指向它的指针。 So a correct prototype for your function would not be 所以你的功能的正确原型不会

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

but rather, if you use structures 但是,如果你使用结构

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

Note that we return a pointer to a structure. 请注意,我们返回一个指向结构的指针。 While it is absolutely possible to directly pass a structure, it may not be considered good practice as it induces some overhead depending on the size of your structure. 虽然绝对可以直接传递结构,但它可能不被认为是好的做法,因为它会根据结构的大小引起一些开销。

or you can use a naïve approach using pointers to char : 或者你可以使用一个天真的方法使用指向char指针:

char* time_to_ascii_art(int digit_number, int small);

Note that if you have a char* pointer to a bidimensional array, you will have to do the math by yourself when trying to access its contents. 请注意,如果您有一个指向二维数组的char*指针,则在尝试访问其内容时,您必须自己进行数学运算。 For example, accessing the y th member of the x th row : array[width * x + y] . 例如,访问第x行的第y个成员: array[width * x + y] To spare yourself from doing this, you can use pointers to arrays : 为了避免这样做,您可以使用指向数组的指针:

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

In this function you could either use a switch … case statement like you did in Java ( example using structures ) : 在这个函数中,您可以像在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;
    }
}

or you could — which would also probably be a good idea in Java — have an array containing your ASCII arts, or pointer to them, indexed so that accessing the n th member will give you the ASCII art for the digit n : 或者你可以 - 在Java中也可能是一个好主意 - 有一个包含你的ASCII艺术的数组,或指向它们的指针,索引,以便访问第n个成员将为你提供数字n的ASCII艺术:

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

Passing the ASCII arts to the display function 将ASCII艺术传递给显示功能

Now to pass your ASCII arts to your display function you can — depending on the datatype you chose — use either pointers to structures : 现在将您的ASCII艺术传递给您的显示功能,您可以 - 根据您选择的数据类型 - 使用指向结构的指针:

void print_screen(struct ascii_digit* hour_first_digit, …);

pointers to char : 指向char指针:

void print_screen(char* hour_first_digit, …);

or pointers to array of chars : 或指向字符数组的指针:

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

In C an array is a pointer. 在C中,数组指针。 When you pass a parameter it is always by copy, so when you "send" an array you send a copy of a pointer, not a copy of the array. 传递参数时,它总是通过复制,因此当您“发送”数组时,您会发送指针的副本,而不是数组的副本。

Structs are copied by value (as int , float …), and can have inside a static array: 结构按值复制(如intfloat ...),并且可以包含静态数组:

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

So you can create variables: Digit zero, one, two… and set values into it: zero.tab[0][0] = ' '; 所以你可以创建变量: Digit zero, one, two…并设置值: zero.tab[0][0] = ' '; . And you can pass it to functions or return it, it will be copied. 你可以将它传递给函数或返回它,它将被复制。

Now for dealing with pointers (better in my opinion as you don't need to duplicate these arrays): an array is still a pointer. 现在处理指针(在我看来更好,因为你不需要复制这些数组):数组仍然是一个指针。 But "static" 2D arrays are a bit strange (it is not an array of arrays). 但“静态”2D数组有点奇怪 (它不是数组数组)。 As mentionned in comment by EOF your arrays are in fact (*)[5]. 正如EOF在评论中提到的那样,你的数组实际上是(*)[5]。 So it lead to something a little bit complicated to match all the types: 因此,匹配所有类型会导致一些有点复杂的事情:

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

Your printScreen function is the same. 您的printScreen功能是相同的。 To store a pointer returned by this select_digit function you have to declare it like this: 要存储由此select_digit函数返回的指针,您必须将其声明为:

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

Your idea of using arrays and pointers would more or less translate to : 您使用数组和指针的想法或多或少会转化为:

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

You can then pass the returned art to print_screen by 然后,您可以将返回的作品传递给print_screen

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

or directly 或直接

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

In the end, this serves to say that wrapping in a struct will gain you a much more readable code. 最后,这可以说在struct中包装将获得更易读的代码。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM