zoukankan      html  css  js  c++  java
  • 数组类型与sizeof与指针的引用

    以char类型为例:

    char a[100];     //a类型为char[100]    &a类型为 char (*)[100]    *a类型为char

    char *p = a;    //p类型为 char*, *p类型为char。 也可以写成char *p = &a; 类型char[100]和char (*)[100]可隐式到char*转化,指向第一个元素的地址。不包含隐式转换的写法应该:char *p  = &a[0];   而它们的区别:

    再看

    #include <iostream>
    
    void test(char *p) //即使形参为char p[]或char p[100]
    {
        //p类型为char *,一指针类型。即使传递的实参类型是char[100],也会退化到char*
        std::cout << sizeof(p) << std::endl; //编译时计算,指针大小为4
        
        p[0] = 'z';
    }
    
    int main()
    {
        char a[100] = "abcdef";
        test(a);
    
        std::cout << a << endl;//"zbcdef"  
        return 0;  
    }

    要想test函数里sizeof正确输出大小,test函数的形参可以改为char (*p)[100]或 char (&p)[100] ,指定大小为100是必要的,因为char[100]不能转为char (&)[],char (*)[100]也不能转为char (*)[] 。那么定义a时改为char a[] = "abcdef";可不可以呢~~~不行,a的数组大小编译时计算,它的实际类型为char[7]而不是char[]

    #include <iostream>
    
    void test(char (*p)[100])
    {
        std::cout << sizeof(*p) << std::endl; //形参已经显示指定大小了,可以肯定输出100了。
    
        (*p)[0] = 'z';
    }
    
    int main()
    {
        char a[100] = "abcdef";
        test(&a);
    
        std::cout << a << std::endl;//"zbcdef"
        return 0;  
    }
    使用char (*p)[100]
    #include <iostream>
    
    void test(char (&p)[100])
    {
        std::cout << sizeof(p) << std::endl; //形参已经显示指定大小了,可以肯定输出100了。
    
        p[0] = 'z';
    }
    
    int main()
    {
        char a[100] = "abcdef";
        test(a);
    
        std::cout << a << std::endl;//"zbcdef"
        return 0;  
    }
    使用char (&p)[100]

    传递指针变量时,有时可能需要传递的是指针的指针或指针的引用
    有时,如果直接传递指针,结果可能不是你想要的,如:

    #include <iostream>
    
    void AllocMem(char *p, int size)
    {
        if(p != NULL)
            delete []p;
    
        p = new char[size];
    }
    
    int main()
    {
        char *pstr = NULL;
        AllocMem(pstr, 100);
        
        //然而pstr依旧为NULL,执行下面的语句将运行出错
        //strcpy(pstr, "hello world");
        //...
    
        delete []pstr;
        return 0;  
    }

    若传递指针的引用,正常工作:

    #include <iostream>
    
    void AllocMem(char *&p, int size)
    {
        if(p != NULL)
            delete []p;
    
        p = new char[size];
    }
    
    int main()
    {
        char *pstr = NULL;
        AllocMem(pstr, 100);
        
        strcpy(pstr, "hello world");
        std::cout << pstr << std::endl;//正常输出 hello world
    
        delete []pstr;
        return 0;  
    }
    #include <iostream>
    
    void AllocMem(char **p, int size)
    {
        if(*p != NULL)
            delete [](*p);
    
        *p = new char[size];
    }
    
    int main()
    {
        char *pstr = NULL;
        AllocMem(&pstr, 100);
        
        strcpy(pstr, "hello world");
        std::cout << pstr << std::endl;//"hello world"
    
        delete []pstr;
        return 0;  
    }
    指针的指针

    指针的指针使用较繁琐,而指针的引用在语法操作上和指针相似,而且还有上面例子里使用时的好处。不使用指针直接用指针的引用多好啊~~~然而:

    //假设Windows编程/MFC下~
    
    char* RectToStr(char *&p /*指针的引用*/, RECT rc)
    {
        //将RECT结构体里的left top right bottom转为一定格式的字符串,如"左上:(30, 40) 宽:100 高:70"
        //...
    
        return p;
    }
    
    int ShowPosition()
    {    
        RECT rc;
        GetWindowRect(&rc);
    
        //有时为了方便,你不想用new/delete操作,直接使用局部数组
        char str[100];
        AfxMessageBox(RectToStr(str, rc)); //编译出错,会提示:无法将参数 1 从“char [100]”转换为“char *&”
        return 0;  
    }

      为了方便和重复使用,将RECT转化为字符串的操作封装为一个函数是合理的。参数char *&p用指针的引用似乎也是合理的,因为函数封装者可能希望传递进来的指针为NULL或者指针指向的内存大小不够时,函数里面重新p = new char[xxx]分配一下(如上文中的AllocMem函数),操作完后返回p,至于delete操作,将假设由调用者自己调用了。

      然而上例中,编译出错了,调用者传递的是个字符数组,char[100]不能转换为char *&。 当然:

        char str[100];
        char *p = str;//////////
        AfxMessageBox(RectToStr(p, rc)); //ok,正常工作了

    但竟让调用者来适应RectToStr函数......这函数就是个失败的封装

    你可能想,如果不用指针的引用作判断,那么传入到RectToStr的指针是个空指针甚至是个野指针怎么办??这不是你该管的事了,是调用者的事情,你可以做个判断或简单的加个断言 assert(p != NULL) 或抛出异常。strcpy strcat等标准函数对这些情况处理了吗?你strcpy(NULL, "abc")试试~。

    所以何时使用指针,何时使用指针的引用,需要你根据实际情况和用途去判断,,,


    sizeof一些更特殊的用法:---引见http://www.cnblogs.com/lidabo/archive/2012/08/27/2658519.html

    • 可对函数类型--但不能对函数名使用sizeof              ----对函数使用sizeof,在编译阶段会被函数返回值的类型取代
    int f1(){return 0;};
    double f2(){return 0.0;}
    void f3(){} 
    
    cout<<sizeof(f1())<<endl; // f1()返回值为int,因此被认为是int
    cout<<sizeof(f2())<<endl; // f2()返回值为double,因此被认为是double
    cout<<sizeof(f3())<<endl; // 错误!无法对void类型使用sizeof
    cout<<sizeof(f1)<<endl; // 错误!无法对函数名使用sizeof 
    cout<<sizeof*f2<<endl; // *f2,和f2()等价,因为可以看作object,所以括号不是必要的。被认为是double
    • 这个很好
    double* (*a)[3][6];
    cout<<sizeof(a)<<endl; // 4 , a类型为double* (*)[3][6],是个指针,指向double* [3][6] 
    cout<<sizeof(*a)<<endl; // 72 , *a类型为double* [3][6],一个多维数组,数组里的数据类型是指针 3*6*4=72
    cout<<sizeof(**a)<<endl; // 24 , **a类型为double* [6]
    cout<<sizeof(***a)<<endl; // 4 , ***a类型为double*
    cout<<sizeof(****a)<<endl; // 8 , ****a类型为double
    •  sizeof -- 是个关键字,不是函数,它在编译阶段求值

      使用:

      1. sizeof(object)   对对象使用sizeof,也可以写成sizeof object 的形式
      2. sizeof(typename)    对类型使用sizeof,注意这种情况下写成sizeof typename是非法的

    int i = 2;
    cout<<sizeof(i)<<endl; // sizeof(object)的用法,合理
    cout<<sizeof i<<endl; // sizeof object的用法,合理
    cout<<sizeof 2<<endl; // 2被解析成int类型的object, sizeof object的用法,合理
    cout<<sizeof(2)<<endl; // 2被解析成int类型的object, sizeof(object)的用法,合理
    cout<<sizeof(int)<<endl;// sizeof(typename)的用法,合理
    cout<<sizeof int<<endl; // 错误!对于操作符,一定要加()
  • 相关阅读:
    OSPF
    【今日CS 视觉论文速览】 24 Jan 2019
    【今日CS 视觉论文速览】Wed, 23 Jan 2019
    【今日CS 视觉论文速览】 21 Jan 2019
    【Processing学习笔记】安装与入门
    【今日CS 视觉论文速览】Part2, 18 Jan 2019
    【今日CS 视觉论文速览】Fri, 18 Jan 2019
    【今日CS 视觉论文速览】Thu, 17 Jan 2019
    【今日CS 视觉论文速览】Part2, 16 Jan 2019
    【今日CS 视觉论文速览】Wed, 16 Jan 2019
  • 原文地址:https://www.cnblogs.com/sfqtsh/p/5134834.html
Copyright © 2011-2022 走看看