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; // 错误!对于操作符,一定要加()
  • 相关阅读:
    justep w模型检查正常,编译出错
    php get post 发送与接收
    编译原理正则文本与有限状态机
    编译原理前端技术
    lucene早期版本基本概念
    golang panic和defer
    2021年1月阅读文章
    elasticsearch 中的fielddata 和 doc_values
    golang中的树
    elasticsearch中的wildcard
  • 原文地址:https://www.cnblogs.com/sfqtsh/p/5134834.html
Copyright © 2011-2022 走看看