美文网首页
CPP_Basic_Summary_0.7

CPP_Basic_Summary_0.7

作者: 贴墙上的咖啡 | 来源:发表于2017-04-12 22:21 被阅读0次

    CPP_Basic_Summary_0.7

    1、C++要求函数的返回值不能是数组,但可以将数组作为结构或对象组成部分来返回
    2、C++的编程风格因为函数原型必须存在,所以提倡main()置于最前面
    3、函数原型不要求必须提供变量名,只需要类型列表就可以:

    void test(double ar[],int);
    void test(double [],int);
    void test(double*,int);//三者同义
    

    4、通常如果可能且仅当有意义时,原型自动将被传递的参数强制转换为期望的类型
    5、在编译阶段进行的原型化被称为静态类型检查,这种检查可以捕获很多运行阶段难以捕获的错误
    6、函数的内部变量(包括参数)是局部变量,函数结束将释放这些内存,按值传递时函数形参传递的是副本
    7、在进行诸如阶乘这类大规模计算的时候,采用交替进行乘除运算的方式,可以有效防止中间结果超最大值而溢出
    8、数组名在大部分时候等同于指向第一个元素的指针,但有以下情形除外:首先是数组声明用数组名来标记存储位置;其次,对数组名使用sizeof将得到整个数组的长度(字节为单位);然后是将地址运算符&用于数组名时,将返回整个数组的地址
    9、将指针(包括数组名)+1,实际上是加上了一个与指针指向类型的长度(字节为单位)相等的值
    10、函数调用数组必须通过数组名,也就是指针传递的方式,可以用数组名和数组容量搭配的方式:

    void demo(double arr[],int size);
    

    也能使用两个指针来指出数组的开头位置和结尾位置:

    int sum_arr(cookies,cookies+size);
    

    11、const double ar[]:保护指针指向的内容不被修改;但只意味着对于ar来说不可以更改,别的指针或许可以,且指针ar本身也可以被修改
    12、int* const pt=&age:意味着指针本身不可被修改。简而言之:前置const锁数据,后置const锁指针,同时则都锁。需要非常注意的是,如果数组元素不是基本类型,而是指针或者指向指针的指针,则不能使用const(比如2D数组)
    13、C++禁止将const的地址赋给非const指针,若数据类型本身不是指针,则可以将const数据或非const数据的地址赋给指向const的指针,但是只能将非const数据的地址赋给非const指针
    14、2D数组的函数定义:int sum(int ar2[] [4],int size);可见是单独传递行数的。ar2[r][c]==*(*(ar2+r)+c)两者完全等价
    15、const char* str="name";即可声明指向字符串的指针str,此处const对于C++11标准是必须的
    16、处理字符串中字符的标准方式:

    while (*str)
    {
        statements;
        str++;
    }
    

    此循环每次增加使得str指向下一个字符,直到最后的'\0'将使*str==0(空值字符的数字编码),从而中断循环
    17、从后向前的循环一般可以节省额外的变量i,比如:

    while (n-- >0)
    {
        pstr[n]=c;
    }
    

    18、子函数结束时,所有局部变量都会被释放,即返回的指针的内存会被释放,但是其值会被返回到main()中,故仍可以通过main()中的指针对新建的字符串相关内容进行访问
    19、函数中使用结构可以使用实值直接传递和结构指针两种方式,但是出于效率考虑,应该优先使用指针。除此以外,还有引用的方式可以解决 表示和效率 两方面的问题
    20、函数中使用string对象数组:

    string list[size];
    getline(cin,list[i]);
    

    21、函数中使用array对象,除了基本数据类型,array还可以存储类对象:

    array<double,4> expenses;
    const array<string,4> sname {"Spring","Summer","Fall","Winter"};
    void show(array<double,4> da);
    void fill(array<double,4> *pa);
    show(expenses);
    fill(&expenses);
    

    22、递归(也称 分而治之):C++允许递归调用除了main()以外的子函数:

    void recurs(argumentlist)
    {
        statements1;
        if (test)//test最终为false将跳出循环
            recurs(arguments);//此处的递归调用应该更新test条件
        statements2;
    }//若statements1将按照调用顺序执行n次,则statements2将按照与函数调用相反的顺序执行n次
    

    23、每一套递归调用都创建自己的一套变量,因此若程序达到第5次调用的时候,将有5个独立的变量:

    void countdown(int n)
    {
        if (n>0)
            countdown(n-1);
    }
    

    24、函数的地址是存储其机器语言代码的内存的开始地址。函数指针允许在不同的时间传递不同函数的地址,这意味着可以在不同的时间使用不同的函数。函数的地址就是函数名,需要注意的是区分函数本身和函数的返回值:

    process(think);//传递的是函数的地址
    thought(think());//传递的是函数的返回值
    

    25、声明一个函数指针,通常可以先写出函数的原型,然后用诸如(*pf)这样的函数指针替换函数名即可:

    double (*pf)(int);//pf是指向函数的指针,该函数返回值类型为double,形参为int
    double* pf(int);//pf是一个函数,接受int形参,且返回值的类型为double*指针
    

    26、需要注意C++特别规定,若pf是一个函数指针,则:
    double y=(*pf)(5)double y=pf(5)是完全等价的,也即此处(*pf)==pf。为强调是函数指针,建议使用前者
    27、类似地,以下代码含义完全一致:

    cout<<(*p1)(av,3)<<*(*p1)(av,3)<<endl;
    //第一部分是函数调用,返回double*指针,第二部分再次解除*,获得具体的double实值
    cout<<p2(av,3)<<*p2(av,3)<<endl;
    //同理,第一部分函数调用,返回double*指针,第二部分是具体的double实值
    

    28、创建指向整个函数指针数组的指针:

    const double* (*(*pd)[3]) (const double*,int)=&pa
    //*pd表明pd是指针,右侧[3]说明指针指向一个数组
    //*(*pd)最左侧的*表明数组的元素是指针
    //观察左右两侧发现数组的元素是函数指针
    //左侧const double*是返回值类型,右侧 (const double*,int)是形参
    

    29、typedef用法:
    例1:

    typedef const double* (*p_fun) (const double*,int);
    p_fun p1=f1;
    p_fun pa[3] {f1,f2,f3};
    p_fun (*pd) [3]=&pa;
    

    例2:

    void (*p1)(形参)=f1;
    const char* (*p2)(形参)=f2;
    void (*ap[5])(形参);
    const char* (*(*pa)[10])(形参);
    //可简化为:
    typedef void (*p_f1)(形参);
    p_f1 p1=f1;
    typedef const char* (*p_f2)(形参);
    p_f2 p2=f2;
    p_f1 ap[5];
    p_f2 (*pa)[10];
    

    30、指针数组 数组指针 指针函数 函数指针

    int *p[4];        //指针数组
      //它是个有4个元素的数组, 每个元素的是指向整型的指针。(数组的每个元素都是指针)
    int (*p)[4];      //数组指针。 
      //它是一个指针,指向有4个整型元素的数组。(一个指针指向有4个整型元素的数组)
    int *func(void);  //指针函数。
      //无参函数, 返回整型指针。(函数的返回值为int*)
    int (*func)(void);//函数指针
      //可以指向无参, 且返回值为整型指针的函数。(函数的返回值为int)
    

    31、复杂函数指针阅读说明:
      右左法则其实并不是C++标准里面的内容,它是从C++标准的声明规定中归纳出来的方法。C++标准的声明规则,是用来解决如何创建声明的,而右左法则是用来解决如何辩识一个声明的,两者可以说是相反的。
      右左法则:首先从最里面的圆括号(未定义的标识符)看起,然后往右看,再往左看。每当遇到圆括号时,就应该掉转阅读方向。一旦解析完圆括号里面所有的东西,就跳出圆括号。重复这个过程直到整个声明解析完毕。
      对这个法则应该进行一个小小的修正,应该从未定义的标识符开始阅读,而不是从括号读起,之所以是未定义的标识符,是因为一个声明里面可能有多个标识符,但未定义的标识符只会有一个。
      现在通过一些例子来讨论右左法则:

    int (*func)(int *p);
    

    首先找到那个未定义的标识符,就是func,它的外面有一对圆括号,而且左边是一个号,这说明func是一个指针,
    然后跳出这个圆括号,先看右边,也是一个圆括号,这说明(
    func)是一个函数,而func是一个指向这类函数的指针,就是一个函数指针,这类函数具有int*类型的形参,返回值类型是 int。

    int (*func)(int *p, int (*f)(int*));
    

    func被一对括号包含,且左边有一个号,说明func是一个指针,跳出括号,右边也有个括号,那么func是一个指向函数的指针,这类函数具有int 和int ()(int)这样的形参,返回值为int类型。再来看一看func的形参int (f)(int),类似前面的解释,f也是一个函数指针,指向的函数具有int*类型的形参,返回值为int。

    int (*func[5])(int *p);
    

    func右边是一个[]运算符,说明func是一个具有5个元素的数组,func的左边有一个,说明func的元素是指针,要注意这里的不是修饰 func的,而是修饰func[5]的,原因是[]运算符优先级比高,func先跟[]结合,因此修饰的是func[5]。跳出这个括号,看右边,也是一对圆括号,说明func数组的元素是函数类型的指针,它所指向的函数具有int*类型的形参,返回值类型为int。

    int (*(*func)[5])(int *p);
    

    func被一个圆括号包含,左边又有一个,那么func是一个指针,跳出括号,右边是一个[]运算符号,说明func是一个指向数组的指针,现在往左看,左边有一个号,说明这个数组的元素是指针,再跳出括号,右边又有一个括号,说明这个数组的元素是指向函数的指针。总结一下,就是:func是一个指向数组的指针,这个数组的元素是函数指针,这些指针指向具有int*形参,返回值为int类型的函数。

    int (*(*func)(int *p))[5];
    

    func是一个函数指针,这类函数具有int*类型的形参,返回值是指向数组的指针,所指向的数组的元素是具有5个int元素的数组。
    32、要注意有些复杂指针声明是非法的,例如:

    int func(void) [5];
    

    func是一个返回值为具有5个int元素的数组的函数。但C语言的函数返回值不能为数组,这是因为如果允许函数返回值为数组,
    那么接收这个数组的内容的东西,也必须是一个数组,但C语言
    的数组名是一个右值,它不能作为左值来接收另一个数组,因此函数返回值不能为数组。

    int func[5](void);
    

    func是一个具有5个元素的数组,这个数组的元素都是函数。这也是非法的,因为数组的元素除了类型必须一样外,每个元素所占用的内存空间也必须相同,显然函数是无法达到这个要求的,即使函数的类型一样,但函数所占用的空间通常是不相同的。实际当中,需要声明一个复杂指针时,如果把整个声明写成上面所示的形式,对程序可读性是一大损害。应该用typedef来对声明逐层分解,增强可读性。
    33、用typedef的分解方法:

    int (*(*func)[5][6])[7][8];
    

    func是一个指向数组的指针,这类数组的元素是一个具有5X6个int元素的二维数组,而这个二维数组的元素又是一个二维数组。

    typedef int (*PARA)[7][8];
    typedef PARA (*func)[5][6];
    int (*(*(*func)(int *))[5])(int *);
    

    func是一个函数指针,这类函数的返回值是一个指向数组的指针,所指向数组的元素也是函数指针,指向的函数具有int*形参,返回值为int。

    typedef int (*PARA1)(int*);
    typedef PARA1 (*PARA2)[5];
    typedef PARA2 (*func)(int*);
    int (*(*func[7][8][9])(int*))[5];
    

    func是一个数组,这个数组的元素是函数指针,这类函数具有int*的形参,返回值是指向数组的指针,所指向的数组的元素是具有5个int元素的数组。

    typedef int (*PARA1)[5];
    typedef PARA1 (*PARA2)(int*);
    typedef PARA2 func[7][8][9];
    

    相关文章

      网友评论

          本文标题:CPP_Basic_Summary_0.7

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