Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 字符数组中的终止字符_C_Arrays_Escaping_Printf - Fatal编程技术网

C 字符数组中的终止字符

C 字符数组中的终止字符,c,arrays,escaping,printf,C,Arrays,Escaping,Printf,我正试图在屏幕上打印一些字符。我使用了大量错误的实现。例如: 示例1: #include <stdio.h> int main(int argc, char const *argv[]) { char hello[6] = {'h', 'e', 'l', 'l', 'o', '\n'}; char bye[5] = {'b', 'y', 'e', '\n', '\0'}; char end[] = "end"; char dot = '.'; char oops

我正试图在屏幕上打印一些字符。我使用了大量错误的实现。例如:

示例1:

#include <stdio.h>

int main(int argc, char const *argv[]) {
  char hello[6] = {'h', 'e', 'l', 'l', 'o', '\n'};
  char bye[5] = {'b', 'y', 'e', '\n', '\0'};
  char end[] = "end";
  char dot = '.';
  char oops[] = {'o', 'o', 'p', 's'};

  printf("%s\n", hello);
  printf("%s\n", bye);
  printf("%s\n", end);
  printf("%s\n", dot);
  printf("%s\n", oops);
  return 0;
}
#include <stdio.h>

int main(int argc, char const *argv[]) {
  char hello[6] = {'h', 'e', 'l', 'l', 'o', '\n'};
  char bye[5] = {'b', 'y', 'e', '\n', '\0'};
  char end[] = "end";
  char oops[] = {'o', 'o', 'p', 's'};

  printf("%s\n", hello);
  printf("%s\n", bye);
  printf("%s\n", end);
  printf("%s\n", oops);
  return 0;
}
输出2:

#include <stdio.h>

int main(int argc, char const *argv[]) {
  char hello[6] = {'h', 'e', 'l', 'l', 'o', '\n'};
  char bye[5] = {'b', 'y', 'e', '\n', '\0'};
  char end[] = "end";
  char dot = '.';
  char oops[] = {'o', 'o', 'p', 's'};

  printf("%s\n", hello);
  printf("%s\n", bye);
  printf("%s\n", end);
  printf("%s\n", dot);
  printf("%s\n", oops);
  return 0;
}
#include <stdio.h>

int main(int argc, char const *argv[]) {
  char hello[6] = {'h', 'e', 'l', 'l', 'o', '\n'};
  char bye[5] = {'b', 'y', 'e', '\n', '\0'};
  char end[] = "end";
  char oops[] = {'o', 'o', 'p', 's'};

  printf("%s\n", hello);
  printf("%s\n", bye);
  printf("%s\n", end);
  printf("%s\n", oops);
  return 0;
}

问题

垃圾还在那儿!我对他们感觉很好,但是为什么
结尾
被打印了两次呢


每当应该使用终止字符时,我都能正确地使用它,但为什么在打印时会出现这种不一致性呢?我来自Java背景,我已经感到很奇怪了

您得到奇怪输出的原因是您有未定义的行为。处理字符串的函数(包括使用
%s
格式说明符和
printf
打印字符串)希望字符串以null结尾,否则会出现未定义的行为。如果发生这种情况,就不能保证特定的输出。它可以像预期的那样工作,它可以给出奇怪的输出,它可以使程序崩溃或者做一些不同的事情。通常对于打印字符串,它只会继续打印,直到出现访问冲突并崩溃,或者直到遇到下一个空字节(这可能会发生得更早,而不是更晚,直到它发生,它才会打印“垃圾”)

这也是为什么改变看似不相关的事物可以改变UB以不同的方式显现的原因。由于示例2中的更改,堆栈看起来不同,当由于UB错误地访问它时,它将访问不同的内容。当您打印
hello
时,示例1中打印的点可能实际上是
char dot='中的点

char hello[6] = {'h', 'e', 'l', 'l', 'o', '\n'};
打印这是未定义的行为,因为它不是以null结尾的

char bye[5] = {'b', 'y', 'e', '\n', '\0'};
char end[] = "end";
 char hello[6] = {'h', 'e', 'l', 'l', 'o', '\n'};
您可以将其打印为字符串,因为它以null结尾

char bye[5] = {'b', 'y', 'e', '\n', '\0'};
char end[] = "end";
 char hello[6] = {'h', 'e', 'l', 'l', 'o', '\n'};
由于您是使用字符串文字创建的,因此会自动添加空终止符;你可以打印出来
char end[]
是一个由四个字符组成的数组:
'e'
'n'
'd'
'\0'

char dot = '.';
这是一个字符,不是字符串。使用
%s
打印是未定义的行为,编译器可能会警告您。改用
%c
打印

char oops[] = {'o', 'o', 'p', 's'};
与第一个相同,空终止符丢失,因此使用
%s
打印它是未定义的行为

垃圾还在那儿!我为他们感到高兴,但为什么 结尾打印了两次

编译器通常在程序的二进制文件中将所有字符串相邻放置。因此,您的
结束
字符串可能会在以非空结尾的
oops
之后出现。所以在内存中它看起来像是
oopsend\0
,这就是为什么它可以打印
“oopsend”
(或者做一些完全不同的事情,因为它仍然是未定义的行为)


一般来说,想知道UB为什么会这样做并没有什么好处,因为它是不一致的(每次运行它时,它可能会做一些不同的事情,在不同的编译器/机器上,或者工作,直到您向其他人演示它,然后突然使程序崩溃)。只需将其视为不应该执行的错误。

您的第一个字符串数组不是以null结尾的

char bye[5] = {'b', 'y', 'e', '\n', '\0'};
char end[] = "end";
 char hello[6] = {'h', 'e', 'l', 'l', 'o', '\n'};
当向printf(以及其他与字符串相关的函数,如strlen、strdup、strcat等)传递以非null结尾的字符串时,行为是未定义的。 它可能会在数组之后打印更多字节,直到它达到空(零)字节(就像在您的情况下,显示为垃圾),否则可能会使程序崩溃

若要修复该行为,您需要所有字符串数组以null结尾,即在末尾有“\0”字符

如果你像这样初始化一个字符串

 char end[] = "end";

它会自动以null结尾,并为声明的字符数组分配正确的长度。

欢迎来到未定义行为的奇妙世界。因为您的一些数组缺少字符串null终止符,所以处理它们的所有标准字符串函数都将超出数组的范围以查找该终止符。超出数组边界的是UB。更糟糕的是,您还有不匹配的格式说明符和参数类型(使用
printf(“%s\n”,dot)
)。这也是未定义的行为。