1.栈存储与堆存储的区别
C++程序编译占用的内存可以分为以下几个部分:
栈区:由编译器自动分配释放,存放函数的参数值、局部变量等,用于存放占用空间小、生命周期短的数据;
堆区:由用户分配释放,用于存储占用空间大、生命周期长的数据,如静态变量和全局变量。手动分配空间后一定要释放空间,否则会导致内存泄漏;
全局区:全局变量和静态变量是存储于在一起的,初始化的存储一块区域,未初始化的存储相邻区域;
文字常量区:常量字符串存放于此区,程序结束后由系统释放;
程序代码区:存放函数体的二进制代码;
堆与栈的区别可以分为三个方面:
- 堆栈在空间上的区别见上面;
- 堆栈在缓存方式上的区别:栈使用的是一级缓存,通常都是被调用时处于存储空间,调用完成立即释放;堆是存放在二级缓存中的,生命周期由虚拟机的垃圾回收算法来决定,故调用这些对象的速度相对较慢;
- 堆栈在数据结构上的区别:堆数据结构可以看成是一棵树,如堆排序;栈数据结构是一种先进后出的数据结构;
逗号表达式:它的运算优先级最低,逗号表达式取最右边表达式的值。
const与define的比较:
C++语言可以使用这两者来定义常量,但是使用const更好,理由如下:
- const常量有数据类型,而宏常量没有数据类型,编译器可以对前者进行安全检查,而对后者只能进行字符替换,字符替换可能会发生意想不到的错误;
- 有些集成化调试工具可以对const常量进行调试,但不能对宏常量调试,此时只能使用const定义常量。更精确地说,const在程序运行时只有一份复制品,而define有多份复制品。
2.类中的常量问题
在类中定义常量,我们很自然地想到使用const,但是const数据成员只对某个对象生存周期内是常量,而对整个类而言是可变的,因为创建多个对象时,不同对象其const数据成员的值可以不同。不能在类声明中初始化const成员,其初始化只能在类的构造函数初始化列表中进行。因为类未被创建时,编译器不知道相应的常量是什么。
应该使用枚举常量来在类中建立一个恒定的常量,枚举常量不会占用对象的存储空间,在编译时全部求值。
3.C++相关语句
C++语句一般由表达式和分号构成的,只有空分号的语句为空语句,程序中允许有多条空语句,空语句不执行任何功能。{}是复合语句,也可用复合语句来代替空语句,但是括号后面没有分号。
多条if语句,程序会依次执行各条语句,从而条件判断较为复杂。对于if/else语句,程序只选择一个分支按条件执行。
return语句用来退出当前函数的执行,若函数没有返回值,则只使用return语句,后不加任何表达式。在使用return语句时,要注意如果代码之前在堆中分配了内存,则在return语句前要释放内存,以防止内存泄漏。
exit语句用于终止当前进程,通常用于结束当前的应用程序。exit包含一个整型参数,用于标识退出的代码,与return不同的是,return语句只退出当前调用的函数,除非当前函数是主函数,return会结束当前进程,而exit会直接结束当前进程,无论当前函数是否是应用程序的主函数。
4.C++函数相关
- 在定义函数时,若函数返回类型不是void类型,一定要在函数中加入return语句;
- 若调用函数处于被调用函数下方,则要对被调用函数进行前置声明,声明也可放置于main函数内部。
- 若函数有多个参数,应保证默认参数出现在参数列表的最右方。
- 在定义数组参数、函数参数时,也可不指定数组的大小,在调用C++编译器时不对数组长度进行检查,只是将数组首地址传给函数,但是使用数组的引用会强制检查参数中元素的个数,这可以更好地确定程序的安全。
值传递:在函数调用时,将实际参数的值复制一份传递到调用函数中,实际参数值不受影响;
引用传递:即传址调用,按引用传递时,调用函数修改了参数值,实际参数值也会发生改变。
因此,通常在定义函数时,如果参数为数组、指针或引用类型,则用引用类型传递方式,否则用值传递方式。
内联函数:
内联函数是指对于程序中出现函数调用的地方,如果是内联函数,编译器直接将函数代码复制到函数调用的地方,省去了程序跳转的过程,用inline关键字标识内联函数。内联函数的目的是提高程序的执行效率。
对于使用inline关键字的内联函数,程序不一定将函数作为内联函数对待,这关键取决于编译器的优先机制。通常对于代码较少、频繁调用的函数,可以标识为内联函数,否则不使用内联函数。
函数的重载:
重载是多个函数具有相同的函数名称,而参数类型或参数个数不同,在调用时编译器正是通过参数类型和参数个数来区分调用哪个函数。
返回值不作为区分重载的一部分;对于参数来说,const关键字不作为区分,但若参数是指针或引用类型,const作为区分标志;参数默认值不作为区分标志;
注意:在局部域中定义声明函数,将使同名函数隐藏而不是重载,要访问其他域函数,用::域访问符。
函数指针:
在C++语言中,函数名实际上是指向函数的指针,定义有如下几种形式:
对于函数指针来说,它指向的函数必须与函数指针定义的形式相同,即返回类型、参数、参数个数均相同。在程序中使用函数指针可以极大的丰富程序的灵活性。
5.局部作用域和全局作用域
局部作用域描述的是函数体中变量、常量等对象的作用范围,对于处于同一个作用域的对象来说,对象不允许重名。当编译器在当前代码处发现变量名时,它将在当前局部作用域中搜索变量的定义,如果未定义则向外搜索,直到局部作用域完成;
全局作用域是函数、变量、常量对象作用范围是整个应用程序。对于全局变量,若未初始化,其存储区为0,对于局部变量,若未初始化,则其值是不可预见的。
6.定义和使用命名空间
在一个应用程序中的多个文件可能存在同名的全局对象,这样会导致应用程序的链接错误,使用命名空间是消除命名冲突的最佳方式。命名空间的定义格式如下:
若要使用命名空间中的对象,则要在对象前加上命名空间的名字,若要访问命名空间的多个对象,可以使用using命令,using的作用域是从当前引用处到当前作用域结束。
对于同一个命名空间,可以在多个文件中定义,此时命名空间中的内容是各个文件中内容之和。命名空间也可嵌套,访问内层函数时,可以用using namespace 外层名称::内层名称。
using命令用于引用命名空间中的全部空间对象,容易和正在编写的程序中的局部变量发生冲突,导致命名空间的变量被隐藏,故不建议过多使用此命令。不命名的空间中的对象只适用于当前文件,各文件中不能相互访问,在一个文件中访问空间中的对象与访问普通全局对象是相同的。
7.函数模板
函数模板提供了一种机制,使函数返回值、参数类型能够被参数化,而函数体保持不变,这极大的增强了函数的灵活性。定义格式如下:
函数模板也可以重载,要注意区分。
=========================================
本文到此结束!
如果对你有帮助,请随手 点赞 或 赞赏
欢迎关注、私信、交流,一起学习,一起进步!
==========================================