【问题标题】:Use array initializer as static array使用数组初始化器作为静态数组
【发布时间】:2014-01-07 14:31:03
【问题描述】:

是否可以将数组初始值设定项用作数组(有点像字符串文字?)

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

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

(这段代码显然行不通。

我想出了以下解决方案(绕过这个要求)

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

使用结构的全局实例。但是,尝试使用时:

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

我无法打印(出现分段错误)

【问题讨论】:

    标签: c arrays segmentation-fault


    【解决方案1】:

    是的,有点,但你必须给你的数组一个类型。从 C99 开始,我们有了复合文字:

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

    这为数组提供了const 限定类型(语法上类似于强制转换)。类型是const-qualified,因此编译器对如何分配数组的约束较少(如果必须)。允许为数组的所有使用分配一个静态副本。

    但如果你只按照TETRAMINO_C[0][0] 中的说明使用它,现代 C 编译器的体面优化器应该能够完全优化数组并且只直接使用常量。

    【讨论】:

    • 这完全无关紧要,01 对于 charunsigned char 都是有效值。段错误的真正原因是字节转换为char** 他实际上将二维数组中的一些字符值解释为指向更多字符的指针。
    • @KrzysztofKosiński,这是对真正问题的回答(第一行)。您正在修复他寻找不同解决方案的尝试。
    • 代码可以编译,所以不是类型错误。您的修改可能会删除编译时警告,但它不会修改代码的行为,也没有解决 OP 观察到的段错误的原因。
    • @KrzysztofKosiński,问题是“是否可以将数组初始值设定项用作数组”。
    • 好的,我好像有点误解了这个问题。
    【解决方案2】:

    问题在于char[2][4] 没有描述与char ** 相同的内存布局。第一个是char 的连续二维数组,而第二个是指向char 的指针数组的指针。您最终将字符值视为指针,这当然会导致地址无效和段错误。

    为了使代码正常工作,newMino->blocks 指针必须是 char *[4] 类型,而不是 char ** 类型。像这样定义它:

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

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

    【讨论】:

    • 我最终使用了这个解决方案,但考虑到 initial 问题,另一个似乎更合适,将另一个标记为答案。有什么建议吗?
    猜你喜欢
    • 1970-01-01
    • 2011-05-25
    • 2013-09-22
    • 2016-10-28
    • 2011-04-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多