为什么此非空终止的字符串正确打印

时间:2019-04-03 05:36:35

标签: c string initialization c-strings

昨天,我进行了单元测试。程序之一是复制字符串并找出没有字符串功能的长度。这是我写的代码:

#include <stdio.h>

int main(){
    char str1[100], str2[100] = {'a'};

    printf("Enter a string\n");
    fgets(str1, sizeof(str1), stdin);

    int i;
    for(i = 0; str1[i] != '\0'; i++){
        str2[i] = str1[i];
    }   

    str2[i] = '\0';

    printf("Copied string = %s", str2);

    printf("Length of string = %d", i-1);
}

我有一个令人惊讶的发现!即使注释了str2[i] = '\0',该字符串也可以正确打印,即在初始化时没有多余的'a',据我所知不应覆盖。

评论str2[i] = '\0'之后,我希望看到以下输出:

test
Copied string = testaaaaaaaaaaaaaaaaaaaaaaaaaaa....
Length of string = 4

这是输出:

test
Copied string = test
Length of string = 4

str2如何正确打印?编译器可以识别字符串的复制并静默添加空终止符吗?我正在使用gcc,但是clang也会产生类似的输出。

2 个答案:

答案 0 :(得分:8)

Python 2.7.5 Django 1.11.14 Mysql Server version: 5.5.60-MariaDB MariaDB Server 不能用100个重复的a填充str2[100] = {'a'};。只是将str [0]设置为“ a”,其余设置为零。

最早回到C89:

  

3.5.7初始化

     

...

     

语义学

     

...

     

如果具有静态存储持续时间的对象未初始化   显式地,它隐式地初始化,就像每个具有   算术类型分配了0,每个成员都具有指针类型   被分配了一个空指针常量。如果对象具有   自动存储持续时间未显式初始化,其值为   不确定。/65/

     

...

     

如果列表中的初始化程序少于的成员,则   聚合,聚合的其余部分应初始化   隐式地与具有静态存储持续时间的对象相同。

答案 1 :(得分:3)

首先,对聚合类型的初始化规则 [1] ,引用C11,第6.7.9章(强调我的

  

初始化应以初始化程序列表的顺序发生,为特定子对象提供的每个初始化程序都将覆盖先前为同一子对象列出的所有初始化程序; 151)所有未明确初始化的子对象应与与以下对象相同的对象隐式初始化:具有静态存储期限。

  

如果未明确初始化具有静态或线程存储持续时间的对象,则:

     
      
  • 如果具有指针类型,则将其初始化为空指针;

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

  •   
  • 如果是聚合,则根据这些规则初始化(递归)每个成员,并将任何填充初始化为零位;

  •   
  • 如果是联合,则将根据这些规则(递归地)初始化第一个命名成员,并将任何填充初始化为零位;

  •   

现在,像这样的初始化语句

char str2[100] = {'a'};

将根据上述规则,将str2[0]初始化为'a',并使用str2[1]str2[99]初始化为0。该0值是 strings 的空终止符。

因此,您在那里存储的,小于数组长度的所有值,直到length-1元素,都将自动以null终止。

所以,您可以将数组用作 string 并获得预期的字符串行为。


[1]:汇总类型:

根据6.2.5 / P21

  

[...]数组和结构类型统称为集合类型。