对C字符串常量感到困惑

时间:2014-07-02 20:32:04

标签: c string

当我遇到这个C language implementation of Porters Stemming algorithm时,我发现了一个C-ism,我很困惑。

#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"形式的一串连续内存块?可能是我忽略了一些基本的东西,但即便如此我也想知道我忽略了什么。我知道这是一个基本概念,但我无法在网上找到一个明确的例子或情况来解释这一点,并且说实话,我不遵循输出。欢迎任何有用的评论。

4 个答案:

答案 0 :(得分:8)

这里至少有三件事:

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

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

  • 符号\0...表示八进制字符常量。八进制数字是基数8,由0到7(包括0到7)的数字组成。 8不是有效的八进制常量,因此"\08"不遵循"\07"

答案 1 :(得分:4)

问题不在于字符串的长度,而是在\o语法中用于指定字符串文字中的不可打印值。 \o\oo\ooo表示 octal 常量,即一个字符,其值以base 8编写。自08 \08以来\0 1}}不代表有效的基数为8的数字,它被解释为8,后跟ASCII字符\10

要解决此问题,请将{8}表示为\010test("\007" "abcdefg"); test("\010" "abcdefgh");

\x

...或切换到十六进制,其中test("\x07" "abcdefg"); test("\x08" "abcdefgh"); test("\x09" "abcdefghi"); test("\x0a" "abcdefghij"); ... 前缀使得基础对于随意读者更明确:

{{1}}

答案 2 :(得分:1)

字符或字符串文字中的

\number表示代码为值number的字符。 number以八进制解释,因此第一个非八进制数字终止该数字。因此"\07"是包含代码7的字符的单字符字符串,但\08是一个双字符字符串,其中包含代码0后跟数字{的字符{ {1}}。

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

答案 3 :(得分:1)

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