代码之家  ›  专栏  ›  技术社区  ›  alcuadrado

在C中打印指针

  •  35
  • alcuadrado  · 技术社区  · 16 年前

    我试图用指针来理解一些东西,所以我编写了以下代码:

    #include <stdio.h>
    
    int main(void)
    {
        char s[] = "asd";
        char **p = &s;
    
        printf("The value of s is: %p\n", s);
        printf("The direction of s is: %p\n", &s);
    
        printf("The value of p is: %p\n", p);
        printf("The direction of p is: %p\n", &p);
    
        printf("The direction of s[0] is: %p\n", &s[0]);
        printf("The direction of s[1] is: %p\n", &s[1]);
        printf("The direction of s[2] is: %p\n", &s[2]);
    
        return 0;
    }
    

    当使用gcc编译它时,我会收到以下警告:

    $ gcc main.c -o main-bin -ansi -pedantic -Wall -lm
    main.c: In function ‘main’:
    main.c:6: warning: initialization from incompatible pointer type
    main.c:9: warning: format ‘%p’ expects type ‘void *’, but argument 2 has type ‘char (*)[4]’
    main.c:11: warning: format ‘%p’ expects type ‘void *’, but argument 2 has type ‘char **’
    main.c:12: warning: format ‘%p’ expects type ‘void *’, but argument 2 has type ‘char ***’
    

    (GCC的标志是因为我必须是C89)

    为什么指针类型不兼容?数组的名称不是指向它的第一个元素的指针吗?如果s是指向a的指针, &s 必须是 char ** 不是吗? 为什么我会收到其他警告?我必须用投手吗( void * )为了打印它们?

    当我跑步时,我会得到这样的感觉:

    $ ./main-bin
    The value of s is: 0xbfb7c860
    The direction of s is: 0xbfb7c860
    The value of p is: 0xbfb7c860
    The direction of p is: 0xbfb7c85c
    The direction of s[0] is: 0xbfb7c860
    The direction of s[1] is: 0xbfb7c861
    The direction of s[2] is: 0xbfb7c862
    

    s的值和它的方向(当然还有 p “一样吗?

    8 回复  |  直到 8 年前
        1
  •  25
  •   James Curran    10 年前

    “s”不是“char*”,而是“char[4]”。因此,“&s”不是“char**”,而是“指向4个字符数组的指针”。编译器可能会将“&S”视为编写了“&S[0]”,这大致相同,但却是一个“char*”。

    当您写“char**p=&s;”时,您试图说“我希望p被设置为当前指向“asd”的对象的地址。但目前没有什么 “ASD”。只有一个数组 持有 “ASD”;

    char s[] = "asd";
    char *p = &s[0];  // alternately you could use the shorthand char*p = s;
    char **pp = &p;
    
        2
  •  14
  •   indiv Olivier Poulin    16 年前

    是的,编译器要求void*。把它们扔到空的地方。

    /* for instance... */
    printf("The value of s is: %p\n", (void *) s);
    printf("The direction of s is: %p\n", (void *) &s);
    
        3
  •  4
  •   Airsource Ltd    16 年前

    如果将数组的名称作为参数传递给函数,则会将其视为传递了数组的地址。所以S和S是相同的参数。见K&R 5.3。&S[0]与&S相同,因为它获取数组第一个元素的地址,这与获取数组本身的地址相同。

    对于所有其他指针,尽管所有指针本质上都是内存位置,但它们仍然是类型化的,并且编译器将警告将一种类型的指针分配给另一种类型。

    • void* p; 说P是内存地址,但我不知道内存中有什么
    • char* s; 表示s是内存地址,第一个字节包含一个字符
    • char** ps; 表示ps是内存地址,其中的四个字节(对于32位系统)包含char*类型的指针。

    囊性纤维变性 http://www.oberon2005.ru/paper/kr_c.pdf (K&R的电子书版本)

        4
  •  3
  •   4pie0    8 年前

    它不是指向角色的指针 char* 但指向4个字符数组的指针: char* [4] . 使用G++时,它不会编译:

    main.cpp:in函数__int main(int,char**)_:main.cpp:126:错误: 初始化时无法将__char(*)[4]_秷转换为__char**_

    此外,Linux手册页 says :

    void*指针参数以十六进制打印(好像是由%x或 %×Lx)。 它应该是指向虚空的指针。

    您可以将代码更改为:

    char* s = "asd";
    char** p = &s;
    
    printf("The value of s is: %p\n", s);
    printf("The address of s is: %p\n", &s);
    
    printf("The value of p is: %p\n", p);
    printf("The address of p is: %p\n", &p);
    
    printf("The address of s[0] is: %p\n", &s[0]);
    printf("The address of s[1] is: %p\n", &s[1]);
    printf("The address of s[2] is: %p\n", &s[2]);
    

    结果:

    s的值为:0x403f00

    S的地址是:0x7fff2df9d588

    p值为:0x7fff2df9d588

    P的地址是:0x7fff2df9d580

    S[0]的地址是:0x403f00

    S[1]的地址是:0x403F01

    S[2]的地址是:0x403F02

        5
  •  1
  •   Sergey Golovchenko    16 年前

    变更线:

    char s[]=“滑动门”;

    到:

    char*s=“asd”;

    事情会变得更清楚

        6
  •  1
  •   Charles Duffy    16 年前

    不能更改静态数组的值(即地址)。在技术术语中,数组的左值是其第一个元素的地址。因此 s == &s . 这只是语言上的一个怪癖。

        7
  •  1
  •   fizzer    16 年前

    通常,不必要地将指针强制转换到(void*)被认为是糟糕的样式。但是,这里需要在printf参数上强制转换为(void*),因为printf是可变的。原型没有告诉编译器在调用站点将指针转换为什么类型。

        8
  •  0
  •   selwyn    16 年前

    您使用过:

    char s[] = "asd";
    

    这里实际上是指向字节“asd”。S的地址也会指向这个位置。

    如果您使用:

    char *s = "asd";
    

    S和S的值将不同,因为S实际上是指向字节“asd”的指针。

    你用过:

    char s[] = "asd";
    char **p = &s;
    

    这里S指向字节“asd”。p是指向字符指针的指针,已设置为字符地址。换句话说,P中的间接寻址太多。如果使用char*s=“asd”,则可以使用此额外的间接寻址。

    推荐文章