【问题标题】:typedef fixed size array in c not working properlyc中的typedef固定大小数组无法正常工作
【发布时间】:2021-04-07 11:06:57
【问题描述】:

我有一个 char 数组的 typedef 来表示棋子的位置。

typedef char chessPos[2];

然而,当我尝试创建这种类型的数组时,我遇到了无法解释的行为。 例如。

  chessPos test= {'A','1'};
  chessPos test2= {'B','2'};
  chessPos* ptr = (chessPos*)(malloc(sizeof(chessPos) * 2));

  (*ptr)[0] = test[0];
  (*ptr)[1] = test[1];

  (*ptr+1)[0] = test2[0];
  (*ptr+1)[1] = test2[1];

  printf("(%c,%c)",*ptr[0],(*ptr)[1]);
  ptr++;
  printf("(%c,%c)",*ptr[0],(*ptr)[1]);

我会得到:

(A,B)(2, ) 

而不是预期的:

(A,1)(B,2)

【问题讨论】:

  • 运算符优先级。 *ptr+1 首先取消引用,然后添加。
  • OT:我更喜欢更具可读性和抗错误性的 chessPos* ptr = malloc(sizeof *ptr * 2); 分配。

标签: arrays c pointers typedef


【解决方案1】:

这是因果报应:编写非常奇怪的代码,宇宙会给你非常奇怪的错误作为报复......

您在运算符优先级方面遇到了几个问题。像这样修复它:

#include <stdio.h>
#include <stdlib.h>

typedef char chessPos[2];

int main (void)
{
  chessPos test= {'A','1'};
  chessPos test2= {'B','2'};
  chessPos* ptr = (chessPos*)(malloc(sizeof(chessPos) * 2));

  (*ptr)[0] = test[0];
  (*ptr)[1] = test[1];

  (*(ptr+1))[0] = test2[0];
  (*(ptr+1))[1] = test2[1];

  printf("(%c,%c)",(*ptr)[0],(*ptr)[1]);
  ptr++;
  printf("(%c,%c)",(*ptr)[0],(*ptr)[1]);
}

但是,您应该通过删除 typedef 并改用多维索引来挽救这个不可读的代码:

#include <stdio.h>
#include <stdlib.h>

int main (void)
{
  char test[2]= {'A','1'};
  char test2[2]= {'B','2'};
  char (*ptr)[2] = malloc( sizeof(char[2][2]) );

  ptr[0][0] = test[0];
  ptr[0][1] = test[1];
  ptr[1][0] = test2[0];
  ptr[1][1] = test2[1];

  printf("(%c,%c)",ptr[0][0],ptr[0][1]);
  ptr++;
  printf("(%c,%c)",ptr[0][0],ptr[0][1]);
}

始终避免将指针和数组隐藏在 typedef 后面!

【讨论】:

  • 我同意第二个例子比 o.p. 干净得多。但是,我不同意您对 typedef 的看法。在 O.P. typedef 断言所有数组定义具有相同数量的元素。在您的回答中,请计算您实际硬编码“2”值的次数。除此之外,您的第二个示例也应该可以维护 typedef。
  • @pqans 这只是一个愚蠢的例子,在实际代码中你显然会使用命名常量。使用 typedef 的理由很糟糕。
  • 是的,我同意您关于不在 typedef 后面隐藏数组的评论。可悲的是,这是他们指定写成这样的学校练习。
【解决方案2】:

为什么不使用结构体而不是数组?

#include <stdio.h>
#include <stdlib.h>

typedef char figureCoordinate_t;

typedef struct{
    figureCoordinate_t x;
    figureCoordinate_t y;
} figurePos_t;

void printFigurePos(figurePos_t *pos)
{
   printf("(%c, %c)", pos->x, pos->y); 
}

int main (void)
{
    figurePos_t testpos1 = {'A', '1'};
    figurePos_t testpos2 = {'B', '2'};
    figurePos_t *ptr = (figurePos_t*)malloc(2*sizeof(*ptr));

    ptr[0].x = testpos1.x;
    ptr[0].y = testpos1.y;

    ptr[1].x = testpos2.x;
    ptr[1].y = testpos2.y;

    printFigurePos(ptr);
    ++ptr;
    printFigurePos(ptr);

    free(ptr); // This was missing in the o.p.
}

【讨论】:

  • 不知道初始化代码可以参考Lundin(sizeof *ptr)所示方式的定义。我认为这是一个好主意,因此就接手了。
  • "为什么不使用结构体而不是数组?"因为这意味着你会得到额外的填充。假设您出于某种原因想要连续分配。
  • 1 的填充是否是硬性要求取决于目标系统的内存限制。这可能是一个论据。另一方面,该结构可能会被游戏中人物的一些其他属性扩展。您如何使用数组而不为每个大小和偏移量定义命名常量?此外,结构对齐为 1 是可能的(使用 C11,alignas)
【解决方案3】:

首先要考虑到指针ptr 的类型是char ( * )[2]

让我们考虑这些表达式语句

  (*ptr+1)[0] = test2[0];
  (*ptr+1)[1] = test2[1];

表达式*ptr 的类型是char[2],表达式产生动态分配的二维数组的第一行。

在表达式中使用的数组指示符 *ptr 被隐式转换(极少数例外)为指向其第一个元素的指针。

因此,子表达式*ptr+1 产生一个指向第一行第二个元素的指针。所以第一行的第二个元素设置为'B'

这个表达式(*ptr+1)[1]产生第二行的第一个元素,它被设置为2

第二行的第二个元素保持未初始化。

结果输出是

(A,B)(2, ) 

【讨论】:

    猜你喜欢
    • 2011-08-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-05
    • 2015-12-17
    • 1970-01-01
    • 1970-01-01
    • 2013-12-21
    相关资源
    最近更新 更多