从0开始学习C语言————指针

指针简介:

 什么是指针:

  指针是一种数据类型,使用它可以定义指针变量,这种变量里存储是整数,这种整数代表了内存的编号,每个整数对应一个字节,使用指针变量可以访问对应的内存,具体访问的多个字节由指针的类型决定。

 什么时候使用指针:

  从理论上讲指针可以访问任何位置的内存,但绝大部分的内存我们没有权限访问,因此非常容易产生段错误,因此建议只有合适的时候才使用指针。

函数之间共享局部变量:
    由于全局变量浪费内存,还可能造成命名冲突,所有全局变量不适合大量共享。
    而函数传递默认是值传递,无法共享,所以指针是函数之间共享局部变量的最好选择。

提高函数的传递效率:
    而函数传递默认是值传递(内存拷贝),当变量的字节数较多时,传递变量的地址效率更高,只需要4/8字节。
    但这样就带来了变量被修改的风险,可以使用const配合指针来保存变量。

配合堆内存使用:
    堆内存无法取名(不能与标识符建立映射关系),因此必须与指针配合使用。

 如何使用指针:

 定义指针变量:类型* 指针变量_p;
  1、由于指针变量的用法与普通变量不同,为了避免与普通变量混淆,指针变量一般以p结尾。
  2、指针变量不能连续定义
    int* p1,p2; // p1 是指针,p2 是int类型变量
    int *p1,*p2; // p1、p2 都是指针
  3、指针变量与普通变量一样默认值是随机(野指针),为了安全一定初始化,如果不知道赋值什么值,可以赋值为NULL(空指针)。
  4、指针的类型决定了访问内存时的字节数。
 指针变量的赋值:
    用变量的地址赋值:p = #
    用堆内存地址赋值:p = malloc(sizeof(*p));
 指针变量的解引用:*指针变量
    通过指针变量中存储内存编号去访问内存,具体访问多个字节由指针变量的类型决定。
    该过程可能产生段错误,但要从指针变量赋值的步骤寻找原因。

 指针的运算:

   指针变量中存储的是整数,理论上整型数据能使用的运算符,指针变量都可以使用,但只有以下运算有意义:
      指针 + n <=> 指针+(n字节数)
      指针 - n <=> 指针-(n
字节数)
      指针 - 指针 <=> (指针-指针)/字节数 只有类型相同的指针才可能相减。

使用指针要注意的问题:

 空指针:

  都是指针变量的值为NULL的指针被称为空指针,这种指针不能解引用,否则会产生段错误。
   大多数系统的NULL是0地址,可以把指针变量当逻辑值使用,但不建议这样。
   为了避免空指针导致的段错误,当使用来历不明的指针时应判断是否是空指针。
   if(NULL == p)
  {

  }

 野指针:

  指针变量的值是随机的、不确定,这种指针称为野指针,使用野指针不一定立即出错,也不一定会出错,与空指针相比它的危害更大。
  无法判断一个指针变量是否是野指针,所有为了避免野指针导致的Bug,我们应该避免产生野指针。
     1、定义指针变量时一定要初始化。
     2、指向变量所指向的内存被释放、销毁后,指针变量要及时赋值为NULL。
     3、函数不返回局部变量的地址。

指针与const:

const int* p; 保护目标不被*p修改。
int const *p; 同上
int* const p; 保存指针变量p不被修改
const int* const p; 既保存p也保存*p
int const * const p; 同上

指针数组与数组指针:

指针数组:由指针变量组成的数组,它的身份是数组,成员是指针变量。
    类型* arr[n];
    int* arr[10];
数组指针:它的身体是指针,专门用来存储数组的地址。
    类型 (*变量名)[n];
    int (*arr) [5];
    注意:数组指针是以数组字节宽度为移动单位。

指针类型:

 void指针:

   1、以1字节为单位移动
   2、不能解引用
   3、可以与任何类型的指针自动类型转换(C语言)
   4、一般用作函数的参数、返回值

 函数指针:

    函数会反翻译二进制指令存储到代码段,而函数名就这段指令的首地址。
    可以定义特殊的指针变量存储函数的首地址,这样就可以把函数当前数据进行传递。
    我们把存储函数地址的指针变量叫做函数指针。
    如何定义函数指针:
     1、复制函数的声明语句
     2、给函数名加上小括号并在函数名前加一个*
     3、给函数名重新取函数指针变量名
    当我们把函数作为数据传递时,被调用的函数可以通过函数指针调用我们以参数形式提供的函     数,这种模式叫回调模式,比如:qsort、bsearch。
    由于函数指针的类型比较长,一般会选择使用 typedef 进行类型重定义。
     void func(int,int);
     typedef void (*FP)(int,int);

 二级指针:

  一级指针里面存储普通变量的地址,二级指针里面存储的是一级指针变量的地址。
   当跨函数共享指针变量时,需要使用二级指针。
   定义二级指针:
   类型** 变量名_pp;

   二级指针的赋值:
     int num;
     int* p = #
     int** pp = &p;

   二级指针解引用:
     *pp <=> p;
     **pp <=> *p;

指针与数组名的关系:

  数组名就是数组空间的首地址,是一个常量地址,可以把它看作常指针。
   数组名可以使用解引用的语法访问成员,指针也可以使用[]解引用,所以:
   arr[n] <=> (arr+n);
   与普通指针的区别:
     1、数组名是常量,普通指针是变量
     2、普通指针变量有自己的存储空间,用来存储内存编号,它与目标内存是指向关系。
     3、数组名没有自己的存储空间,它就代表数组空间的首地址,它与数组内存是映入关系。
     4、对数组名取地址结果还是数组名的值。
      int arr[5]
       arr <=> &arr;
      arr 类型 int

      &arr 类型 int (*)[5]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值