字符指针和printf函数

Fab*_*ous 7 c printf pointers

我试图学习指针,我写了下面的代码来打印指针的值:

#include <stdio.h>

    int main(void) {
        char *p = "abc";
        printf("%c",*p);
        return 0;
    }
Run Code Online (Sandbox Code Playgroud)

输出是:

一个

但是,如果我将上面的代码更改为:

#include <stdio.h>

int main(void) {
    char *p = "abc";
    printf(p);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我得到输出:

ABC

我不明白以下两件事:

  1. 为什么printf在第二种情况下不需要格式说明符?是否printf(pointer_name)足以打印指针的值?

  2. 根据我的理解(这很少),*p指向包含的连续内存块abc.我预计两个输出都是相同的,即

ABC

由于印刷方式不同,是不同的产出?

编辑1

此外,以下代码会产生运行时错误.为什么这样?

 #include <stdio.h>

    int main(void) {
        char *p = "abc";
        printf(*p);
        return 0;
    }
Run Code Online (Sandbox Code Playgroud)

Som*_*ude 15

对于您的第一个问题,printf函数(和系列)将字符串作为第一个参数(即a const char *).该字符串可以包含该printf函数将替换为相应参数的格式代码.文本的其余部分按原样逐字打印.这就是当你p作为第一个参数传递时发生的事情.

请注意,使用printf这种方式是非常不推荐的,特别是如果字符串包含来自用户的输入.如果用户在字符串中添加格式代码,并且您没有提供正确的参数,那么您将具有未定义的行为.它甚至可能导致安全漏洞.

对于第二个问题,变量p指向一些内存.表达式*p取消引用指针,为您提供单个字符,即p实际指向的字符,即p[0].

想象p这样:

+---+      +-----+-----+-----+------+
| p | ---> | 'a' | 'b' | 'c' | '\0' |
+---+      +-----+-----+-----+------+

变量p并不真正指向"字符串",它只指向内存中的某个单独位置,即字符串中的第一个字符"abc".使用它的函数p将内存视为一系列字符.

此外,常量字符串文字实际上存储为字符串中字符数的(只读)数组,以及字符串终止符的一个数组.

此外,为了帮助你理解为什么*p是一样的p[0],你需要知道的是,对于任何指针或数组 p和有效的索引i,表达式p[i]等于*(p + i).要获得第一个字符,你有索引0,这意味着你p[0]应该等于*(p + 0).对任何东西添加零是一个无操作,所以*(p + 0)*(p)相同的*p.因此p[0]等于*p.


关于你的编辑(你在哪里printf(*p)),因为*p返回由p(即p[0])指向的第一个"元素"的值,你传递一个字符作为指向格式字符串的指针.这将导致编译器将其转换成其指向任何地址都有单个字符值的指针(它不字符转换为指针,以字符).此地址不是一个非常有效的地址(在ASCII字母表 'a'中的值97是程序将查找要打印的字符串的地址),并且您将具有未定义的行为.

  • @simrandhamija:"*`p [0]`*"不是一个"字符串"而是一个字符,只有一个`char`."A"和"A"之间有区别.前者是一个`char`-literal,后者是一个"字符串"-literal,实际上是一个'0'终止的`char`数组. (2认同)

Osk*_*kog 7

  1. p 是格式字符串.

    char *p = "abc";
    printf(p);
    
    Run Code Online (Sandbox Code Playgroud)

    是相同的

    print("abc");
    
    Run Code Online (Sandbox Code Playgroud)

    这样做非常糟糕,因为你不知道变量将包含什么,如果它包含格式说明符,调用printf可能会做很糟糕的事情.

  2. 第一种情况(with "%c")仅打印第一个字符的原因是,它%c表示一个字节,*p表示p指向的第一个值.

    %s 会打印整个字符串.

    char *p = "abc";
    printf(p); /* If p is untrusted, bad things will happen, otherwise the string p is written. */
    printf("%c", *p); /* print the first byte in the string p */
    printf("%s", p); /* print the string p */
    
    Run Code Online (Sandbox Code Playgroud)