所在的位置: C++ >> C++前景 >> CC重点八股文

CC重点八股文

北京治疗白癜风手术哪家便宜 https://wapjbk.39.net/yiyuanzaixian/bjzkbdfyy/

1.C/C++关键字

1.1static(静态)变量

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

静态变量只会初始化一次,然后在这函数被调用过程中值不变。

在文件内定义静态变量(函数外),作用域是当前文件,该变量可以被文件内所有函数访问,不能被其他文件函数访问。为本地的全局变量,只初始化一次。

在C++中,类内数据成员可以定义为static

对于非静态数据成员,每个对象有一个副本。而静态数据成员是类的成员,只存在一个副本,被所有对象共享。

静态成员变量没有实例化对象也可以使用,“类名:静态成员变量”

静态成员变量初始化在类外,但是private和protected修饰的静态成员不能类外访问。

classStu

{

public:

staticintage;

private:

staticintheight;

};

//初始化静态成员变量

intStu::age=19;

intStu::height=;

intmain()

{

coutStu::ageendl;//输出19;

coutStu::heightendl;//错误的,私有无法访问。

Stus;

couts::ageendl;//输出19;

couts::heightendl;//错误的,私有无法访问。

return0;

}

在类中,static修饰的函数是静态成员函数。静态成员函数一样属于类,不属于对象,被对象共享。静态成员函数没有this指针,不能访问非静态的函数和变量,只能访问静态的。

与全局变量相比,静态数据成员的优势:

全局变量作用域是整个工程,而static作用域是当前文件,避免命名冲突

静态数据成员可以是private成员,而全局变量不能,实现信息隐藏

为什么静态成员变量不能在类内初始化?

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

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

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

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

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

1.2const的作用

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

在C中,const的作用为:

定义变量(局部或者全局)为常量

constinta=10;//常量定义时,必须初始化

1

修饰函数的参数,函数体内不能修改这个参数的值

修饰函数的返回值

const修饰的返回值类型为指针,返回的指针不能被修改,而且只能符给被const修饰的指针

constchar*GetString()

{

//...

}

intmain()

{

char*str=GetString();//错误,str没被const修饰

constchar*str=GetString();//正确

}

const修饰的返回值类型为引用,那么函数调用表达式不能做左值(函数不能被赋值)

constintadd(inta,intb)

{

//..

}

intmain()

{

add(a,b)=4;//错误,const修饰add的返回引用,不能做左值

}

const修饰的返回值类型为普通变量,由于返回是普通临时变量,const修饰没意义。

在c++中,const还有作用为:

const修饰类内的数据成员。表示这个数据成员在某个对象的生命周期是常量,不同对象的值可以不一样,因此const成员函数不能在类内初始化。

const修饰类内的成员函数。那么这个函数就不能修改对象的成员变量

const的优点?

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

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

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

为函数重载提供参考

classA

{

voidf(inti){...}//非const对象调用

voidf(inti)const{...}//const对象调用

}

5.节省内存

6.提高程序效率(编译器不为普通const常量分配存储空间,而保存在符号表中。称为一个编译期间的常量,没有存储和读内存的操作)

什么时候使用const?

修饰一般常量

修饰对象

修饰常指针

constint*p;

intconst*p;

int*constp;

constint*constp;

修饰常引用

修饰函数的参数

修饰函数返回值

修饰类的成员函数

修饰另一文件中引用的变量

externconstintj;

const和指针(常量指针、指针常量)

常量指针(const修饰常量,const在*的左边)

constint*p=a;//const修饰int,指针的指向可以修改,但是指针指向的值不能改

intconst*p;//同上

p=b;//正确

*p=10;//错误

指针常量(const修饰指针,const在*的右边)

int*constp=a;//const修饰指针,指针的指向不可以改,但是指针指向的值可以改

*p=10;//正确

p=b;//错误

const都修饰指针和常量(指针和常量都不能修改)

constint*constp;

intconst*constp;

1.3switch语句中case结尾是否必须加break

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

1.4volatile的作用

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枚举变量的值计算

#includestdio.h

intmain()

{

enum{a,b=5,c,d=4,e};

printf("%d%d%d%d%d",a,b,c,d,e);

return0;

}

输出为

1.7字符串存储方式

字符串存储在栈中

charstr1[]="abc";

charstr2[]="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进行内存释放,否则会造成内存泄漏。

全局区(静态区)

