【问题标题】:Why does C need a null zero as a string terminator while Java doesn't?为什么 C 需要空零作为字符串终止符,而 Java 不需要?
【发布时间】:2015-05-24 17:37:10
【问题描述】:

我注意到,当我在 C 语言中创建一个字符数组来保存字符串时,我总是需要在末尾添加一个空零作为终止符。例如:

char Month[10];
Month[0] = 'M';
Month[1] = 'a';
Month[2] = 'r';
Month[3] = 'c';
Month[4] = 'h';
Month[5] = '\0';

这里我需要添加Month[5] = '\0'以使char数组显示正确的结果。如果我忽略空零,它将给出结果March_\377。但在 Java 中,我仍然会得到 March 而不添加空零。我想知道 C 和 Java 如何以不同的方式处理这种情况?

【问题讨论】:

  • 在 Java 中,所有字符串都是不可变的对象。在 C 中,您可以通过使指向 char 的指针指向字符串文字来重新创建相同的内容。但是,您的问题似乎过于宽泛,因为每种语言都有其相似之处和不同之处。
  • @Edyyy 你自己知道的答案:他们确实以不同的方式处理这种情况。:)
  • @Vlad 来自莫斯科,这不仅仅是一个随意的选择。拥有一个具有长度属性的 String 对象可以避免遍历整个字符串来查找 '\0'

标签: java c


【解决方案1】:

在 Java 中,我们有一个名为 String 的类,它有一个名为 length() 的方法。

在 C 中,您需要在字符串的末尾有一个 \0,以便您知道字符串的结尾。但是在Java中,这个问题是用length()方法处理的。

【讨论】:

  • 从 Java 8 开始,该变量似乎已被删除。 length() 就是 return backedCharArray.length;(实际上它在 Java 7 的某些版本中也消失了)
  • @AlexisC。谢谢,我不知道,我会编辑我的答案
  • 抱歉编辑混乱;这主要是因为我也对count 感到困惑,而length() 通常是Java 中获取字符串长度的方式。
  • @juanchopanza 它不在文档中,因为它是不需要公开的私有状态。但是你可以在源代码中找到它(至少在java 7之前是这样的)(grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/…
  • @Joey 不考虑亚历克西斯的评论,你是对的,他们似乎不再在length() 中使用count
【解决方案2】:

在 C 中没有类型 string,只有一个指向 char 的指针。在 C 语言中你需要一个字符串时,你需要知道字符串中有多少个字符,或者有一个指示器来查看你已经到达了字符串的末尾。

传统上,有两种方法可以满足此要求。在 C 世界中,约定是用 \0 字符终止字符串。在 PASCAL 世界中,约定是使用另一个变量来存储字符串的长度。

Java 使用 PASCAL 约定并将字符串的长度存储在另一个变量中作为字符串的内容。

这两种方法都有其优点。在 Java/PASCAL 世界中,很容易知道字符串的长度,并且字符串可以包含 \0 字符。在 C 中,您可以为尾子字符串等重用相同的字符数组。

【讨论】:

  • 嗯,C 中有 char 数组。这些不是指向 char 的指针。
  • 是的,字符串确实可以存储在char 数组中(就像问题中一样),但是对于 C sting 逻辑来说,*char 是否指向数组并不重要,数组的中间或包含chars 的任何其他内存。
【解决方案3】:

C 没有字符串作为实际的数据类型,约定只是以空字符结尾的字符数组可以用作字符串。这就是您在语言中使用字符串文字时得到的结果,而当您不使用它们时,您必须重新创建。

根本问题是 C 想要通过不存储长度来节省其字符串表示的内存(例如,Pascal 将字符串长度存储在第一个字节中),因此长度必须以某种方式从数据中得出,在这种情况下以'\0'结束数据。

【讨论】:

    【解决方案4】:

    在 Java 中,字符串主要是一种抽象,您不应该关心内部表示。您有对其执行操作并允许您获取有关字符串的信息的方法。

    然而,在 C 中,情况恰恰相反。您想知道并关心字符串的内部结构,以避免违反分段。

    此外,在 C 中,组成字符串的以空字符结尾的字符序列占用一组连续的内存位置。大多数字符串函数(strcmp、strcat 等)都希望您有一个以空结尾的字符串来知道字符串的结尾在哪里。所以,如果你最后没有空字符,那么字符串函数可以在字符串的末尾运行。

    【讨论】:

    • 嗯,内部表示是一系列 UTF-16 代码单元。这是相当有名的和记录的。
    • 感谢您的澄清,但我不是指那个。我只是说你不需要关心内部表示。所以我将在我的回答中将“知道”替换为“关心”。
    【解决方案5】:

    由于这是一个董事会问题,我们必须在这里指出两点重要的事情:

    1) 首先要确认的是,C 作为一种基本语言并且具有低抽象性,它没有字符串作为数据类型。在 C 中,字符串只是字符的集合。所以我们需要一些东西来指定字符串在哪里结束,为此我们使用 \0 空终止符(它告诉库,这是字符串结束的地方)

    那么,为什么 \0 空终止符:空终止恰好是 C、字符串文字和处理字符串的标准库函数所选择的方式。不知不觉,这很方便,因为空字符并没有真正用于其他任何事情。它既不是控制字符也不是可打印的,也没有定义任何行为(例如以某种特定方式移动光标,例如 \t)

    另外,根据 ISO C 标准,第 7.1.1 节,这样定义字符串:

     字符串是由第一个空字符终止并包括第一个空字符的连续字符序列。

    2) Java 是一种成熟的语言,我的意思是,它是比 C 更高级的语言。在 Java 中,我们可以将字符串定义为:

    字符串被定义为一个固定长度的字符值序列。所有可能的 char 值(从 0 到 65535)都可以在字符串中使用。没有表示字符串结束的“可区分”值。

    那么,它们是如何跟踪字符串结尾的呢? String 类提供了一个名为 length 的方法来知道字符串中的字符数。

    所以,你可以从语言实现规范中清楚地看到,C 需要对字符串进行 Null 终止,因为它们只不过是一个字符序列,需要一个特殊字符来确定这个序列的结束位置,而 java 字符串是实现的作为类(和对象)。

    额外说明:我知道这不是被问到的,但我要说明的是,如果您通过 JNI 读取 C 代码中的 Java 字符串数据,那么我们使用 JNI 函数,例如 GetStringChars() 或获取字符串UTFChars()。这些函数都没有记录为返回以空值结尾的数据,我们应该使用 GetStringLength() 来确定它的长度。与 GetStringUTFChars() 类似,您必须使用 GetStringUTF8Length() 来确定修改后的 UTF-8 格式的长度。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多