1

Is it possible to use an array initializer as an array (sort of like a string literal?)

#define TETRAMINO_I {{1,1,1,1},{0,0,0,0}}

printf("%c",(TETRAMINO_I[0][0]) ? "#" : ' ');

(This code obviously doesn't work.

I have come up with the following solution (bypassing this requirement)

#define TETRAMINO_I {{1,1,1,1},{0,0,0,0}}
#define TETRAMINO_J {{1,1,1,0},{0,0,1,0}}
#define TETRAMINO_L {{1,1,1,0},{1,0,0,0}}
#define TETRAMINO_O {{1,1,0,0},{1,1,0,0}}
#define TETRAMINO_S {{0,1,1,0},{1,1,0,0}}
#define TETRAMINO_T {{1,1,1,0},{0,1,0,0}}
#define TETRAMINO_Z {{1,1,0,0},{0,1,1,0}}

typedef unsigned char byte;

typedef struct tetraminos{
    char I[2][4];
    char J[2][4];
    char L[2][4];
    char O[2][4];
    char S[2][4];
    char T[2][4];
    char Z[2][4];

}tet_minos_t;

tet_minos_t tet_mino_blocks{ TETRAMINO_I,TETRAMINO_J,TETRAMINO_L,TETRAMINO_O,TETRAMINO_S,TETRAMINO_T,TETRAMINO_Z};

Using a global instance of a struct. However, when trying to use:

newMino->blocks = (char**)tet_mino_blocks.I;
printf("%c",(newMino->blocks[0][0]) ? "#" : ' ');

I am unable to print (get segmentation fault)

2 Answers 2

2

Yes, kind of, but you have to give your array a type. Since C99 we have compound literals:

#define TETRAMINO_C ((unsigned char const[][4])TETRAMINO_I)

This gives the array a const-qualified type (syntactically similar to a cast). The type is const-qualified, so the compiler is less constraint on how to allocate the array, if it has to. It is allowed to just allocate one static copy for all your uses of the array.

But if you only use it as indicated in TETRAMINO_C[0][0] a decent optimizer of a modern C compiler should be able to optimize the array completely out and to only use the constants directly.

Sign up to request clarification or add additional context in comments.

5 Comments

This is completely irrelevant, 0 and 1 are valid values for both char and unsigned char. The real cause of the segfault is that byt casting to char** he is actually interpreting some character values from a 2D array as a pointer to more characters.
@KrzysztofKosiński, this is an answer to the real question (first line). You are fixing his attempt to find a different solution.
The code compiles, so it is not a type error. It is possible that your modification removes a compile-time warning, but it does not modify the behavior of the code and does not address the cause of the segfault the OP is observing.
@KrzysztofKosiński, the question is "Is it possible to use an array initializer as an array".
OK, seems like I misunderstood the question a little.
1

The problem is that char[2][4] does not describe the same memory layout as char **. The first is a contiguous two-dimensional array of char, while the second is a pointer to an array of pointers to char. You end up treating the character values as a pointer, which of course results in an invalid address and a segfault.

In order for the code to work correctly, the newMino->blocks pointer has to be of type char *[4], not of type char **. Define it like this:

struct ... {
    char (*blocks)[4];
};

or

typedef char[4] tetromino_col_t;
struct ... {
    tetromino_col_t *blocks;
};

1 Comment

I ended up using this solution, but as the other seems more appropriate given the initial problem, marked the other as the answer. Any suggestions?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.