c - char 数组中的终止符

标签 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[] = {'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;
}

输出 1:

enter image description here

问题:

为什么在bye之前打印了字符?

字符后面的这些垃圾是什么?

示例 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 oops[] = {'o', 'o', 'p', 's'};

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

输出 2:

enter image description here

问题

垃圾还在那里!我为他们感觉很好,但为什么 end 被打印了两次?

我设法在应该使用终止符的时候正确地使用它,但是为什么我在打印时会出现这种不一致的情况?我来自 Java 背景,我已经感觉很奇怪了!

最佳答案

你得到奇怪的输出的原因是你有未定义的行为。处理字符串的函数(包括使用 %s 格式说明符和 printf 打印它们)期望它们以 null 终止,否则您会得到未定义的行为。如果发生这种情况,则无法保证特定的输出。它可以按预期工作,可以提供奇怪的输出,可以使程序崩溃或执行不同的操作。通常在打印字符串时,它会继续打印,直到出现访问冲突并崩溃,或者直到遇到下一个空字节(这可能会发生得早而不是晚,并且在发生之前,它会打印“垃圾”) .

这也是为什么改变看似无关的事物可以改变 UB 以不同的方式显现。由于示例2中的变化,堆栈看起来不一样,并且当由于UB错误访问时,它会访问不同的东西。示例 1 中打印 hello 时打印的点可能实际上是 char dot = '.'; 中的点。

char hello[6] = {'h', 'e', 'l', 'l', 'o', '\n'};

打印这是未定义的行为,因为它不是以 null 结尾的。

char bye[5] = {'b', 'y', 'e', '\n', '\0'};

您可以将其打印为字符串,因为它以 null 结尾。

char end[] = "end";

由于您使用字符串文字进行此操作,因此会自动添加空终止符;你可以打印它。 char end[] 是一个由四个字符组成的数组:'e''n' 'd''\0'

char dot = '.';

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

char oops[] = {'o', 'o', 'p', 's'};

与第一个相同,缺少空终止符,因此使用 %s 打印它是未定义的行为。

The rubbish are still there! I am feeling good for them but why the end was printed twice?

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

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

关于c - char 数组中的终止符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58522758/

相关文章:

c# - 在 ASP.NET MVC 5 中,在我应用迁移来更改 MODEL 类后,它也会更改我的 View .cshtml 文件吗?

c - 是什么导致这些数组值不匹配?

c - 简单 C 程序中的 undefined symbol

arrays - 有哪些方法可以查找包含特定实数值的数组元素?

PHP sprintf 转义 %

javascript - jquery中的特殊字符

javascript - JavaScript 中的字符串转义

c - 在另一个 .c 文件上声明函数使浮点乘法始终为 0

arrays - postgresql Json 路径功能

arrays - 使用 mongoose 将对象添加到数组