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

C 语言 指针问题

  •  
  •   cio · 2017-01-30 20:02:08 +08:00 · 3373 次点击
    这是一个创建于 2845 天前的主题,其中的信息可能已经有所发展或是发生改变。
    #include <stdio.h>
    
    const int MAX = 3;
    
    int main ()
    {
       int  var[] = {10, 100, 200};
       int  i, *ptr;
    
       /* 指针中的数组地址 */
       ptr = var;
       for ( i = 0; i < MAX; i++)
       {
    
          printf("存储地址: var[%d] = %x\n", i, ptr );
          printf("存储值: var[%d] = %d\n", i, *ptr );
    
          /* 移动到下一个位置 */
          ptr++;
       }
       return 0;
    }
    

    其中的 ptr = var; 这里是把数组 var 的第一个值得地址赋值给了 ptr 指针吗? 那可不可以这样写 ptr = &var[0];

    刚学。可能问的问题弱智了点,还是期望有人解惑..

    31 条回复    2017-02-03 12:43:22 +08:00
    am241
        1
    am241  
       2017-01-30 20:06:06 +08:00
    可以这样写,不过没必要
    stevezjb
        2
    stevezjb  
       2017-01-30 20:07:56 +08:00
    var=&var[0]
    liyvhg
        3
    liyvhg  
       2017-01-30 20:11:11 +08:00 via Android   ❤️ 1
    这两种写法是等价的
    LGA1150
        4
    LGA1150  
       2017-01-30 20:17:08 +08:00 via Android
    一个引用&,一个解引用[],正好抵消
    firebroo
        5
    firebroo  
       2017-01-30 20:22:38 +08:00 via Android
    可以的。
    cio
        6
    cio  
    OP
       2017-01-30 20:26:02 +08:00
    谢谢!理解了。我再去好好看看书..
    Lonely
        7
    Lonely  
       2017-01-30 22:20:19 +08:00 via iPhone
    理一下顺序就是&(var[0])
    sfqtsh
        8
    sfqtsh  
       2017-01-30 22:25:18 +08:00 via Android
    var 的类型是 int [3],是个数组类型, ptr 类型是 int*,是个指针类型,前者可隐含向后者转换,指向其首地址。
    var[0]类型是 int ,所以&var[0]类型就是 int*。
    owt5008137
        9
    owt5008137  
       2017-01-30 22:25:28 +08:00 via Android
    可以,一样的
    NvSylvanas
        10
    NvSylvanas  
       2017-01-30 22:50:32 +08:00
    可以
    lzhCoooder
        11
    lzhCoooder  
       2017-01-30 23:18:02 +08:00
    数组名代表数组首地址,这应该是很重要的一个概念,记住它就不会有疑惑了
    klesh
        12
    klesh  
       2017-01-31 00:16:37 +08:00 via Android
    看的什么书?合格的入门级会直接给多第二种写法,并说明是等效的。
    msg7086
        13
    msg7086  
       2017-01-31 02:17:53 +08:00
    a[b] 就是 *(a+b) 的语法糖。
    &a[b] 自然就是 (a+b) 。
    b 是 0 的情况下,&a[0] 就是 (a+0) 也就是 a 了。
    justyy
        14
    justyy  
       2017-01-31 02:21:02 +08:00
    a[b] 可以写成 b[a]
    424778940
        15
    424778940  
       2017-01-31 02:51:44 +08:00
    数组的名字所指向的地址就是数组第一个元素的地址 所以你直接用名字和取第一个元素的地址 结果应该是一样的
    ryd994
        16
    ryd994  
       2017-01-31 08:57:11 +08:00 via Android
    学深点你就知道 a[i]==*(a+i)
    所以可以用这种办法直接偏移数组
    ryd994
        17
    ryd994  
       2017-01-31 08:59:28 +08:00 via Android   ❤️ 1
    推荐你再零长度数组 https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html
    会感觉打开了新世界的大门
    然后乱飞指针无法自拔,直到写出自己都看不懂的代码为止

    我就是这么过来的
    ryd994
        18
    ryd994  
       2017-01-31 09:01:10 +08:00 via Android
    @justyy 不一定,如果 a 和 b 不是一个类型呢?
    zhujinliang
        19
    zhujinliang  
       2017-01-31 10:04:31 +08:00 via iPhone
    我觉得&a[n]写法更好,因为 a 的类型不确定,用数组的形式编译器会自动决定偏移多少
    自己处理指针除非有特殊用途
    introom
        20
    introom  
       2017-01-31 10:22:58 +08:00 via Android
    @ryd994 a,b 当然不是一个类型
    ryd994
        21
    ryd994  
       2017-01-31 12:56:15 +08:00
    @introom 考虑这 short *a=1; long *b=2
    ryd994
        22
    ryd994  
       2017-01-31 12:59:55 +08:00
    @zhujinliang 只要指针类型对,指针加减的偏移量是正确的
    指针加加减减是很正规的用法
    C 规范规定了 a[i]和*(a+i) 是等同的
    introom
        23
    introom  
       2017-01-31 14:42:54 +08:00 via Android
    @ryd994 之前楼上那位的意思应该是说,比如
    int arr = {1,2,3}
    那么, arr[1]和 1[arr]一个意思。

    你的问句是,如果 a,b 不是一个类型呢?
    所以 a,b 是一个类型是什么意思?
    crazyjin
        24
    crazyjin  
       2017-01-31 15:40:01 +08:00
    楼主去看看《 csapp 》的前几章,再看看《 c 陷阱与缺陷》。你会理解 c 的指针的本质,并且见识一些极端复杂的用法。
    snnn
        25
    snnn  
       2017-01-31 18:42:44 +08:00
    @zhujinliang “我觉得&a[n]写法更好,因为 a 的类型不确定,用数组的形式编译器会自动决定偏移多少”

    C 语言中所有类型都是静态的。不存在不确定的类型。
    snnn
        26
    snnn  
       2017-01-31 18:43:22 +08:00
    @ryd994 “考虑这 short *a=1; long *b=2 ”

    你这代码编译不过去。
    mintist
        27
    mintist  
       2017-02-01 15:00:22 +08:00   ❤️ 1
    C 语言中的 **指针** 由两部分构成:地址值和类型。

    地址值就是数字,和汇编中是一样的。

    而类型,在汇编里面是没有的,所以是给 C 语言的编译器看的,在编译期间, C 语言会根据你写的指针类型给它们分配所需要的空间。
    (或者说是弱类型吧,不能说没有类型,而是只有简单的不同位数的整形,浮点型,而没有指针,数组,数组的数组之类的高阶的类型,因为汇编器是比较原始的,没有那么复杂的设计)

    再回到题主的问题:

    “ ptr = var; 这里是把数组 var 的第一个值得地址赋值给了 ptr 指针吗? 那可不可以这样写 ptr = &var[0];”

    这里有两个变量和类型:

    ptr ,它的类型是 int *,为指向整形的指针;
    var ,它的类型是 int [3],为有 3 个整形元素的数组。
    var[0],它的类型是 int ,是*(var+0)的语法糖,所以自然也可以写成*(0+var),进一步的写成 0[var]。
    而 & 表示取地址符的意思,所以 &var[0] 的类型是 int *。

    所以,后两者只是地址值是相等的,其类型是不同的。

    那么类型不同体现在什么地方呢?比如 sizeof(var) = 3*4 =12;而 sizeof(var) = 4 (假设为 32 位的机子)

    当然,还有一些场景,两者会相互转换,比如函数传参数,数组会退化成指针,楼主用 “ C language array & pointer difference ”搜索下估计就能搜到不少

    清楚了类型之后,可以看到,后者的写法是更加正确的,因为左右的类型都是 int *,而前者的写法左右两边类型是不同,有一个类型自动转化在里面,就是地址值过去了,类型给忽略掉了。
    mintist
        28
    mintist  
       2017-02-01 15:02:25 +08:00
    所以,一般个人在写的时候,会把 ptr = var;改成 ptr = (int*)var;,虽然必要性不大,但是这样写只是为了告诉自己,后面就用 int * 类型的指针去访问这段内存吧,的意思
    visionsmile
        29
    visionsmile  
       2017-02-02 20:31:02 +08:00
    @424778940 @lzhCoooder 数组名不是指针,标准里面是这么写的: Here x is a 3 × 5 array of integers. When x appears in an expression, it is converted to a pointer to (the first of three) five-membered arrays of integers. In the expression x[i] which is equivalent to *(x+i), x is first converted to a pointer as described; then x+i is converted to the type of x, which involves multiplying i by the length of the object to which the pointer points,namely five integer objects.
    lzhCoooder
        30
    lzhCoooder  
       2017-02-03 10:41:42 +08:00
    @visionsmile 数组名当然不是指针,我没说是指针呀...稍微写过一点就知道 sizeof 一个数组和一个指针结果是很不一样的,你搬出标准也只能证明数组名会被隐式转换成数组首地址,这我说的没错呀,一般用起来数组名就是代表首地址...
    visionsmile
        31
    visionsmile  
       2017-02-03 12:43:22 +08:00
    @lzhCoooder “你搬出标准也只能证明数组名会被隐式转换成数组首地址”,那不然还证明啥?“一般用起来数组名就是代表首地址...”,你这样说理解起来会有很大歧义....因为它并不“代表”首地址,只是在使用时会转换为指针。措辞还是要严谨一些啊。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5523 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 38ms · UTC 01:29 · PVG 09:29 · LAX 17:29 · JFK 20:29
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.