• 数组,指针和引用


    一,指针

    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或把一已存在的变量地址赋给指针)。

  • 相关阅读:
    【原】泛型委托
    【原】web页面登陆验证
    【原】在一般处理程序中设置session
    16Aspx.com-PHP企业整站源码 景观石材大理石类织梦模板 含手机移动端 完整源码 APP+PC
    16Aspx.com-将15位身份证转换成18位
    16Aspx.com-书通网中小学生免费在线学习网站源码 带采集带手机版帝国cms内核
    16Aspx.com源码2014年7月详细
    Web电子商务网(三层)V2.0源码
    毫秒级百万数据分页存储过程
    C#做的一个加密/解密的类
  • 原文地址:https://www.cnblogs.com/zhoutian220/p/4000893.html
Copyright © 2020-2023  润新知