(c语言中)全局区有.bss段和.data段组成,可读可写。

C++不分bss和data

.bss段

未初始化的全局变量存放在.bss段。

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

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

.data段

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

静态变量存放在.data段。

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

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

常量区

字符串存放在常量区。

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

代码区

程序执行代码(二进制代码文件)存放在代码区。

1.9*p++和(*p)++的区别

*p++先完成取地址,然后对指针地址进行++,再取值

(*p)++,先完成取值,再对值进行++

1.10new/delete与malloc/free的异同

相同点

都可用于内存的动态申请和释放

不同点

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

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

new是类型安全的,malloc不是。例如:

int*p=newfloat[2];//编译错误

int*p=(int*)malloc(2*sizeof(double));//编译无错误

new调用名为operatornew的标准库函数分配足够空间并调用相关对象的构造函数,delete对指针所指对象运行适当的析构函数;然后通过调用名为operatordelete的标准库函数释放该对象所用内存。malloc/free均没有相关调用

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

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

1.11exit()和return的区别

return是语言级的,标志调用堆栈的返回。是从当前函数的返回,main()中return的退出程序

exit()是函数,强行退出程序,并返回值给系统

return实现函数逻辑,函数的输出。exit()只用来退出。

1.12extern和export的作用

变量的声明有两种情况:

一种是需要建立存储空间的。例如:inta在定义的时候就已经建立了存储空间。

另一种是不需要建立存储空间的。例如:externinta其中变量a是在别的文件中定义的。

总之就是:把建立空间的声明成为“定义”,把不需要建立存储空间的成为“声明”。

extern

普通变量、类。结构体

export(C++中新增)

和exturn类似,但是用作模板

使用该关键字可实现模板函数的外部调用

模板实现的时候前面加上export,别的文件包含头文件就可用该模板

1.13C++中,explicit的作用

隐式转换

Strings1="hello";

//进行隐式转换,等价于

Strings1=String("hello");

1

2

3

explicit阻止隐式转换

classTest1

{

public:

Test1(intn){num=n}

private:

intnum;

}

classTest2

{

public:

explicitTest2(intn){num=n}

private:

intnum;

}

intmain()

{

Test1t1=1;//正确,隐式转换

Test2t2=1;//错误,禁止隐式转换

Test2t2(1);//正确,可与显示调用

}

1.14C++的异常处理

C++中的异常处理机制主要使用try、throw和catch三个关键字

#includeiostream

usingnamespacestd;

intmain()

{

doublem=1,n=0;

try{

cout"beforedividing."endl;

if(n==0)

throw-1;//抛出int型异常

elseif(m==0)

throw-1.0;//拋出double型异常

else

coutm/nendl;

cout"afterdividing."endl;

}

catch(doubled){

cout"catch(double)"dendl;

}

catch(...){

cout"catch(...)"endl;

}

cout"finished"endl;

return0;

}

//运行结果

//beforedividing.

//catch(...)

//finished

代码中,对两个数进行除法计算,其中除数为0。可以看到以上三个关键字,

程序的执行流程是先执行try包裹的语句块,如果执行过程中没有异常发生,则不会进入任何catch包裹的语句块,如果发生异常,则使用throw进行异常抛出,再由catch进行捕获,

throw可以抛出各种数据类型的信息,代码中使用的是数字,也可以自定义异常class。catch根据throw抛出的数据类型进行精确捕获(不会出现类型转换),如果匹配不到就直接报错,可以使用catch(…)的方式捕获任何异常(不推荐)。

当然,如果catch了异常,当前函数如果不进行处理,或者已经处理了想通知上一层的调用者,可以在catch里面再throw异常。

1.15回调函数

把一段可执行的代码像参数传递那样传给其他代码,而这段代码会在某个时刻被调用执行,这就叫做回调。

如果代码立即被执行就称为同步回调,如果过后再执行,则称之为异步回调。

回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。

主函数和回调函数是在同一层的,而库函数在另外一层。如果库函数对我们不可见,我们修改不了库函数的实现,也就是说不能通过修改库函数让库函数调用普通函数那样实现,那我们就只能通过传入不同的回调函数

sort(),中自定义的cmp就是回调函数

————————————————

版权声明:本文为CSDN博主「songwei」的原创文章,遵循CC4.0BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:


转载请注明:http://www.aierlanlan.com/cyrz/4211.html

  • 上一篇文章:
  •   
  • 下一篇文章: 没有了