【问题标题】:How to properly initialize a string如何正确初始化字符串
【发布时间】:2011-07-26 19:34:16
【问题描述】:

我将如何为以下函数定义以下字符串?

到目前为止,我收到了警告:

C4047: '=' : 'const char' differs in levels of indirection from 'char [4]'

和错误:

C2166: l-value specifies const object.

都在下面代码的第三行:

uint8_t *buffer= (uint8_t *) malloc(sizeof(uint32_t));
const char *stringaling= (const char *) malloc(sizeof(uint32_t));
*stringaling = "fun";
newval = protobuf_writeString (buffer, stringaling);

uint32_t protobuf_writeString(uint8_t *out,const char * str)
{

      if (str == NULL)
      {
          out[0] = 0;
          return 1;
      }
      else
      {
          size_t len = strlen (str);
          size_t rv = uint32_pack (len, out);
          memcpy (out + rv, str, len);
          return rv + len;
      }
}

【问题讨论】:

  • 你为什么使用sizeof(unit32_t)
  • @Michael 你推荐我用什么
  • 这取决于你想要做什么。正如你现在的代码,我不明白你为什么要分配一个 32 位整数大小的字符串。

标签: c string function


【解决方案1】:
const char *stringaling= (const char *) malloc(sizeof(uint32_t));
*stringaling = "fun";

这不是有效的代码。您正在尝试分配一个 const 变量,这是非法的。然后你试图将一个字符数组分配给一个字符。最后,即使你有一个大小合适的非常量字符数组,你仍然不能分配数组,因为它们不是一等值。

【讨论】:

    【解决方案2】:

    尝试使用

    char *stringaling = malloc(sizeof(uint32_t));
    strcpy(stringaling, "fun");
    

    ...相反,看看这是否效果更好。但是请注意,(至少通常)sizeof(uint32_t) 恰好是保持“乐趣”的正确尺寸是非常偶然的。你通常不想这样做。

    或者,您可能想要:

    char const *stringaling = "fun";
    

    或:

    char stringaling[] = "fun";
    

    但是你的任务是行不通的——C 对语言中内置的字符串只有非常最低限度的支持;大多数操作(包括复制字符串)通常通过库函数完成,例如 strcpy

    【讨论】:

      【解决方案3】:

      "fun" 是一个字符串文字,本质上是一个const char *

      stringaling 也是一个const char *,所以你的第三行试图将一个const char * 分配给一个const char,这不会飞。

      如果它是一个常量字符串,你可以这样做:

      const char *stringaling = "fun";
      

      如果你的输入字符串是动态的,你可以这样做:

      char *stringaling= (char *) malloc(strlen(inputString)+1);
      strcpy(stringaling, inputString);
      

      显然,如果你 malloc 它,你需要释放它,否则会感到愤怒的内存泄漏。

      【讨论】:

        【解决方案4】:

        如果你真的想初始化char *,你可以这样写:

        const char *stringaling = "fun";

        这里是some reference

        【讨论】:

          【解决方案5】:

          没有你也可以使用的所有东西:

          newval = protobuf_writeString (buffer, "fun" );
          

          【讨论】:

            【解决方案6】:

            第一个问题:

            const char *stringaling= (const char *) malloc(sizeof(uint32_t));
            

            这条线上有几个问题。

            首先,您不想将stringaling 声明为const char *;您将无法修改 stringaling 指向的任何内容(IOW,*stringaling 将不可写)。这很重要,因为您想将另一个字符串的内容复制到stringaling 指向的位置。删除 const 关键字。

            其次,malloc(sizeof(uint32_t)) 恰好为这个特定的字符串分配了足够的字节 (4),但不清楚您的意思是 分配 4 个字节。为数组分配内存时(字符串是数组),明确指出您打算分配的元素数量

            最后,转换 malloc 的结果在 C 中被认为是不好的做法。如果您忘记包含 stdlib.h 或在范围内没有 malloc 的原型,转换将抑制有用的诊断消息。从 1989 年标准开始,malloc 返回 void *,可以将其分配给任何其他对象指针类型,而无需强制转换。这在 C++ 中是不正确的,所以这里需要强制转换,但是如果你正在编写 C++,你应该使用 new 而不是 malloc

            所以,把那行改为阅读

            char *stringaling = malloc(LEN); // or malloc(LEN * sizeof *stringaling), but
                                             // in this case that's redundant since 
                                             // sizeof (char) == 1 
            

            其中 LEN 是您要分配的字符数。

            malloc 呼叫的一般形式是

            T *p = malloc (N * sizeof *p);
            

            其中T 是基本类型(intcharfloatstruct ... 等),N 是类型的元素 的数量T 你要分配。由于表达式*p的类型是T,所以sizeof *p == sizeof(T);如果您更改了p 的类型,您不必在malloc 调用本身中复制该更改。

            第二个问题:

            *stringaling = "fun";
            

            同样,有几个问题在起作用。首先,您不能使用= 运算符分配字符串值。字符串字面量是数组表达式,在大多数情况下,数组表达式的类型从“T 的 N 元素数组”隐式转换(“衰减”)到“指向 T 的指针”。您只需将指针分配给字符串中的第一个字符,而不是复制字符串文字的内容。

            除了你在作业中取消引用 stringaling 之外,哪个会“工作”(见下文);表达式*stringaling 的类型是const char(在进行了我上面指出的更改后的char),这与char * 类型的赋值不兼容。如果你放弃解引用运算符并写

            stringaling = "fun";
            

            您会修复编译时错误,但现在您遇到了另一个问题;如上所述,您还没有将字符串文字“fun”的内容复制到您使用malloc 分配的内存块中;相反,您只需将字符串文字的地址复制到变量stringaling。这样一来,您就会忘记动态分配的块,从而导致内存泄漏。

            为了将字符串 contents 从一个地方复制到另一个地方,您必须使用像 strcpystrncpymemcpy 这样的库函数,如下所示:

            strcpy(stringaling, "fun");
            

            如果stringaling 不需要驻留在堆上(例如,您只在单个函数中使用它并在返回之前释放它),您可以通过将其声明为常规数组来完全避免内存管理char 并用 "fun" 对其进行初始化:

            char stringaling[] = "fun"; 
            

            这是在声明中初始化数组而不是赋值表达式的特殊情况,因此= 确实将字符串文字的内容复制到stringaling 数组。但是,这只适用于数组声明。您可以稍后使用其他字符串值(最多 3 个字符加上 0 终止符)修改该数组,但您必须再次使用 strcpy

            strcpy(stringaling, "one");
            

            如果你不需要修改stringaling的内容,你可以这样做

            const char *stringaling = "fun";
            

            这会将字符串文字“fun”的地址复制到变量stringaling。并且由于尝试修改字符串文字的内容会调用未定义的行为,因此我们确实希望在这种情况下将stringaling 声明为const char *;这将防止您意外修改字符串文字。

            【讨论】:

              猜你喜欢
              • 2019-09-11
              • 1970-01-01
              • 1970-01-01
              • 2022-01-01
              • 2010-11-11
              • 1970-01-01
              • 2011-06-20
              • 2011-03-20
              • 1970-01-01
              相关资源
              最近更新 更多