Printf输出的指针字符串解释来自一次采访

时间:2018-04-17 17:10:12

标签: c string pointers printf

我接受了一次采访,我得到了这段代码,并询问每个printf语句的输出是什么。

我的回答是评论,但我不确定其余的。

任何人都可以解释陈述1,3和7的不同输出以及为什么?

谢谢!

#include <stdio.h>

int main(int argc, const char * argv[]) {

    char *s = "12345";

    printf("%d\n", s);      // 1.Outputs "3999" is this the address of the first pointer?
    printf("%d\n", *s);     // 2.The decimal value of the first character
    printf("%c\n", s);      // 3.Outputs "\237" What is this value?
    printf("%c\n", *s);     // 4.Outputs "1"
    printf("%c\n", *(s+1)); // 5.Outputs "2"
    printf("%s\n", s);      // 6.Outputs "12345"
    printf("%s\n", *s);     // 7.I get an error, why?
    return 0;
}

4 个答案:

答案 0 :(得分:5)

此次电话

printf("%d\n", *s);

具有未定义的行为,因为无效的格式说明符与指针一起使用。

此次电话

'1'

输出字符printf("%c\n", s); 的内部代码(例如ASCII代码)。

此次电话

printf("%c\n", *s);
printf("%c\n", *(s+1));
由于使用带指针的无效格式说明符,

具有未定义的行为。

这些电话

'1'

有效。第一个输出字符'2',第二个输出字符printf("%s\n", s);

此次电话

"12345"

正确并输出字符串printf("%s\n", *s);

此次电话

char

无效,因为无效的格式说明符与ggplot( diamonds, aes(clarity , price) ) + geom_bar(stat = "identity") + scale_y_continuous(labels = scales::comma) 类型的对象一起使用。

答案 1 :(得分:1)

第7行失败,因为预期C样式字符串作为输入,而您正在放置一个字符。

看看:

答案 2 :(得分:1)

  1. 此代码是未定义的行为(UB)。您正在传递指针,该函数需要int值。例如,在64位体系结构中,指针是64位,int是32位。您可以打印截断值。

  2. 您正在传递第一个char值(由编译器自动转换为int)并以十进制格式打印。可能你得到了49'1'的ASCII代码。这是合法用途,但要小心惊喜,因为如果你的平台char实现是{{1},你可能会得到负值}。

  3. 您正在将传递的指针重新解释为signed值。未定义的行为,因为您无法将指针转换为char值。

  4. 您正在将char的指向值打印为s,以便获得字符串char"12345")的第一个字符。

  5. 您正在打印'1'指向的第一个char旁边的代码,因此您获得字符串的第二个字符(s)。

  6. 您正在打印'2'指向的字符串,因此您将获得整个字符串。这是合法的,实际上是打印字符串的常用方法。

  7. 您传递的字符串的第一个字符被解释为指向要打印的空终止字符串的指针(它不是')。这是未定义的行为。您正在重新解释s值作为指向空终止字符串的指针。在这种情况下char是常见的,(但不保证:))当程序在到达终止字符串的假定空字符之前尝试访问未分配的内存时发送信号(但它可以找到{{1}在路上只打印垃圾)。

答案 3 :(得分:0)

我使用以下online C compiler来运行您的代码, 以下是结果:

1. 4195988            - undefined behaviour (UB), manifesting here as the address
                        of the char array as you stated (for a 64 bit address you might or
                        might not get truncation)
2. 49                 - ASCII value of '1'
3. �                  - undefined behaviour, manifesting here as unsupported ASCII value
                        for a truncation of the address of the array of chars
                        (placing 32-bit address into a char - assuming a 32-bit system)
4. 1                  - obvious
5. 2                  - obvious
6. 12345              - obvious
7. Segmentation fault - undefined behaviour, trying to place the first char
                        of a char array into a string reserved position
                        (placing char into a string)

关于第3点的注意事项:我们可以推断出在运行期间发生的事情。 在问题中提供的具体示例中 -

printf("%c\n", s);      // 3.Outputs "\237". What is this value?

这是处理UB时的硬件/编译器/ OS相关行为。

为什么呢?由于输出“\ 237” - &gt;这意味着在执行此代码的特定硬件系统下截断

请参阅下面的解释(假设 - 32位系统):

char *s = "12345"; // Declaring a char pointer pointing to a char array
char c = s; // Placement of the pointer into a char - our UB
printf("Pointer to character array: %08x\n", s); // Get the raw bytes
printf("Pointer to character: %08x\n", c); // Get the raw bytes
printf("%c\n", s); // place the pointer as a character
                   // display is dependent on the ASCII value and the OS
                   // definitions for 128-255 ASCII values

输出:

Pointer to character array: 004006e4  // Classic 32-bit pointer
Pointer to character: ffffffe4        // Truncation to a signed char
                                      // (Note signed MSB padding to 32 bit display)
�                                     // ASCII value E4 = 228 is not displayed properly

最终的printf命令相当于char c = s; printf("%c\n", c);。 为什么?感谢截断。

另一个带有合法ASCII字符输出的示例:

    char *fixedPointer = 0xABCD61; // Declaring a char pointer pointing to a dummy address
    char c = fixedPointer; // Placement of the pointer into a char - our UB
    printf("Pointer to 32-bit address: %08x\n", fixedPointer); // Get the raw bytes
    printf("Pointer to character: %08x\n", c); // Get the raw bytes
    printf("%c\n", fixedPointer);

实际产出:

Pointer to 32-bit address: 00abcd61
Pointer to character: 00000061
a