C语言指针

来源:互联网 发布:淘宝怎么买二手冰箱 编辑:程序博客网 时间:2024/06/07 19:12

指针是C语言编程里重要的概念,被称为C语言的核心。C指针的优点是高效,所以其未对指针越界、野指针(即未显式初始化的指针)进行安全检查。俗话说任何事物有利弊性,指针也不例外。指针的弊端正是由于起为了追求高效引起的,主要体现在:内存越界地址的访问、野指针造成的正常值的意外修改、程序崩溃...,不过这些问题都是可以通过我们的学习积累逐渐避免的,所以这也就是为何很多人推崇C指针的原因吧。

什么是指针

指针是一种变量,形如 int  *ptr,这里的类型int只是泛指,它也可以是charfloat等类型,该语句表示指向相应类型变量的指针。指针变量和一般变量的最大区别是:指针中存放的是数据地址而不是数据本身,普通变量可以直接访问到数据,但是指针不行,指针要通过间接访问操作符*才能取得相应数据。

C语言为什么定义指针

由以上描述可知,C语言指针在取数值方面并不比一般变量取值方便,甚至可以用笨拙来形容(因指针不要间接访问才能取得数据),那为什么还需要C指针呢?那是因为某些方面C语言具有其他机制不可替代的作用。比如:内存分配回收、结构体的传参...

1)内存分配与回收

C语言赋予了程序员在内存使用上的灵活性,当需要内存时可以人为申请内存(通过malloc族函数),当不需要时可以人为释放内存(通过free函数)。而mallocfree的机制都是通过操作地址(即指针)来达到这个便利的。

【注意】

通过malloc申请内存使用后,必须通过free人为释放,否则易造成内存泄漏。

  1. 结构体传参

    C语言的传参属于值传递,所谓值传递即产生一个原参数的副本,当传送的值过大(如大的结构体)就会增大系统的开销,尤其是当结构体使用频繁时这种弊端就越加明显,它会过多占用内存,变缓程序执行效率。但是使用指针进行传参就不会有这种效率问题,指针一般占机器字节个内存,开销相对较小。

指针初始化很有必要

申明指针而不显式初始话,指针的值大体上分三种:0值、错误边界值、正常地址。

10

指针未被显式初始化,它可能会被赋值为0值,0值是一个非法地址,对它访问将会产生段错误从而终止程序。程序发生这种现象算是比较好的,这样我们可以在程序出错时主动查找隐藏的错误并解决掉它。

  1. 错误边界值

    我们已经知道整型数据存储于整型所占字节数的整数倍的地址上,但未被初始化的指针可能打破这种规则,如int *ptr; ptr所存地址可能是3的整数倍(注意:仅仅是可能),那么此时对该指针执行间接访问时会报错,这种错误在unix系统下称为“总线错误”。这也是一种相对而言你应该庆幸的结果,下面这种情况则会使人特别抓狂。

  2. 正常地址

    未被显式初始化的系统默认分配的初始化值有可能已经是其他变量的地址,这种情况就十分危险了,当对指针变量执行间接访问操作时产生的后果就是你更改了原来变量的值,这很可能不是你希望看到的结果。由于这种错误的隐秘性你很难查到问题的根源,因为引发这种错误的代码与你原定义变量的那段代码甚至完全不相干。

    综合以上三点,指针初始化很有必要,务必牢记。

指针的指针

我们可以定义指针变量来存储其他变量的地址,那么可以定义一个变量来存储指针的地址吗?答案是肯定的。指针的指针就用于存放指向变量的指针的地址。指针的指针被称为二级指针,只要你原意,你也可以定义三级指针、四级指针...,但实际编程中我们一般最多定义到二级指针。二级指针定义如下:

 /* 二级指针形式 */
 int i = 10;//普通变量
 int *j = &i;//j为指向i的指针,存放着变量i的地址
 int **k = &j;//k为指向j的二级指针,存放着一级指针j的地址

指针的运算

算术运算

指针可以执行算术运算,实例如下:

 int i = 3,j = 4,num = 5;
 char c = 'c';
 int *ptr1 = &i,*ptr2 = &j;
 char *ptr3 = &c;

 /* 指针的算术运算 */
 ptr1+ptr2;//语法错误,将两个地址相加毫无意义
 ptr1*ptr2;//语法错误,将两个地址相乘毫无意义
 ptr1/ptr2;//语法错误,将两个地址相除毫无意思
 ptr1-ptr2;//语法正确,求两个地址间相差多少个指针类型变量。一般用在数组或连续内存区域中
 ptr1-ptr3;//语法错误,不同类型指针相减毫无意义
 ptr1+num;//语法正确,求ptr后第num个类型变量的地址。一般用于数组或连续内存区域中
 ptr1-num;//语法正确,求ptr前第num个类型变量的地址。一般用于数组或连续内存区域中

关系运算

指针可以执行关系运算,实例如下:

 /* 指针的以下关系运算都是合法的,它们常用于循环处理一片内存区域 */
 ptr1>ptr2;
 ptr1<ptr2;
 ptr1==ptr2;
 ptr1>=ptr2;
 ptr1<=ptr2;

指针变量或运算含义浅析

关于指针有很多易混淆的概念,以下浅析常用到的形式:

 int const *p;//(1)
 const int *p2;//(2)
 /* (1)与(2)含义相同,表示指向整型常量的指针。即:指针本身可修改、但其指向内容不可修改 */
 
 int * const p3 = &i;//(3)
 /* (3)定义了指针常量,即:其本身不可以修改,但其指向的内容可以修改 */

 int const * const p4 = &i;//(4)
 /* (4)定义指向常量值的指针常量,即:指针本身与指针指向的内容均不可修改 */

 ptr1++;//ptr1指向下一个变量的地址,常用与数组或连续内存区域中
 ptr1--;//ptr1指向上一个变量的地址,常用于数组或连续内存区域中

【总结】

  1. 指针是一种特殊变量,其值为变量的地址

  2. 指针是一把双刃剑,熟悉其语法使你能写出安全高效的代码

  3. 二级指针用来存放指针的地址

  4. 指针可以执行运算,但是有一定的限制

  5. 最最重要的,使用指针一定要记得初始化

1 0