C char数组初始化


118

我不确定初始化后通过以下方式在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,会发生什么bufbuf[0] == '\0'buf[1]buf[9]将会是随机内容?


2
好吧,我的编译器不接受您的(更正后的)代码:“数组类型'char [10]'无法分配”。
Martin R

@MartinR现在它将起作用...
lkkeepmoving

1
@lkkeepmoving:char buf[10]; buf = "a";没有没有编译。-请先尝试一下,然后将您的实际代码复制/粘贴到问题中。这样可以为您和您的问题的所有读者节省很多工作。
Martin R

@MartinR对不起。我以为我可以将buf []分配给后者,但似乎没有。现在,代码开始运行。
lkkeepmoving

Answers:


222

这不是初始化数组的方式,但适用于:

  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。即使在函数内部声明了数组,也是如此。


45
为了方便人们提问,值得指出的是,C标准要求对其余部分元素(由编译器)用零填充任何部分完整的数组初始化。这适用于所有数据类型,而不仅仅是char
水稻

4
@ouah为什么buf []的末尾没有'\ 0'?
lkkeepmoving

14
@lkkeepmoving 0'\0具有相同的值。
哇,2013年

1
@lkkeepmoving初始化和赋值是两个不同的野兽,因此C让您可以提供一个字符串作为char数组的初始化程序,但是禁止数组赋值(如ouah所说)。
Lorenzo Donati-Codidact.com 2013年

3
@Pacerier char buff[3] = "abcdefghijkl";无效。char p3[5] = "String";也无效。char p[6] = "String";是有效的,并且与相同char p[6] = {'S', 't', 'r', 'i', 'n', 'g'};
ouah 2014年

28

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

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

char buf[10] ; buf = ''

是双重违法的。首先,在C语言中,没有Empty这样的东西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];

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


“要初始化一个数组,必须在定义时执行它……”这和下面的代码行比接受的答案要好。
Laurie Stearn

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

8

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

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

21 如果用大括号括起来的列表的初始化程序少于聚合中的元素或成员,或者用于初始化已知大小的数组的字符串文字中的字符少于该数组中的元素,则聚合的其余部分应该与具有静态存储持续时间的对象隐式初始化

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

最后,

10 如果未自动初始化具有自动存储期限的对象,则其值不确定。如果未明确初始化具有静态或线程存储持续时间的对象,则:

[-]

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

[-]

因此,char作为算术类型,还保证数组的其余部分用零初始化。


3

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

示例程序:

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

1

我不确定,但是在这种情况下,我通常将数组初始化为“”,因此我无需担心字符串的空结尾。

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'
}

您不应该真正使用隐式int规则。你应该指定一个类型main()(你也应该使用void,即int main(void) { ... },C99摆脱了这个规则,所以这段代码不会编译C99及更高版本。其他的事情,这里要注意的是,开始与C99,如果忽略return在main,在main的末尾有一个自动return 0;放置/隐含的控件,}您正在使用隐式int规则,该规则仅在C99之前可用,但是您在使用隐式int规则,该规则仅在returnC99和更高版本上起作用;这显然是矛盾的。
RastaJedi
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.