V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
qw7692336
V2EX  ›  C

C 语言入门级问题,指针问题

  •  
  •   qw7692336 · 2015-08-17 05:49:16 +08:00 · 1814 次点击
    这是一个创建于 3414 天前的主题,其中的信息可能已经有所发展或是发生改变。
    #include <stdio.h>
    
    void main(){
        int a = 5;
        int* b = &a;
        int* c = &b;
        printf("%d\n",&a==b);
        printf("%d\n",&b==c);
        printf("%d\n",a==*b);
        printf("%d\n",b==*c);
    }
    

    输出是
    1
    1
    1
    0

    为何最后一个是0?

    第 1 条附言  ·  2015-08-17 11:40:47 +08:00

    还有两行忘了加

    printf("%d\n",b);
    printf("%d\n",*c);
    

    另外 markdown 怎么贴代码

    第 2 条附言  ·  2015-08-17 11:41:42 +08:00
    还有就是用 vim 来写 C ,需要装什么插件。
    第 3 条附言  ·  2015-08-17 11:43:36 +08:00
    果然是 64 位截断问题,把代码改成 long* c = &b;就输出 1 了
    25 条回复    2015-08-17 17:13:57 +08:00
    Andiry
        1
    Andiry  
       2015-08-17 05:59:17 +08:00
    int **c = &b
    pimin
        2
    pimin  
       2015-08-17 08:14:45 +08:00
    int* c = &b;
    这句可以编译通过么
    zhangchioulin
        3
    zhangchioulin  
       2015-08-17 08:32:27 +08:00
    为什么我不能编译通过
    Fulminit
        4
    Fulminit  
       2015-08-17 08:35:23 +08:00 via Android
    b 是指向 a 的指针
    b 的值是 a 的指针地址
    c 是指向 b 的指针
    c 的值是 b 的指针地址

    那么 c 解引用之后就是 b 的指针地址,自然和 b 的值不相同。

    (好久没写C了有错误请指出,谢谢)
    colorsand
        5
    colorsand  
       2015-08-17 08:41:47 +08:00
    c里边的数组指针和指针数组比较难理解
    ljbha007
        6
    ljbha007  
       2015-08-17 09:04:38 +08:00
    1楼就给出了正解
    c里存的是b的地址所以*取出来的值是b的值 也就是a的地址
    b里存的是a的地址 所以*取出来的值是a的值 也就是5
    lizhiqing1996
        7
    lizhiqing1996  
       2015-08-17 09:06:17 +08:00
    c是一个整型指针,怎么存进一个指针型指针的?
    nozama
        8
    nozama  
       2015-08-17 09:19:35 +08:00 via Android
    和平台有关吧,应该64位系统上就会出现这个结果。sizeof(int) != sizeof(int*),于是*c本来应该是一个64位的指针值,但是int只有32位,所以被截断了。
    canautumn
        9
    canautumn  
       2015-08-17 09:20:58 +08:00
    无视warning的话可以编译通过。具体为啥不等你要查C标准是怎么规定的了,不过写这种不规范的代码有啥意义吗?
    xiaocaibaozi
        10
    xiaocaibaozi  
       2015-08-17 09:22:08 +08:00
    同新路过,不过我这里的GCC碉堡了,即没给我报c类型的错,还给我输出了四个一。
    linux40
        11
    linux40  
       2015-08-17 09:45:53 +08:00 via Android
    看一楼,别的不用看了。
    DiamondY
        12
    DiamondY  
       2015-08-17 10:15:28 +08:00
    用楼主的代码,使用 VC6 编译,有 3 个警告;
    用 1 楼的方式替换掉代码后,有 0 个警告;
    但我用 VC6 运行得出的结果,却两种方式都是 4 个 1 ……囧
    也就是说,单从值上面说,(b==*c )这个判断条件是 true 的;
    只不过,楼主把 c 定义成指向 int 的指针,*c 出来的是 int ,而 b 却是指向 int 的指针,两个数值类型不一样
    DiamondY
        13
    DiamondY  
       2015-08-17 10:18:42 +08:00
    贴出 VC6 下编译的警告:

    int a = 5;
    int* b = &a;
    int* c = &b; (warning C4047: 'initializing' : 'int *' differs in levels of indirection from 'int ** ')
    printf ("%d\n",&a==b );
    printf ("%d\n",&b==c ); (warning C4047: '==' : 'int ** ' differs in levels of indirection from 'int *')
    printf ("%d\n",a==*b );
    printf ("%d\n",b==*c ); (warning C4047: '==' : 'int *' differs in levels of indirection from 'int ')
    chensonglu
        14
    chensonglu  
       2015-08-17 10:37:28 +08:00
    定义的时候得用 int **c = &b ,因为 c 是一个二级指针,否则编译不通过。改完之后你会发现最后结果就是 1 了。
    weyou
        15
    weyou  
       2015-08-17 10:46:31 +08:00
    楼主的程序肯定有警告,其他同意 @nozama , 楼主应该是在 64bit 系统上运行的程序。 *c 发生了截断,因为 int* 和 int 的 size 在 64bit 系统上是不同的。
    w99wen
        16
    w99wen  
       2015-08-17 11:04:53 +08:00   ❤️ 3
    对于指针的问题。
    你可以这么理解。

    比如有一个仓库,里面有很多东西。
    那么你想要用这个仓库,所以你需要知道这个仓库的地址是什么。

    指针就是仓库的地址。因此指针的内存占用是很小的。因为他只是一个地址的标记(貌似是 4B ,好久没弄过 C/C++了)。
    而真实的仓库内容可能非常大。可能有 1G 大小。

    那么在你说的这个情况中,这个仓库就是那个 int a = 5 ,也就是 5 这个值。
    而这个地址就是那个指针 int* b 。

    我们都可以用这个仓库的地址去找到仓库。然后对仓库进行改动。
    然而怎么通过地址(也就是指针 b )找到仓库的真实内容(也就是 a 实际里面存了什么值)那。就是通过*符号。类似的,也可以用&得到仓库的地址。

    在你的代码中:
    你先用&a ,把仓库 a (也就是 int 值 5 )的地址给了 b 去存储。那么你*b 得到的自然是仓库 a 的内容。

    你又用&b ,把 b 的地址给了 c ,那么*c 地址对应的应该是 b 的内容。也就是 a 仓库的地址。( a 仓库的地址 b 也看做是一个仓库)

    所以你要是想从 c ,得到 a 的内容。你应该是**c ,这才是 a 仓库的内容。

    应该明白的点:
    指针就像是个地址。我们能通过这个地址得到我们想要的东西。得到一个东西的地址的方法是用&,而由一个地址拿到那个东西的方法是用*。
    比如一个 int 值 5 ,他在内存中, 5 可以用&得到 5 的地址。我们把 5 的地址存起来,放在指针 b 里面。注意, b 也是在内存中, b 存储的是 5 的地址, b 也是有一个地址的,随意我们还可以用&得到 b 的地址。然后存储到另一个指针 c 里面。

    这时候。我们用*c ,得到的是 c 存储的地址对应的内容,也就是 b 指针的内容,也就是 5 这个值的地址。因为*c 是 b 的内容, 5 的地址。所以要再用一次*,也就是**c ,才能得到 5 这个值。

    我是不是蛋疼。
    wlee1991
        17
    wlee1991  
       2015-08-17 11:10:02 +08:00
    正确写法应该是这样的:

    {% codeblock lang:c %}
    #include <stdio.h>

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

    int a = 5; //a is int
    int * b = &a; //b is a pointer to int
    int * * c = &b; //c is a pointer to int *
    int * * * d = &c; //d is a pointer to int * *

    printf ("a = %d, &a = %p\n", a, &a );
    printf ("b = %p, &b = %p\n", b, &b );
    printf ("c = %p, &c = %p\n", c, &c );
    printf ("d = %p, &d = %p\n", d, &d );

    printf ("*b = %d\n", *b );
    printf ("**c = %d\n", **c );
    printf ("***d = %d\n", ***d );

    printf ("%d\n", &a == b );
    printf ("%d\n", &b == c );
    printf ("%d\n", &c == d );

    printf ("%d\n", a == *b );
    printf ("%d\n", b == *c );
    printf ("%d\n", c == *d );

    return 0;
    }
    {% endcodeblock %}
    wlee1991
        18
    wlee1991  
       2015-08-17 11:11:48 +08:00
    `#include <stdio.h>
    `
    `int main (int argc, const char * argv[]) {
    `
    ` int a = 5; //a is int
    ` int * b = &a; //b is a pointer to int
    ` int * * c = &b; //c is a pointer to int *
    ` int * * * d = &c; //d is a pointer to int * *
    `
    ` printf ("a = %d, &a = %p\n", a, &a );
    ` printf ("b = %p, &b = %p\n", b, &b );
    ` printf ("c = %p, &c = %p\n", c, &c );
    ` printf ("d = %p, &d = %p\n", d, &d );
    `
    ` printf ("*b = %d\n", *b );
    ` printf ("**c = %d\n", **c );
    ` printf ("***d = %d\n", ***d );
    `
    ` printf ("%d\n", &a == b );
    ` printf ("%d\n", &b == c );
    ` printf ("%d\n", &c == d );
    `
    ` printf ("%d\n", a == *b );
    ` printf ("%d\n", b == *c );
    ` printf ("%d\n", c == *d );
    `
    ` return 0;
    `}
    kokutou
        19
    kokutou  
       2015-08-17 11:12:31 +08:00 via Android
    @w99wen 是的。
    wlee1991
        20
    wlee1991  
       2015-08-17 11:14:19 +08:00
    ```c
    #include <stdio.h>

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

    int a = 5; //a is int
    int * b = &a; //b is a pointer to int
    int * * c = &b; //c is a pointer to int *
    int * * * d = &c; //d is a pointer to int * *

    printf ("a = %d, &a = %p\n", a, &a );
    printf ("b = %p, &b = %p\n", b, &b );
    printf ("c = %p, &c = %p\n", c, &c );
    printf ("d = %p, &d = %p\n", d, &d );

    printf ("*b = %d\n", *b );
    printf ("**c = %d\n", **c );
    printf ("***d = %d\n", ***d );

    printf ("%d\n", &a == b );
    printf ("%d\n", &b == c );
    printf ("%d\n", &c == d );

    printf ("%d\n", a == *b );
    printf ("%d\n", b == *c );
    printf ("%d\n", c == *d );

    return 0;
    }
    ```
    wlee1991
        21
    wlee1991  
       2015-08-17 11:15:51 +08:00
    我就不信弄不粗来

    ` ` `
    #include <stdio.h>

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

    int a = 5; //a is int
    int * b = &a; //b is a pointer to int
    int * * c = &b; //c is a pointer to int *
    int * * * d = &c; //d is a pointer to int * *

    printf ("a = %d, &a = %p\n", a, &a );
    printf ("b = %p, &b = %p\n", b, &b );
    printf ("c = %p, &c = %p\n", c, &c );
    printf ("d = %p, &d = %p\n", d, &d );

    printf ("*b = %d\n", *b );
    printf ("**c = %d\n", **c );
    printf ("***d = %d\n", ***d );

    printf ("%d\n", &a == b );
    printf ("%d\n", &b == c );
    printf ("%d\n", &c == d );

    printf ("%d\n", a == *b );
    printf ("%d\n", b == *c );
    printf ("%d\n", c == *d );

    return 0;
    }
    ` ` `
    testlc
        22
    testlc  
       2015-08-17 11:19:53 +08:00
    手动 markdown 好毅力 哈哈
    qw7692336
        23
    qw7692336  
    OP
       2015-08-17 11:44:33 +08:00
    @nozama
    @weyou
    改为
    long* c = &b;
    会输出 1 ;
    果然是 64 位截断问题
    Banio
        24
    Banio  
       2015-08-17 16:18:29 +08:00
    In function 'main':
    [Warning] initialization from incompatible pointer type [enabled by default]
    [Warning] comparison of distinct pointer types lacks a cast [enabled by default]
    [Warning] comparison between pointer and integer [enabled by default]

    1
    1
    1
    1
    用的 dev cpp 5.1
    oska874
        25
    oska874  
       2015-08-17 17:13:57 +08:00
    32bit linux,64 bit cygwin,用 gcc 4.8+编译,都是编译有 warning ,但是结果都是 4 个 1 。

    别用 vc 6 了,我们搞工控的都是 vs 2013 了。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2738 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 32ms · UTC 13:14 · PVG 21:14 · LAX 05:14 · JFK 08:14
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.