cio
V2EX  ›  C

C 语言 指针问题

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

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

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

    C 语言中所有类型都是静态的。不存在不确定的类型。
    snnn
    snnn
    Jan 31, 2017
    26
    @ryd994 “考虑这 short *a=1; long *b=2 ”

    你这代码编译不过去。
    mintist
    mintist
    Feb 1, 2017❤️1
    27
    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
    mintist
    Feb 1, 2017
    28
    所以,一般个人在写的时候,会把 ptr = var;改成 ptr = (int*)var;,虽然必要性不大,但是这样写只是为了告诉自己,后面就用 int * 类型的指针去访问这段内存吧,的意思
    visionsmile
    visionsmile
    Feb 2, 2017
    29
    @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
    lzhCoooder
    Feb 3, 2017
    30
    @visionsmile 数组名当然不是指针,我没说是指针呀...稍微写过一点就知道 sizeof 一个数组和一个指针结果是很不一样的,你搬出标准也只能证明数组名会被隐式转换成数组首地址,这我说的没错呀,一般用起来数组名就是代表首地址...
    visionsmile
    visionsmile
    Feb 3, 2017
    31
    @lzhCoooder “你搬出标准也只能证明数组名会被隐式转换成数组首地址”,那不然还证明啥?“一般用起来数组名就是代表首地址...”,你这样说理解起来会有很大歧义....因为它并不“代表”首地址,只是在使用时会转换为指针。措辞还是要严谨一些啊。
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   1467 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 58ms · UTC 16:50 · PVG 00:50 · LAX 08:50 · JFK 11:50
    ♥ Do have faith in what you're doing.