New in C, Returns a pointer to a 2D array

I am trying to convert a program from Java to C, it is a clock emulator and show the time when I use Ascii art. I saved all numbers (0-9) in 2D char arrays (fx. 9):

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

Now I have a function whose task is to convert the time stored in the int array (fx. 22:04:59, will be stored as 220459 in the array). The function should return the corresponding Ascii art for each digit, so finally, I can call the function, which prints the time (in the form of ascii), which takes 6 char [] [] parameters.

In short, I need to know which 6 parameters to call this function:

 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 to simply create a function that returned a char [] [] array, and then a switch statement for 10 cases (0-9) (here are the first few lines):

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

Possible solution: I read that where there are at least two possible solutions to the problem (in general), 1. Replace the pointer with an array. 2. Wrap with a frame.

My thoughts on: 1. I'm really not sure how I will return to the pointer to the array (can someone explain how to do this with case 0: as an example? :)

+5
source share
4 answers

I suggest the following. Approach.

Define a function that will contain an array of images with a static storage duration.

for instance

 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 would be better if the function has a return type of char ( * )[5]

for instance

 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 returns an array of 6 elements with the corresponding numbers to the structure. These elements will serve as an argument to the get_image call get_image .

It's enough.

+2
source

As I understand it, you want:

  • Some kind of repository for your ASCII art;
  • A function that receives a digit and returns some pointer to the corresponding ASCII store,
  • A function that receives an ASCII art set and prints them.

Conservation of ASCII Art

It would be wise to wrap your ASCII art in a structure, since then you could store more data about it. You might want to get a finer number 1 in the future; you will need to store the size data of each ASCII art:

 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 anything other than a fixed size, the arrays are fine.


Finding the Right ASCII Art

When passing arrays to C, you usually don't pass the array directly: you usually use a pointer to it. Thus, the correct prototype for your function will not be

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

but if you use structures

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

Note that we are returning a pointer to a structure. Although it is absolutely impossible to directly transfer a structure, it cannot be considered good practice, since it causes some overhead depending on the size of your structure.

or you can use a naive approach with char pointers:

 char* time_to_ascii_art(int digit_number, int small); 

Note that if you have a char* pointer for a two-dimensional array, you will have to do the math yourself when trying to access its contents. For example, access to the yth member of the string x th: array[width * x + y] . To get rid of this, you can use pointers for arrays:

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

In this function, you can either use the switch … case , as in Java (an example using structures):

 // Let 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 probably be a good idea in Java to have an array containing your ASCII arts, or a pointer to them indexed so that access to the n th element gives you ASCII art for the digit n :

 // Let 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 ASCII Art to a Display Function

Now, to pass your ASCII skills to your display function, you can - depending on the data type you choose - either use pointers to structures:

 void print_screen(struct ascii_digit* hour_first_digit, …); 

points to char :

 void print_screen(char* hour_first_digit, …); 

or pointers to an array of characters:

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

In C, an array is a pointer. When you pass a parameter, it is always copied, so when you "send" an array, you are sending a copy of the pointer, not a copy of the array.

Structures are copied by value (like int , float ...) and can have inside a static array:

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

So, you can create variables: Digit zero, one, two… and set values ​​in it: zero.tab[0][0] = ' '; . And you can pass it to functions or return it, it will be copied.

Now for working with pointers (better, in my opinion, since you do not need to duplicate these arrays): the array is still a pointer. But the β€œstatic” 2D arrays are a bit strange (this is not an array of arrays). As mentioned in the EOF comment, your arrays are actually (*) [5]. So this leads to something a bit complicated to fit all types:

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

Your printScreen function printScreen same. To save the pointer returned by this select_digit function, you must declare it as follows:

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

Your idea of ​​using arrays and pointers will 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; ... } 

Then you can pass the returned art to print_screen on

 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 suggests that the wrapper in the struct will give you much more readable code.

+1
source

Source: https://habr.com/ru/post/1235294/


All Articles