<>1.C/C++关键字

<>1.1 static(静态)变量

<>在C中,关键字static是静态变量:

* 静态变量只会初始化一次,然后在这函数被调用过程中值不变。
* 在文件内定义静态变量(函数外),作用域是当前文件,该变量可以被文件内所有函数访问,不能被其他文件函数访问。为本地的全局变量,只初始化一次。
<>在C++中,类内数据成员可以定义为static

* 对于非静态数据成员,每个对象有一个副本。而静态数据成员是类的成员,只存在一个副本,被所有对象共享。
* 静态成员变量没有实例化对象也可以使用,“类名:静态成员变量”
* 静态成员变量初始化在类外,但是private和protected修饰的静态成员不能类外访问。 class Stu { public: static
int age; private: static int height; }; //初始化静态成员变量 int Stu::age = 19; int Stu::
height= 180; int main() { cout<<Stu::age<<endl;//输出19; cout<<Stu::height<<endl;
//错误的,私有无法访问。 Stu s; cout<<s::age<<endl;//输出19; cout<<s::height<<endl;
//错误的,私有无法访问。 return 0; }
* 在类中,static修饰的函数是静态成员函数。静态成员函数一样属于类,不属于对象,被对象共享。静态成员函数没有this指针
,不能访问非静态的函数和变量,只能访问静态的。
<>与全局变量相比,静态数据成员的优势:

* 全局变量作用域是整个工程,而static作用域是当前文件,避免命名冲突
* 静态数据成员可以是private成员,而全局变量不能,实现信息隐藏
<>为什么静态成员变量不能在类内初始化?

因为类的声明可能会在多处引用,每次引用都会初始化一次,分配一次空间。这和静态变量只能初始化一次,只有一个副本冲突,因此静态成员变量只能类外初始化。

<>为什么static静态变量只能初始化一次?

所有变量都只初始化一次。但是静态变量在全局区(静态区),而自动变量在栈区。静态变量生命周期和程序一样,只创建初始化一次就一直存在,不会销毁。而自动变量生命周期和函数一样,函数调用就进行创建初始化,函数结束就销毁,所以每一次调用函数就初始化一次。

<>在头文件中定义静态变量是否可行?

不可行,在头文件中定义的一个static变量,对于包含该头文件的所有源文件,实质上在每个源文件内定义了一个同名的static变量。造成资源浪费,可能引起bug

<>1.2 const的作用

常量类型也称为const类型,使用const修饰变量或者对象

<>在C中,const的作用为:

* 定义变量(局部或者全局)为常量 const int a = 10; //常量定义时,必须初始化
* 修饰函数的参数,函数体内不能修改这个参数的值
* 修饰函数的返回值
* const修饰的返回值类型为指针,返回的指针不能被修改,而且只能符给被const修饰的指针const char* GetString() { //...
} int main() { char *str = GetString();//错误,str没被const修饰 const char *str =
GetString();//正确 }
* const修饰的返回值类型为引用,那么函数调用表达式不能做左值(函数不能被赋值)const int & add(int &a , int &b) {
//.. } int main() { add(a,b) = 4;//错误,const修饰add的返回引用,不能做左值 }
* const修饰的返回值类型为普通变量,由于返回是普通临时变量,const修饰没意义。
<>在c++中,const还有作用为:

* const修饰类内的数据成员。表示这个数据成员在某个对象的生命周期是常量,不同对象的值可以不一样,因此const成员函数不能在类内初始化。
* const修饰类内的成员函数。那么这个函数就不能修改对象的成员变量
<>const的优点?

*
进行类型检查,使编译器对处理内容有更多了解。

*
避免意义模糊的数字出现,类似宏定义,方便对参数进行修改。

*
保护被修饰的内容,防止被意外修改

*
为函数重载提供参考
class A { void f(int i){...} //非const对象调用 void f(int i) const {...}//const对象调用
}
5.节省内存
6.提高程序效率(编译器不为普通const常量分配存储空间,而保存在符号表中。称为一个编译期间的常量,没有存储和读内存的操作)

<>什么时候使用const?

*
修饰一般常量

*
修饰对象

*
修饰常指针
const int *p; int const *p; int *const p; const int *const p;
*
修饰常引用

*
修饰函数的参数

*
修饰函数返回值

*
修饰类的成员函数

*
修饰另一文件中引用的变量
extern const int j;
<>const和指针(常量指针、指针常量)

*
常量指针(const 修饰常量,const在*的左边)
const int *p = &a; // const修饰int,指针的指向可以修改,但是指针指向的值不能改 int const *p;//同上 p = &b
;//正确 *p = 10;//错误
*
指针常量(const修饰指针,const在*的右边)
int *const p = &a;//const修饰指针,指针的指向不可以改,但是指针指向的值可以改 *p = 10;//正确 p = &b;//错误
*
const都修饰指针和常量(指针和常量都不能修改)
const int *const p; int const *const p;
<>1.3 switch语句中case结尾是否必须加break

**一般必须在case结尾加break。**因为通过switch确认入口点,一直往下执行,直到遇见break。
否则会执行完这个case后执行后面的case,default也会执行。 注,switch(c),c可以是int、long、char等,但是不能是float

<>1.4 volatile 的作用

volatile 关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改,比如:操作系统、硬件或者其它线程等。

* 编译器不再进行优化,从而可以提供对特殊地址的稳定访问。
* 系统总是重新从它所在的内存读取数据,不会利用cache中原有的数值。
* 用于多线程被多个任务共享的变量,或者并行设备的硬件寄存器
<>1.5 断言ASSERT()是什么?

**是一个调试程序使用的宏。**定义在<assert.h>中,用于判断是否出现非法数据。括号内的值 为false(0),程序报错,终止运行。
ASSERT(n != 0);// n为0的时候程序报错 k = 10/n;
ASSERT()在Debug中有,在Release中被忽略。 ASSERT()是宏,assert()是ANSCI标准中的函数,但是影响程序性能。

<>1.6 枚举变量的值计算
#include<stdio.h> int main() { enum {a,b=5,c,d=4,e}; printf("%d %d %d %d %d",a,
b,c,d,e); return 0; }
输出为 0 5 6 4 5

<>1.7 字符串存储方式

* 字符串存储在栈中 char str1[] = "abc"; char str2[] = "abc";
* 字符串存储在常量区 char *str3 = "abc"; char *str4 = "abc";
* 字符串存储在堆中 char *str5 = (char*)malloc(4); strcpy(str5,"abc"); char *str6 = (
char*)malloc(4); strcpy(str6,"abc");
* 字符串是否相等
* str1 != str2 ,str1和str2是两个字符串的首地址。
* str3 == srt4 , str3和str4是常量的地址,同样字符串在常量区只存在一份。
* str5 != str6 ,str5 和str6是指向堆的地址。

<>1.8 程序内存分区

内存高地址栈区
堆区
全局/静态区 (.bss段 .date段)
常量区
内存低地址代码区
* 栈区(stack)
*
临时创建的局部变量存放在栈区。

*
函数调用时,其入口参数存放在栈区。

*
函数返回时,其返回值存放在栈区。

*
const定义的局部变量存放在栈区。

* 堆区(heap)
*
堆区用于存放程序运行中被动态分布的内存段,可增可减。

*
malloc函数分布的内存,必须用free进行内存释放,否则会造成内存泄漏。

* 全局区(静态区)
* 全局区有.bss段和.data段组成,可读可写。
* .bss段
*
未初始化的全局变量存放在.bss段。

*
初始化为0的全局变量和初始化为0的静态变量存放在.bss段。

*
.bss段不占用可执行文件空间,其内容有操作系统初始化。

* .data段
*
已经初始化的全局变量存放在.data段。

*
静态变量存放在.data段。

*
.data段占用可执行文件空间,其内容有程序初始化。

*
const定义的全局变量存放在.rodata段。

* 常量区
*
字符串存放在常量区。

*
常量区的内容不可以被修改。

* 代码区
* 程序执行代码存放在代码区。
<>1.9 *p++ 和 (*p)++ 的区别

* *p++ 先完成取地址,然后对指针地址进行++,再取值
* (*p)++,先完成取值,再对值进行++
<>1.10 new / delete 与 malloc / free的异同

*
相同点

* 都可用于内存的动态申请和释放
*
不同点

*
new / delete 是C++运算符,malloc / free是C/C++语言标准库函数

*
new自动计算要分配的空间大小,malloc需要手工计算

*
new是类型安全的,malloc不是。例如:
int *p = new float[2]; //编译错误 int *p = (int*)malloc(2 * sizeof(double));//编译无错误
*
new调用名为operator new的标准库函数分配足够空间并调用相关对象的构造函数,delete对指针所指对象运行适当的析构函数
;然后通过调用名为operator delete的标准库函数释放该对象所用内存。malloc / free均没有相关调用

*
malloc / free需要库文件支持,new / delete不用

*
new是封装了malloc,直接free不会报错,但是这只是释放内存,而不会析构对象

<>1.11 exit()和return 的区别

* return是语言级的,标志调用堆栈的返回。是从当前函数的返回,main()中return的退出程序
* exit()是函数,强行退出程序,并返回值给系统
* return实现函数逻辑,函数的输出。exit()只用来退出。

技术
下载桌面版
GitHub
Gitee
SourceForge
百度网盘(提取码:draw)
云服务器优惠
华为云优惠券
腾讯云优惠券
阿里云优惠券
Vultr优惠券
站点信息
问题反馈
邮箱:[email protected]
吐槽一下
QQ群:766591547
关注微信