繁体   English   中英

在 clang 中用大括号括起来的列表初始化的 char 数组中的尾随符号是什么?

[英]What's the trailing symbols within an char array which initialized with brace-enclosed lists in clang?

#include <stdio.h>

int main(int argc, const char *argv[]) {
  char name1[] = {'f','o','o'};
  char name2[] = "foo";
  printf("%s\n", name1);
  printf("%s\n", name2);
  return 0;
}

运行上面的代码会导致:

foox\363\277\357\376
foo
Program ended with exit code: 0

那么,这两个初始化器有什么区别呢?

name1是一个由三个字符组成的数组{'f', 'o', 'o'}

name2是一个由四个字符组成的数组{'f', 'o', 'o', '\0'}

printf("%s", ...)需要一个以 null 字符结尾的数组。 因为name1不是,所以您开始取消引用超出数组末尾的字符,这可能具有传统的未定义行为。

第一个数组({'f','o','o'} )将没有null字符'\0' ,而第二个数组("foo" )将。

使用%s时的printf规范说明如下:

如果不存在 l 修饰符: const char * 参数应为指向字符类型数组的指针(指向字符串的指针)。 数组中的字符最多写入(但不包括)一个终止 null 字节('\0'); 如果指定了精度,则写入的数量不超过指定的数量。 如果给定精度,则不需要存在 null 字节; 如果未指定精度或大于数组的大小,则数组必须包含终止 null 字节。

由于您的printf不包括精度,因此它将写入数组中的字符,直到到达 null 字节( '\0' )。 因此,对于char name1[] = {'f','o','o'}; 导致 printf 从分配给name1数组的 memory 中写入字符。 这种行为被认为是未定义的。

这就是为什么printf("%s\n", name1); 从 memory 中不应该访问的下一个位置打印foo加上一些额外的符号,而printf("%s\n", name2); 它按原样打印字符串foo"

数组中没有尾随符号。

但是printf%s格式需要一个string ,而数组name1不是一个字符串:根据定义, C 字符串是零终止的……而您的数组不是。 因此,行为是未定义的,在您的特定情况下似乎发生的情况是printf继续打印恰好位于 memory 内容后面的随机值name1

在 C 语言中,如果您使用逐字符初始化程序初始化字符串,则需要输入'\0' ,它是 NULL/终止字符以指示字符串的结尾。 所以 name1 应该是{'f', 'o', 'o', '\0'}

您可以在 output 的末尾看到的x\363\277\357\376只是因为 printf 在字符串名称的末尾找不到“\0”而打印的垃圾值1。

对于 name2,您使用双引号来初始化字符串,该字符串会自动在字符串末尾放置一个'\0'

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM