【问题标题】:Confused about C string constants对 C 字符串常量感到困惑
【发布时间】:2014-07-02 20:32:03
【问题描述】:

当我遇到这个C language implementation of Porters Stemming algorithm 时,我发现了一个令我困惑的 C 主义。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void test( char *s )
{
    int len = s[0];

    printf("len= %i\n", len );

    printf("s[len] = %c\n", s[len] );
}

int main()
{
    test("\07" "abcdefg");

    return 0;
}

和输出:

len = 7
s[len] = g

但是,当我输入时

test("\08" "abcdefgh");

或任何长度超过 7 且第一对括号中对应长度的字符串常量(即test("\09" "abcdefghi");,输出为

len = 0
s[len] = 

但是像test("\01" "abcdefgh"); 这样的任何输入都会打印出该位置的字符(如果我们暂时将第一个字符位置称为 1 而不是 0)

如果test( char *s ) 读取第一对括号中的数字(我不确定它是如何做到的,因为我认为 s[0] 只能读取一个字符,即 '\' )并打印第二对括号中字符串常量的索引 + 1 处的最后一个字符。

我的问题是:似乎我们将两个字符串常量传递给test( char *s )。这里到底发生了什么,意思是,编译器似乎如何通过两对括号“拆分”字符串?另一个问题是,"blah" "abcdefg" 形式的字符串是一个连续的内存块吗?可能是我忽略了一些基本的东西,但即便如此我想知道我忽略了什么。我知道这是一个基本概念,但我在网上找不到一个明确的例子或情况来解释这一点,老实说,我不遵循输出。欢迎任何有用的 cmets。

【问题讨论】:

标签: c string


【解决方案1】:

这里至少发生了三件事:

  • 相互并列的文字字符串由编译器连接。 "a" "b""ab" 完全相同。

  • 反斜杠是转义字符,这意味着它不会按字面意思复制到结果字符串中。 \01 表示“ASCII 值为 1 的字符”。

  • 符号\0... 表示八进制 字符常量。八进制数以 8 为基数,由 0 到 7(含)的数字组成。 8 不是一个有效的八进制常数,所以"\08" 不跟在"\07" 后面。

【讨论】:

  • 请注意,八进制符号不一定是\0... - 例如,\33 是一个完全有效的八进制字符常量。 \08 被解释为\0 后跟8
  • 是的,C 中以长度为前缀的字符串非常不寻常,您在任何地方都找不到对它们的太多支持。
  • 长度字节和“实际字符串”分开的原因可能需要一些额外的解释。
【解决方案2】:

问题不在于字符串的长度,而在于\o 用于在字符串文字中指定不可打印值的语法。 \o\oo\ooo 表示 八进制 常量,即其值以基数 8 写入的单个字符。由于 \08 中的 08 不代表有效基数8位数字,解释为\0后跟ASCII字符8

要解决此问题,请将 8 表示为 \10\010

test("\007" "abcdefg");
test("\010" "abcdefgh");

...或切换到十六进制,其中\x 前缀使基础对不经意的读者更加明确:

test("\x07" "abcdefg");
test("\x08" "abcdefgh");
test("\x09" "abcdefghi");
test("\x0a" "abcdefghij");
...

【讨论】:

    【解决方案3】:

    \number 在字符或字符串字面量中是指代码为值number 的字符。 number 以八进制解释,因此第一个非八进制数字终止该数字。所以"\07"是一个包含代码7的字符的单字符字符串,而\08是包含代码0的字符后跟数字8的二字符字符串。

    此外,代码0 是在C 中用于指示字符串结尾的空终止符。所以第二个字符串在开头结束,因为它的第一个字节是终止符。这就是为什么第二个示例中字符串的长度是0

    【讨论】:

      【解决方案4】:

      当两个或多个字符串文字相邻(仅由空格分隔)时,编译器会将它们连接成一个字符串。因此"\07" "abcdefg" 等价于"\07abcdefg". "\07" 是八进制转义。八进制转义在三位数字或第一个非八进制字符后结束。因此,当您输入“\08”时,8 是一个非八进制字符,因此转义结束并且0 存储在s[0]
      现在,len0,打印s[len] 将尝试打印s[0] 处的字符,该字符具有不可打印的ASCII 码(只有高于32 的ASCII 值以上的字符是可打印的)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-03-13
        • 1970-01-01
        • 2021-12-05
        • 2012-07-14
        • 2020-08-01
        • 1970-01-01
        • 2017-10-19
        相关资源
        最近更新 更多