【问题标题】:C char array initializationC char 数组初始化
【发布时间】:2013-09-12 09:29:20
【问题描述】:

我不确定通过以下方式初始化后 char 数组中的内容。

1.char buf[10] = "";
2.char buf[10] = " ";
3.char buf[10] = "a";

对于案例2,我认为buf[0]应该是' 'buf[1]应该是'\0',并且从buf[2]buf[9]将是随机内容。对于案例3,我认为buf[0]应该是'a'buf[1]应该是'\0',并且从buf[2]buf[9]将是随机内容。

对吗?

对于案例 1,buf 中的内容是什么? buf[0] == '\0' 和从buf[1]buf[9] 会是随机内容吗?

【问题讨论】:

  • 好吧,我的编译器不接受你的(更正后的)代码:“数组类型'char [10]'不可赋值”。
  • @MartinR 现在可以工作了...
  • @lkkeepmoving: char buf[10]; buf = "a"; not 编译。 - 请先尝试,然后将您的实际代码复制/粘贴到问题中。这为您和您问题的所有读者节省了大量工作。
  • @MartinR 抱歉。我以为我可以分配 buf[] 后者,但似乎不行。现在代码运行。

标签: c arrays char initialization buffer


【解决方案1】:

这不是你初始化数组的方式,而是:

  1. 第一个声明:

    char buf[10] = "";
    

    等价于

    char buf[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    
  2. 第二个声明:

    char buf[10] = " ";
    

    等价于

    char buf[10] = {' ', 0, 0, 0, 0, 0, 0, 0, 0, 0};
    
  3. 第三个声明:

    char buf[10] = "a";
    

    等价于

    char buf[10] = {'a', 0, 0, 0, 0, 0, 0, 0, 0, 0};
    

如您所见,没有随机内容:如果初始化器较少,则数组的剩余部分使用0 进行初始化。即使在函数内部声明了数组也是如此。

【讨论】:

  • 为了问这个问题的人,值得指出的是,C 标准要求任何部分完成的数组初始化都用零填充其余元素(由编译器)。这适用于所有数据类型,而不仅仅是char
  • @ouah 为什么 buf[] 末尾没有'\0'?
  • @lkkeepmoving 0'\0 具有相同的值。
  • @Pacerier char buff[3] = "abcdefghijkl"; 无效。 char p3[5] = "String"; 也无效。 char p[6] = "String"; 有效,与char p[6] = {'S', 't', 'r', 'i', 'n', 'g'}; 相同。
  • @delive 你是什么意思,它与这个答案有什么相关性?
【解决方案2】:
  1. 这些是等价的

    char buf[10] = "";
    char buf[10] = {0};
    char buf[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    
  2. 这些是等价的

    char buf[10] = " ";
    char buf[10] = {' '};
    char buf[10] = {' ', 0, 0, 0, 0, 0, 0, 0, 0, 0};
    
  3. 这些是等价的

    char buf[10] = "a";
    char buf[10] = {'a'};
    char buf[10] = {'a', 0, 0, 0, 0, 0, 0, 0, 0, 0};
    

【讨论】:

    【解决方案3】:

    编辑:在我提供此答案后,OP(或编辑器)在某个时候默默地将原始问题中的一些单引号更改为双引号。

    您的代码将导致编译器错误。您的第一个代码片段:

    char buf[10] ; buf = ''
    

    是双重非法的。首先,在 C 中,没有空的char 这样的东西。您可以使用双引号来指定一个空字符串,如:

    char* buf = ""; 
    

    这将为您提供一个指向 NUL 字符串的指针,即其中仅包含 NUL 字符的单字符字符串。但是您不能使用其中没有任何内容的单引号 - 这是未定义的。如果需要指定NUL字符,则必须指定:

    char buf = '\0';
    

    反斜杠对于消除字符 '0' 的歧义是必要的。

    char buf = 0;
    

    完成了同样的事情,但我认为前者读起来不那么模棱两可了。

    其次,您不能在定义数组后对其进行初始化。

    char buf[10];
    

    声明并定义数组。数组标识符buf 现在是内存中的地址,您无法通过赋值更改buf 指向的位置。所以

    buf =     // anything on RHS
    

    是非法的。因此,您的第二个和第三个代码片段是非法的。

    要初始化一个数组,必须在定义的时候进行:

    char buf [10] = ' ';
    

    会给你一个 10 字符的数组,第一个字符是空格 '\040',其余的是 NUL,即'\0'。当使用初始化器声明和定义数组时,具有指定初始值的数组元素(如果有)将自动填充0。不会有任何“随机内容”。

    如果你声明并定义了数组但没有初始化它,如下所示:

    char buf [10];
    

    您将在所有元素中包含随机内容。

    【讨论】:

    • "要初始化一个数组,你必须在定义的时候做..." 这和下面的行使它比接受的答案更好。
    【解决方案4】:

    C11 标准草案 n1570 6.7.9 初始化的相关部分说:

    14 字符类型的数组可以由字符串字面量或 UTF-8 字符串初始化 字面量,可选地用大括号括起来。字符串文字的连续字节(包括 如果有空间或数组大小未知,则终止空字符)初始化 数组的元素。

    21 如果大括号括起来的列表中的初始值设定项数少于元素或成员数 聚合,或 用于初始化已知数组的字符串文字中的更少字符 大小超过数组中的元素,聚合的其余部分应为 隐式初始化与具有静态存储持续时间的对象相同。

    因此,如果有足够的空间,将附加 '\0',其余字符将使用 static char c; 将在函数中初始化的值进行初始化。

    最后,

    10 如果具有自动存储时长的对象没有显式初始化,则其值为 不定。如果具有 static 或线程存储持续时间的对象未初始化 明确地,那么:

    [--]

    • 如果它具有算术类型,则将其初始化为(正或无符号)零;

    [--]

    因此,char 是一种算术类型,数组的其余部分也保证用零初始化。

    【讨论】:

      【解决方案5】:

      有趣的是,可以在程序中的任何时候以任何方式初始化数组,只要它们是structunion 的成员。

      示例程序:

      #include <stdio.h>
      
      struct ccont
      {
        char array[32];
      };
      
      struct icont
      {
        int array[32];
      };
      
      int main()
      {
        int  cnt;
        char carray[32] = { 'A', 66, 6*11+1 };    // 'A', 'B', 'C', '\0', '\0', ...
        int  iarray[32] = { 67, 42, 25 };
      
        struct ccont cc = { 0 };
        struct icont ic = { 0 };
      
        /*  these don't work
        carray = { [0]=1 };           // expected expression before '{' token
        carray = { [0 ... 31]=1 };    // (likewise)
        carray = (char[32]){ [0]=3 }; // incompatible types when assigning to type 'char[32]' from type 'char *'
        iarray = (int[32]){ 1 };      // (likewise, but s/char/int/g)
        */
      
        // but these perfectly work...
        cc = (struct ccont){ .array='a' };        // 'a', '\0', '\0', '\0', ...
        // the following is a gcc extension, 
        cc = (struct ccont){ .array={ [0 ... 2]='a' } };  // 'a', 'a', 'a', '\0', '\0', ...
        ic = (struct icont){ .array={ 42,67 } };      // 42, 67, 0, 0, 0, ...
        // index ranges can overlap, the latter override the former
        // (no compiler warning with -Wall -Wextra)
        ic = (struct icont){ .array={ [0 ... 1]=42, [1 ... 2]=67 } }; // 42, 67, 67, 0, 0, ...
      
        for (cnt=0; cnt<5; cnt++)
          printf("%2d %c %2d %c\n",iarray[cnt], carray[cnt],ic.array[cnt],cc.array[cnt]);
      
        return 0;
      }
      

      【讨论】:

        【解决方案6】:

        我不确定,但我通常将数组初始化为“” 在那种情况下,我不需要担心字符串的空端。

        main() {
            void something(char[]);
            char s[100] = "";
        
            something(s);
            printf("%s", s);
        }
        
        void something(char s[]) {
            // ... do something, pass the output to s
            // no need to add s[i] = '\0'; because all unused slot is already set to '\0'
        }
        

        【讨论】:

        • 您不应该真正使用 implicit int 规则。你应该为main()指定一个类型(你也应该使用void,即int main(void) { ... }。C99摆脱了这个规则,所以这段代码不会为C99及更高版本编译。这里要注意的另一件事是从 C99 开始,如果您在 main 中省略 return,则会在 main 末尾的 } 之前自动放置/隐含一个 return 0;。您正在使用隐式 int 规则,该规则仅在 C99 之前工作,但您正在使用仅适用于 C99 和更高版本的隐式return;这两者显然是矛盾的。
        猜你喜欢
        • 1970-01-01
        • 2017-05-02
        • 1970-01-01
        • 2014-02-02
        • 2016-11-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-04-15
        相关资源
        最近更新 更多