为了账号安全,请及时绑定邮箱和手机立即绑定

C语言-指针

标签:
C

指针pointer

数据类型决定了变量可以表示的数值范围。除此之外,表示变量在内存中生命期范围存储期以及变量名也都是变量的重要属性。

取址运算符-address operator

单目运算符`&`     `&a`     取得`a`的地址(生成指向a的指针)

取址运算符&的功能是取得对象的地址。

对于使用register关键字声明的寄存器对象,不能加上取址运算符&.

指针

int foo = 178;int *pf = &foo;    
printf("pointer value == %d\n", *pf);printf("foo value == %d\n", foo);//pointer value == 178//foo value == 178

上例中,变量名前加*,通过该声明定义了指向int型变量的指针变量,他们指向的是int型变量。

以上的两种形式可以理解为:

int型变量: 保存整数的盒子

指向int型变量的指针变量:保存存放整数对象的地址的盒子。

指针运算符

单目运算符 *    *p     p指向的对象

根据上例,可以得出:

*pf就是foo*pffoo的别名(alias)

解引用

通过在指针前写上指针运算符*来访问该指针指向的对象,称为解引用(dereference)

例: *pf

指针的类型

指向Type型对象的指针,即Type*型指针。

并不是表示指向OO号,更确切地说是指向以OO号为首地址的Type型对象

空指针 - null pointer

什么也不指向的特殊指针是空指针(null pointer),表示空指针的对象式宏NULL是空指针的常量。

指针和数组

数组名原则上会被解释为指向该数组起始元素的指针。

指针p指向数组中的元素e时,
p + i为指向元素e后第i个元素的指针
p - i为指向元素e前第i个元素的指针

void array_pointer(void){    int a[5] = {1, 2, 3, 4, 5};    int *p = a;    
    for (int i = 0; i < 5; i++) {        printf("&a[%d] = %p p+%d = %p\n", i, &a[i], i, p+i);
    }
} /*
     &a[0] = 0x7ffeefbff4f0 p+0 = 0x7ffeefbff4f0
     &a[1] = 0x7ffeefbff4f4 p+1 = 0x7ffeefbff4f4
     &a[2] = 0x7ffeefbff4f8 p+2 = 0x7ffeefbff4f8
     &a[3] = 0x7ffeefbff4fc p+3 = 0x7ffeefbff4fc
     &a[4] = 0x7ffeefbff500 p+4 = 0x7ffeefbff500
*/
数组名在什么情况下不被视为指向起始元素的指针
  • 作为sizeof运算符的操作数出现时

sizeof(array)不会生成指向起始元素的指针的长度,而是生成数组整体的长度

  • 作为取址运算符&的操作数出现时

&数组名不是指向起始元素的指针的指针,而是指向数组整体的指针。

指针运算符和下标运算符

当指针p指向数组中的元素e时,
指向e后第i个元素的*(p + i),可以写为p[i];
指向e前第i个元素的*(p - i),可以写为p[-i]

Type*型指针p指向Type型数组a的起始元素a[0]时,指针p的行为就和数组a本身一样。

数组的下标表示位于起始元素后的第几个元素的位置,因此必须从0开始。

虽然可以为指针加上整数,但是指针之间相加是不可以的

下标运算符的操作数

* (p + i)

括号内的p + i, 是pi的加法运算。和算术类型的数值间的加法运算a + b等同于b + a一样, p + i也等同于i + p

也就是说, * (p + i)* (i + p)是等价的。

这样一来,是不是访问数组元素的表达式p[i]也可以写成i[p]呢。实际上确实是可以的。

下标运算符[],是具有两个操作数的双目运算符。

其中一个操作数的类型是:

  • 指向Type型对象的指针

另一个操作数的类型是:

  • 整数类数据类型

下标运算符[]的操作数的顺序是随意的。就像a + b等同于b + a一样, a[3]3[a]也是一样的。

下标运算符[]所生成的值的类型是

  • Type

指针p指向数组a的起始元素a[0]时,
a[i]    *(a + i)        p[i]      *(p + i)

这4个表达式表示的都是相同的元素。实际上

a[i]   i[a]   *(a + i)   *(i + a)    p[i]    i[p]    *(p + i)    *(i + p)

这8个表达式表示的都是相同的元素。

数组和指针的不同点

int *p;int y[5];
p = y;    //OKint a[5];int b[5];
a = b;    //错误

赋值表达式的左操作数不可以是数组名。

数组的传递

在函数间传递数组时,可以灵活应用指针和数组的相似性。

void arr_set(int v[], ...){   /*----do sth------*/}void arr_set(int v[5], ...){   /*-----do sth-----*/}void arr_set(int *v, ...){   /*-----do sth-----*/}

以上三个函数, 第一个和第二个都可以解释为第三个。 形参V的类型不是数组, 而是指针。即使像第二个函数那样指定元素个数,该值也会被无视

调用上述arr_set函数时,int*型的形参V将使用实参a,即&a[0]进行初始化。



作者:Jeremy_L_Wang
链接:https://www.jianshu.com/p/682fc61e04c7


点击查看更多内容
1人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消