【问题标题】:char* truncated when assigned as struct memberchar* 在分配为结构成员时被截断
【发布时间】:2015-09-16 01:12:08
【问题描述】:

我有一个具有以下 typedef 的结构。

typedef struct {
    short cmdLength;
    char cmdRequest[126];
} cmdRequest_t;

然后我在主程序中有以下代码。

char *command = "d tcpip\0";
printf("command: %s\n", command);
size_t cmdLen = strlen(command);
printf("size: %zu\n", cmdLen);
cmdRequest_t cmdRequest = {(short) cmdLen, *command};
printf("size: %hi\n", cmdRequest.cmdLength);
printf("command: %s\n", cmdRequest.cmdRequest);

但是,我的输出如下。

command: d tcpip
size: 7
size: 7
command: d

大小仍然正确,但由于某种原因命令被截断为一个字母。知道为什么会这样吗?

【问题讨论】:

  • #define COMMAND "d tcpip" 然后使用COMMAND 而不是*command
  • @BLUEPIXY:这很难看,OP 可能正在动态获取字符串...
  • @Alex 字符串文字不需要显式的 NULL (\0) 终止符 - 如果您不这样做,它们会正确地以空值终止。

标签: c pointers struct


【解决方案1】:

会发生什么……

cmdRequest_t cmdRequest = {(short)cmdLen, *command};

这会将cmdRequest 的成员cmdRequest 初始化为command 的解引用,或者换句话说,您将得到字符串中的第一个字符。在那之后你实际上没有有零太容易了,所以printf() 不起作用。如果您更改了一些不相关的内容,您可能会完美地得到这样的输出......

command: d%$232!>~11cCV224
mysh: program received SIGSEGV, Segmentation fault

改为这样做...

#include <string.h> 

cmdRequest_t cmdRequest;
cmdRequest.cmdLength = (short)cmdLen;
strncpy(cmdRequest.cmdRequest, command, sizeof(cmdRequest.cmdRequest) - 1);

【讨论】:

  • @user3386109:啊,抱歉……已编辑!
【解决方案2】:

使用 strcpy 而不是简单的赋值

将取消引用的 char 指针分配给数组时,只读取第一个 char

【讨论】:

    【解决方案3】:

    command 是指向char 的指针。

    它是用一个字符串常量初始化的,这意味着它是一个指向该字符串第一个字符的指针,即'd'

    如果您取消引用指向char 的指针,您将得到它指向的单个char,因此*command 的计算结果为'd'

    您正在初始化一个结构,它是 C 中的“聚合类型”,该结构的第二个成员是一个数组,它也是一个“聚合类型”。

    C90 在第 6.5.7 节“初始化”中说

    否则,具有聚合类型的对象的初始值设定项应该是一个用大括号括起来的聚合成员的初始值设定项列表,以递增的下标或成员顺序编写;并且具有联合类型的对象的初始化程序应该是联合的第一个成员的大括号括起来的初始化程序。

    如果聚合包含聚合或联合的成员,或者联合的第一个成员是聚合或联合,则规则递归地应用于子聚合或包含的联合。如果子聚合或包含联合的初始化程序以左大括号开头,则由该大括号及其匹配的右大括号包围的初始化程序初始化子聚合的成员或包含联合的第一个成员。否则,仅从列表中获取足够多的初始化器来考虑子聚合的成员或包含的联合的第一个成员;剩下的任何初始化器都将用于初始化当前子聚合或包含的联合所属的聚合的下一个成员。

    你的结构初始化器用大括号括起来,所以该初始化器中的初始化器按顺序初始化结构成员cmdLengthcmdRequest,因此它将cmdLength初始化为cmdlen并将cmdRequest初始化为'd'.

    cmdRequest 是一个聚合,但它的初始化器不在大括号中,因此“只考虑列表中足够的初始化器来考虑子聚合的成员”,因此 cmdRequest[0] 被初始化为 'd'

    如果要将cmdRequest 初始化为command 指向其第一个成员的数组,则必须使用strcpy:

    cmdRequest_t cmdRequest;
    cmdRequest.cmdLen = (short) cmdLen;
    strcpy(cmdRequest.cmdRequest, command);
    

    很抱歉,但这就是您在使用字符串不是真正数据类型的语言时得到的结果......

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-10-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-20
      • 2022-01-02
      相关资源
      最近更新 更多