美文网首页编程ing
C语言的灵魂——指针

C语言的灵魂——指针

作者: 指尖极光 | 来源:发表于2017-03-04 17:53 被阅读73次

    一、指针简介

    1、什么是指针?

    指针是一个变量,其值为另一个变量的地址,即内存地址的直接地址。做个比喻,假设将你比作变量,那么你身份证上的住址就是指针,根据你身份证上的地址可以找到你,即指针存的内容是你身份证上的住址。

    指针有两种含义,一是作为数据类型,二是作为实体。

    指针作为实体,是一个用来保存一个内存地址的计算机语言中的变量。指针一般出现在比较底层的程序设计语言中,如C语言。高级语言如Java一般避免用指针,而是引用。指针作为数据类型,可以从一个函数类型、一个对象类型或者一个不完备类型中导出。从中导出的数据类型称之为被引用类型(referenced type)。指针类型描述了一种对象,其值为对被引用类型的实体的引用。

    指针可以用来有效地表示复杂的数据结构,可以用于函数参数传递并达到更加灵活使用函数的目的。使C语言程序的设计具有灵活、实用、高效的特点。

    2、*与&操作符

    取地址运算符(&):取变量的地址,即返回操作数的内存地址。&var 读作"var 的地址"。

    间接寻址运算符(*):返回操作数所指定地址的变量的值。

    3、如何使用指针?

    使用指针时会频繁进行以下几个操作:

    1. 定义一个指针变量;
    2. 把变量地址赋值给指针;
    3. 访问指针变量中可用地址的值。

    这些是通过使用一元运算符 * 来返回位于操作数所指定地址的变量的值。

    #include <stdio.h>
    int main (){
       int  var = 20;   /* 实际变量的声明 */
       int  *ip;/* 指针变量的声明 */
       ip = &var;  /* 在指针变量中存储 var 的地址 */
       printf("Address of var variable: %x\n", &var  );
       /* 在指针变量中存储的地址 */
       printf("Address stored in ip variable: %x\n", ip );
       /* 使用指针访问值 */
       printf("Value of *ip variable: %d\n", *ip );
       return 0;
    }
    

    当上面的代码被编译和执行时,它会产生下列结果:

    Address of var variable: bffd8b3c
    Address stored in ip variable: bffd8b3c
    Value of *ip variable: 20
    

    4、指针运算符

    C 指针是一个用数值表示的地址。因此,您可以对指针执行算术运算。可以对指针进行四种算术运算:++、--、+、-。

    假设 ptr 是一个指向地址 1000 的整型指针,是一个 32 位的整数,让我们对该指针执行下列的算术运算:

    ptr++
    

    在执行完上述的运算之后,ptr 将指向位置 1004,因为 ptr 每增加一次,它都将指向下一个整数位置,即当前位置往后移 4 个字节。这个运算会在不影响内存位置中实际值的情况下,移动指针到下一个内存位置。如果 ptr 指向一个地址为 1000 的字符,上面的运算会导致指针指向位置 1001,因为下一个字符位置是在 1001。

    5、NULL 指针

    在变量声明的时候,如果没有确切的地址可以赋值,为指针变量赋一个 NULL 值是一个良好的编程习惯。赋为 NULL 值的指针被称为空指针。NULL 指针是一个定义在标准库中的值为零的常量。请看下面的程序:
    #include <stdio.h>
    int main (){
    int *ptr = NULL;
    printf("ptr 的值是 %x\n", ptr );
    return 0;
    }

    当上面的代码被编译和执行时,它会产生下列结果:

    ptr 的值是 0
    

    二、指针与数组

    1、区别

    C++/C程序中,指针和数组在不少地方可以相互替换着用,让人产生一种错觉,以为两者是等价的。数组是连续分配一串单元,数目开始定义的时候就必须固定下来,看起来整洁,但是写的程序是死程序,容易浪费内存。指针是存放一个地址值,表示指向某一个单元,可以用指针来索引单元。数组可以完成栈,堆,树等等的操作,它在编程时候的好处是非常的灵活,在构建思路的时候有很大的灵活性。

    2、指针数组与数组指针

    指针数组:array of pointers,即用于存储指针的数组,也就是数组元素都是指针。

    数组指针:a pointer to an array,数组名本身就是一个指针,指向数组的首地址,即指向数组的指针。

    int* a[4] ;   /* 指针数组      
                     表示:数组a中的元素都为int型指针     
                     元素表示:*a[i]   *(a[i])是一样的,因为[]优先级高于*/
    int (*a)[4]  ;/* 数组指针      
                     表示:指向数组a的指针
                     元素表示:(*a)[i]   */
    
    #include <stdio.h>
    int main(void)
    {
        int c[4]={1,2,3,4};
        int *a[4]; //指针数组
        int (*b)[4]; //数组指针
        b=&c;
        //将数组c中元素赋给数组a
        for(int i=0;i<4;i++)
        {
            a[i]=&c[i];
        }
        //输出看下结果
        printf("%d",*a[1]);//输出2就对
        printf("%d",(*b)[2]);//输出3就对
        return 0;
    }
    

    三、指针与字符串

    C语言中没有特定的字符串类型,我们通常是将字符串放在一个字符数组中。字符数组归根结底还是一个数组,使用指针的方式来输出字符串:

    #include <stdio.h>
    int main(){
        char str[] = "http://www.jianshu.com/";
        char *pstr = str;
        int len = strlen(str), i;
        //使用*(pstr+i)
        for(i=0; i<len; i++){
            printf("%c", *(pstr+i));
        }
        printf("\n");
        //使用pstr[i]
        for(i=0; i<len; i++){
            printf("%c", pstr[i]);
        }
        printf("\n");
        //使用*(str+i)
        for(i=0; i<len; i++){
            printf("%c", *(str+i));
        }
        printf("\n");
        return 0;
    }
    

    四、指针与函数

    函数指针:本身是一个指针,指向一个函数入口地址,通过该指针可调用其指向的函数,使用函数指针可实现回调函数。

    #include <stdio.h>
    void inc(int *val)
    {
        (*val)++;
    }
    int main(void)
    {
        void (*fun)(int *);
        int a=3;
        fun=inc;//fun是一个函数指针
        (*fun)(&a);
        printf("%d" , a);
    }
    

    指针函数:本身是一个函数,其返回值是一个指针。

    #include <stdio.h>
    float *find(float(*pionter)[4],int n);//函数声明
    int main(void)
    {
         static float score[][4]={{60,70,80,90},{56,89,34,45},{34,23,56,45}};
         float *p;
         int i,m;
         printf("Enter the number to be found:");
         scanf("%d",&m);
         printf("the score of NO.%d are:\n",m);
         p=find(score,m-1);
         for(i=0;i<4;i++)
             printf("%5.2f\t",*(p+i));
         return 0;
     }
    float *find(float(*pionter)[4],int n)/*定义指针函数*/
     {
         float *pt;
         pt=*(pionter+n);
         return(pt);
     }
    

    五、指针与引用

    1. 引用总是指向一个对象,没有所谓的 null reference 。所有当有可能指向一个对象也有可能不指向对象则必须使用指针。由于C++ 要求 reference 总是指向一个对象所以 reference要求有初值.由于没有所谓的 null reference 所以在使用前不需要进行测试其是否有值,而使用指针则需要测试其的有效性。
    2. 指针可以被重新赋值而reference则总是指向最初或地的对象。
    3. 必须使用reference的场合.Operator[]操作符由于该操作符很特别地必须返回 [能够被当做ssignment 赋值对象] 的东西,所以需要给他返回一个 reference。
    4. 其实引用在函数的参数中使用很经常。格式如下:
        void Get***(const int& a){} //这样使用了引用又可以保证不修改被引用的值
    

    区别:

    • 指针是一个实体指向一块内存,它的内容是所指内存的地址;引用是某块内存的别名;
    • 引用使用时无需解引用(*),指针需要解引用;
    • 引用只能在定义时被初始化一次,之后不可变;指针可变;
    • 引用“从一而终”;
    • 引用没有 const,指针有 const,const 的指针不可变;
    • 引用不能为空,指针可以为空;
    • sizeof 引用”得到的是所指向的变量(对象)的大小,而“sizeof 指针”得到的是指针本身(所指向的变量或对象的地址)的大小;typeid(T) == typeid(T&) 恒为真,sizeof(T) == sizeof(T&) 恒为真,但是当引用作为成员时,其占用空间与指针相同(没找到标准的规定);
    • 指针和引用的自增(++)运算意义不一样。

    相关文章

      网友评论

        本文标题: C语言的灵魂——指针

        本文链接:https://www.haomeiwen.com/subject/vnfjgttx.html