• 数组,指针和引用


    一,指针

    1,指针的类型

      指针的类型和指针所指向的类型

     
    指针的类型
    指针所指向的类型
    sizeof(*ptr) 说明
    int *ptr; 
    int *
    int 
    4
     
    int **ptr;
    int **
    int * 
    4
     
    int (*ptr)[3];
    int(*)[3] 
     int()[3] 
    12
    指向有3个int型元素的数组
    int (*ptr)(int);
    int (*)(int)
     int ()(int)
     
    指向函数的指针,该函数有一个整型参数并返回一个整型数

        说明:

        a,指针的类型:是指针本身所具有的类型。把指针声明语句里的指针名字去掉,剩下的部分就是这个指针的类型。

        b,指针所指向的类型:决定指针所指向的那片内存的大小和编译器怎么看待这片内存。 把指针声明语句中的指针名字和名字左边的指针声明符 *去掉,剩下的就是指针所指向的类型。

        c,指针的值:在32位系统中,它是一个32位的整数,是一个地址。其所占的内存是4byte

        指针所指向的类型和指针所指向的内存是不同的,一个指针被定义时,指针所指向的类型已经确定,但由于指针未初始化,它所指向的内存区是不存在的

      指针数组

        int *a[3];    //一个有3个指针的数组,该指针是指向一个整型数的。sizeof(a)=12,sizeof(*a)=4

        int (*a[10])(int);  //一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数

    2,指针的强制类型转换的应用

      a,新指针的类型是TYPE*:  ptr1=(TYPE*)ptr2

    注意:如果sizeof(ptr2的类型)大sizeof(ptr1的类型),那么在使用指针ptr1来访问ptr2所指向的存储区时是安全的。如果sizeof(ptr2的类型)小于sizeof(ptr1的类型),那么在使用指针ptr1来访问ptr2所指向的存储区时是不安全的。

      b,调用地址为0x30008000的函数:
          void (*p)(int *, char *);//定义函数指针
          p=(void (*)(int *,char *))0x30008000;
        将100赋给地址为0x804a008:
          *((int *)0x804a008) = 100;
      c,动态分配
        char *p
        p= (char *)malloc(sizeof(char));  //malloc()返回void型的指针 
     

    3,函数指针

      定义:void (*pf)(char *);   //pf是指向void,参数是char* 的类型的函数的指针。

      赋值:void fun(char *);  fp=fun;

      调用方法

        (*fp)(name);  或者  fp(name);

        ANSI C支持这两种;unix支持第二种;K&R C支持第一种。

    注意区分 void *pf(char *);   //pf是返回一个指针的函数

     

    二,数组

    1,一维数组:

    <1>指定初始化项目(C99):int date[4] = {[0]=1,[5]=5};  其他项为0。

    <2>数组名是该数组首元素的地址:date==&date[0],是一个指向int型的常量指针

    <3>对指针加1,等价于对指针的值加上它指向的对象的字节大小:date+2==&date[2]   *(date+2)==date[2]

    <4>保护数组的内容:int sum(const int ar[],int n);

    <5>数组做函数形参: int sum(int *ar,int n);int sum(int ar[],int n);

    2,指针和多维数组

      二维数组初始化:date={{1,2,3},{4,5,6}} 也可以省去{}。

      指向二维数组的指针:int zippo[4][2];   和   int (*pz)[2];

         pz指向包含两个int值的数组,即是指向二维数组,该二维数组有2列。使用该类型指针时注意不要超过二维数组的行数的范围

    pz=zippo;  
    zippo==&zippo[0]; zippo[0]==&zippo[0][0]; zippo==&(&zippo[0][0]);
    *(zippo+2)==zippo[2]==&zippo[2][0]  //第三个元素,即包含2个int值的数组
    *(*(zippo+2)+1)==zippo[2][1]

      指针兼容:

    int **p1;int *p2[2];
    p1=pz;(非法)//pz是指向int[2]型的指针。p1是指向int *的指针
    p1=p2;(合法)

      二维数组做函数形参:

        void fun(int (*pz)[2]);  或   void fun(int pz[][2]);

     3,指针变量作为函数参数

    <1>实参变量和形参变量之间数据传递是单向的。不可能通过函数调用来改变实参指针变量的值,但可以改变实参指针变量所指变量的值
    void swap(int *p1,int *p2){int temp;temp=*p1;*p1=*p2;*p2=temp;}    //a,b(*pp1,*pp2)的值可以互换
    void main(){int a=1, b=2;  int *pp1=&a,*pp2=&b;  swap(pp1,pp2)}      
     
    void swap(int *p1,int *p2){int * temp;temp=p1;p1=p2;p2=temp;} 
    //只是改p1,p2的地址,pp1,pp2不能改变,*p1,*p2(*pp1,*pp2)的值没有改变。因此不能交换a,b

    <2>如果想要改变的是指针变量p的值,就要传递p的地址。

    void getmemory(char *p, int num)
    {
        p = (char *)malloc(sizeof(char)*num);
    }
    void test()
    {
        char *str = NULL;
        getmemory(str, 100);   //此时str仍为NULL
        strcpy(str, "hello");       //出现段错误
    }
    
    正确写法有两种:
    a种方法
    void getmemory(char **p, int num)                        
    {
        *p = (char *)malloc(sizeof(char)*num);
    }
    void test()
    {
        char *str = NULL;
        getmemory(str, 100);   
        strcpy(str, "hello");
        free(str);      
    }
    
    b种方法
    char* getmemory( int num)                        
    {
        return (char *)malloc(sizeof(char)*num);   //返回的指针指向堆区
    }
    void test()
    {
        char *str = NULL;
        str = getmemory(100);   
        strcpy(str, "hello");
        free(str);      
    }

    三 , 引用

      引用是C++中新增的一种复合类型,引用是对象的别名,其典型的用途是作为函数参数,具体的说是结构和对象的参数。

    1,引用的定义和作为函数参数

    //定义
    int rats;
    int & rodents = rats;
    int * rodentsp = &rats;
    //作为函数参数
    void swap(int &a, int &b)
    {
        int temp;
        temp = a;
        a = b;
        b = temp;
    }
    void main()
    {
        int a = 30 , b = 20;
        swap(a, b);
    
    }
    View Code

      引用作为函数参数使得函数中的变量名成为调用程序中变量的别名,这种传递方式成为引用传递。引用传递允许被调用函数能够访问调用函数中的变量;而C语言只能按值传递,被调用函数使用调用函数的值的拷贝。

     2,临时变量,引用参数和const

    double refcube(const double &ra)
    {
        retirn ra*ra*ra;
    }
    //下面的调用方式都将产生临时变量
    double side = 3.0;
    long edge = 5L;
    double c1 = refcube(side + 10.0); //表达式
    double c2 = refcube(7.0);  //传递常量
    double c3 = refcube(edge); //类型不符合
    View Code

      若refcube函数的参数不是const型的,则不能产生临时变量,即上述的调用方式将出错。若声明将引用定义为const,则在必要时产生临时变量,其行为类似于按值传递。

    3,将const用于引用返回类型

    typedef struct point
    {
        int x;
        int y;
    }Point;
    
    Point &accumulate(Point &p1, const Point &p2)
    {
        p1.x += p2.x;
        p1.y += p2.y;
        return p1;
    }
    
    void main()
    {
        Point p1 = {1, 2};
        Point p2 = {3, 4};
    
        //p1, p3的值是一样的,函数返回的是传入的p1的引用
        Point p3 = accumulate(p1, p2); 
    
        //函数返回的是p1的引用,所以这个语句是可行的。若是按值返回,则不能通过编译
        accumulate(p1, p2) = p2;
    }
    View Code

       返回的非const引用使其含义模糊;将返回的引用声明为const,则最后一条语句不合法。

       返回引用时,需注意:应避免返回函数终止时不再存在的内存单元的引用

    4,传值,传指针,传引用

    <1>如果数据对象很小,则按值传递

    <2>如果数据对象是数组,则使用指针。因为这是唯一的选择。

    <3>如果数据对象是较大的结构,则使用引用或指针

    <4>如果数据对象是类对象,则使用引用。类设计的语义常常要求使用引用。

    传指针和引用时,若不修改调用函数的数据,尽量使用const修饰

      

    四,指针与引用的区别

    http://blog.csdn.net/listening_music/article/details/6921608

    1,指针与引用的区别

    a,引用不可为空;指针可以是空的。使用指针之前必须做判空操作,而引用就不必

    b,引用在定义的时候初始化,且不能再被赋值,其本身是常量;而指针是变量

    c,引用的大小是所指向的便量的大小;指针是指针本身的大小

    d,指针和引用的自增(++)运算意义不一样。指针的自增是指针指向的地址加1,引用则是所代表的内存的值加1.

    d,指针指向一块内存,它的内容是所指内存的地址;而引用是某块内存的别名,且引用不改变指向。

    2,常量指针和常量引用

         指向常量的指针和引用: const int *pointer = &i;             const int& refs = i;

     这里*pointer是常量,不能通过指针修改这块内存,该指针也不能赋给其他非常量指针;常量引用也是一样,所代表的内存是常量,不能通过该引用改变这块内存。

    五,注意

    <1>int days[]={....},sizeof days是整个数组的大小;sizeof day[0]是一个元素的大小(以字节为单位)

    <2>C并不检查你是否使用了正确的下标,例如:int a[10];a[10]=12;编译器不会发现这样的错误。当程序运行时,这些语句把数据放在可能由其他数据使用的位置,因而可能破坏程序的结果甚至使程序崩溃。

    <3>在返回指针变量时,注意不要用return返回指向栈内存中的指针。否则,函数返回后该指针指向的内存被释放。

    <4>当创建一个指针时,系统只分配了用来存储指针本身的内存空间,并不分配用来存储数据的内存空间。因此在使用指针之前,必须给它赋予一个分配的内存。(可用malloc或把一已存在的变量地址赋给指针)。

  • 相关阅读:
    【算法学习笔记】76.DFS 回溯检测 SJTU OJ 1229 mine
    【算法学习笔记】75. 动态规划 棋盘型 期望计算 1390 畅畅的牙签盒(改)
    【算法学习笔记】74. 枚举 状态压缩 填充方案 SJTU OJ 1391 畅畅的牙签袋(改)
    【算法学习笔记】73.数学规律题 SJTU OJ 1058 小M的机器人
    【算法学习笔记】72.LCS 最大公公子序列 动态规划 SJTU OJ 1065 小M的生物实验1
    【算法学习笔记】71.动态规划 双重条件 SJTU OJ 1124 我把助教团的平均智商拉低了
    【算法学习笔记】70.回文序列 动态规划 SJTU OJ 1066 小M家的牛们
    【算法学习笔记】69. 枚举法 字典序处理 SJTU OJ 1047 The Clocks
    【算法学习笔记】68.枚举 SJTU OJ 1272 写数游戏
    【算法学习笔记】67.状态压缩 DP SJTU OJ 1383 畅畅的牙签袋
  • 原文地址:https://www.cnblogs.com/zhoutian220/p/4000893.html
Copyright © 2020-2023  润新知