关于空字符的必要性的混淆?

时间:2017-08-21 10:36:30

标签: c++

我正在阅读为什么确实需要空字符,然后我发现this answer对我来说有点意义。它声明它是必需的,因为char数组(对于C字符串)通常被分配比实际字符串大得多,因此你需要一种方法来象征结束。

但是为什么这些数组不仅仅是基于初始化器构造的大小减去(没有实际上在直接分配给字符串文字时隐式添加的空字符)。就像,如果持有字符串的数组是使用大小减去构造的,则不需要null字符,因为数组不比字符串大,所以当然,它将在该数组的末尾结束。

5 个答案:

答案 0 :(得分:1)

  

我正在阅读为什么确实需要空字符,然后我发现这个答案对我来说有点意义。它声明它是必需的,因为char数组(对于C字符串)通常被分配比实际字符串大得多,因此你需要一种方法来象征结束。

答案是误导性的。这不是为什么需要空终止的原因。接受更多赞成票的答案更好。

  

不需要null字符,因为数组不比字符串大,所以当然,它会在该数组的末尾结束。

让我们提醒自己,我们不能使用数组作为函数参数。即使我们可以,我们也不会想要,因为将整个数组复制到参数中会很慢。

因此,需要间接引用数组。间接通常使用指针(或引用)来实现。现在,我们可以有一个"指向大小为42"的字符数组,但这不是很有用,因为那时参数只能指向一个特定大小的字符串。

相反,常见的方法是使用指向数组第一个元素的指针。这是一种常见的模式,语言有一个规则允许数组的名称隐式地衰减到指向第一个元素的指针。

但是你可以根据指向该数组元素的指针来判断数组的大小吗?你不能。您需要额外的信息。链接问题的接受答案解释了可用于表示大小的选项,并且C的设计者选择使用终止字符的选项(这已经是C所基于的BCPL语言所使用的约定)。

TL;需要DR大小信息,因为需要间接引用字符串,并且间接隐藏有关数组大小的知识。空终止是在字符串内容中编码大小信息的一种方式,它是C语言设计者选择的方式。

答案 1 :(得分:0)

历史上,字符串数组具有终止符号。原因很简单:您只需要传递一个值(数组的头部),而不是发送两个值(数组的头部和数组长度)。这简化了呼叫签名,但对呼叫者提出了一些要求。

在C / C ++本身中,空字符是一个终止符号,因此所有运行时函数都可以使用它们可以满足的第一个空字符是一个行结束。同时,就应用逻辑而言,终端符号可能不同:例如,在HTTP头中,有一个CR-LF-CR-LF序列,标记了报头的结尾和单个CR-LF序列只是下一行的开始。

答案 2 :(得分:0)

  

但是为什么这些数组不仅仅是用尺寸推导构造的   基于初始化器(没有实际的空字符)   直接分配给字符串文字时隐式添加。)

我想你的意思是为什么你不能写:

char t[] = "abracadabra";

并且编译器会推断出大小为11?

因为你有12个字符而不是11.如果数组大小为11,那么就会丢失一些东西:用于包含NUL的字节不会被引用,编译器也不会产生差别: / p>

char t[] = "abracadabra"; // an array deduced from a C-string literal

char t[11] = { 'a', 'b', 'r', 'a', 'c', 'a', 'b', 'r', 'a' }; // a "real" array not a C-string!

第一个必须在范围结束时释放12个字节,第二个11。

历史上,数组只是指针算术之上的一种语法糖。

答案 3 :(得分:0)

  

...因为char数组...通常被分配比实际字符串大得多

答案很糟糕。

C字符串可以动态分配,这意味着在运行之前你不知道它们应该存在多长时间。您可以malloc(required_size+1)而不是预先分配大量数组并用零填充大部分数据,并在最后添加一个单个字符。

相反,在编译时 已知的字符串文字肯定"分配比实际字符串大得多#34;。没有任何意义,因为你事先知道需要多少空间。

  

但为什么这些数组不仅仅是基于初始化器构造的大小减去

size_t expected;
if (read(fd, &expected, sizeof(expected)) == sizeof(expected)) {
  char *buf = malloc(expected + 1);
  if (buf && read(fd, buf, expected) == expected) {
    buf[expected] = 0;
    /* now do something with buf */
  }
}

你去,一个动态大小的字符串。你的"尺寸扣除"是?什么是"初始化程序"?

我本可以用std::string编写一个不那么丑陋的例子,因为这个问题是用C ++标记的,但它实际上是你特别询问的C字符串,而且它并没有。做出任何真正的改变。

答案 4 :(得分:0)

通常通过创建char数组来操纵字符串以保存中间结果并修改其内容:

char buffer[128];
strcpy(buffer, "Hello, ");
strcat(buffer, "world");
std::cout << buffer << '\n';

在调用strcpy之后,缓冲区有7个我们关心的字符;在调用strcat之后它有12个。所以缓冲区中的字符数可以改变,我们需要有一种方法来指示有多少字符。一种惯例是将字符计数放在数组中的第一个位置,然后是实际字符。另一个惯例是在重要角色的末尾放置一个标记。这里有一些权衡,但C中的决定是通过C ++进行的,而不是结束标记。