【C++语言基础】总结篇

您所在的位置:网站首页 葡萄酒酿造工艺专业 【C++语言基础】总结篇

【C++语言基础】总结篇

2023-10-16 19:44| 来源: 网络整理| 查看: 265

点我–>C++内存 点我–>面向对象 点我–>STL 点我–>新特性

【操作系统】常见问题汇总及解答 【数据库】常见问题汇总及解答 【计算机网络】常见问题汇总及解答 【设计模式】总结篇

本文目录 1. 简述C++语言的特点2. 说说C语言和C++的区别3. 说说C++中 struct 和 class 的区别4. 说说include头文件的顺序以及双引号""和尖括号的区别5. C语言结构体和C++结构体的区别6. 说说导入C函数的关键字是什么,C++编译时和C语言有什么不同7. 简述C++从代码到可执行二进制文件的过程8. 说说 static 关键字的作用9. 说说数组和指针的区别10. 说说什么是函数指针,如何定义函数指针,有什么使用场景11. 说说静态变量什么时候初始化12. 说说 nullptr 可以调用成员函数吗,为什么13. 说说什么是野指针,怎么产生的,如何避免14. 说说静态局部变量,全局变量,局部变量的特点,以及使用场景15. 说说内联函数和宏函数的区别16. 说说运算符i++和++i的区别17. 说说 new 和 malloc 的区别,各自底层实现原理18. 说说 const 和 define 的区别19. 说说C++中函数指针和指针函数的区别20. 说说const int *a, int const *a, const int a, int *const a, const int *const a分别是什么,有什么特点21. 说说使用指针需要注意什么22. 说说内联函数和函数的区别,内联函数的作用23. 简述C++有几种传值方式,之间的区别是什么24. 简述指针常量与常量指针的区别25. 变量的声明和定义有什么区别26. 写出int 、bool、 float 、指针变量与 “零值”比较的 if 语句

1. 简述C++语言的特点 C++支持面向对象编程,它提供类、对象、继承、封装、多态等OOP的特性,使得程序设计更加模块化、可维护、可扩展;C++继承了C语言的基本语法和特性,因此可以兼容C语言的代码;C++语言编写出的程序结构清晰、易于扩充,程序可读性好;C++生成的代码质量高,运行效率高,仅比汇编语言慢10%~20%,因为C++是一种编译型语言,程序在编译后就会被转换为机器码;C++更加安全,增加了 const 常量、引用、四类 cast 转换(static_cast、dynamic_cast、const_cast、reinterpret_cast)、智能指针、try - catch等;C++可复用性高,C++引入了模板的概念,后面在此基础上,实现了方便开发的标准模板库 STL(Standard Template Library);同时,C++是不断发展的语言。C++后续版本更是发展了不少新特性,如C++11中引入了 nullptr、auto 变量、Lambda匿名函数、右值引用、智能指针。 2. 说说C语言和C++的区别 C++是面向对象的编程语言,C语言是面向过程的编程语言;C语言是C++的子集,C++可以很好地兼容C语言;但是C++又有很多新特性,如引用、智能指针、auto变量等;C++支持函数重载,C语言不支持;C语言有一些不安全的语言特性,如指针使用的潜在危险、强制转换的不确定性、内存泄露等;而C++对此增加了不少新特性来改善安全性,如const常量、引用、cast 转换、智能指针、try - catch 等;C++可复用性高,C++引入了模板的概念,后面在此基础上,实现了方便开发的标准模板库STL,C++的STL库相对于C语言的函数库更灵活、更通用。 3. 说说C++中 struct 和 class 的区别 访问控制:在struct中,成员默认是公共的(public),而在class中,默认是私有的(private)。也就是说,在class中,必须显式指定访问级别才能访问该成员。例如: struct S { int x; // 默认:公共成员 }; class C { int x; // 默认:私有成员 public: void setX(int value) { x = value; } // 需要显式设置public访问级别 int getX() { return x; } }; 继承方式:在class中,默认继承方式是私有继承(private),而在struct中,是公共继承(public)。例如: struct Base { void foo() { std::cout }; // 私有继承 int main() { Derived1 d1; d1.foo(); // OK,公共继承 Derived2 d2; d2.foo(); // 错误,私有继承 }

可以看到,Derived1从Base中继承的成员函数foo()可以在Derived1中直接使用,而Derived2则不能。

class 关键字可以用于定义模板参数,就像 typename,而 struct 不能用于定义模板参数。 4. 说说include头文件的顺序以及双引号""和尖括号的区别 区别: 尖括号的头文件是系统文件,双引号""的头文件是自定义文件。编译器预处理阶段查找头文件的路径不一样。 查找路径: 使用尖括号的头文件的查找路径:编译器设置的头文件路径–>系统变量。使用双引号""的头文件的查找路径:当前头文件目录–>编译器设置的头文件路径–>系统变量。 5. C语言结构体和C++结构体的区别 C语言的结构体内不允许有函数存在,C++允许有内部成员函数,且允许该函数是虚函数。C语言的结构体对内部成员变量的访问权限只能是 public,而C++允许 public、protected、private三种。C语言的结构体是不可以继承的,C++的结构体是可以从其他的结构体或者类继承过来的。C语言中使用结构体需要加上 struct 关键字,或者对结构体使用 typedef 取别名,而C++中可以省略 struct 关键字直接使用。例如: struct Student { int age; string name; }; struct Student stu1; // C语言中正常使用 typedef struct Student Student2; // C语言中取别名 Student2 stu2; // C语言中通过取别名的使用 Student stu3; // C++中使用 对比项C语言结构体C++结构体成员函数不能有可以静态成员不能有可以访问控制默认public,不能修改public/private/protected继承关系不能继承可从类或者其他结构体继承初始化不能直接初始化数据成员可以 6. 说说导入C函数的关键字是什么,C++编译时和C语言有什么不同 关键字:在C++中,导入C函数的关键字是 extern,表达形式为 extern “C”, extern “C” 的主要作用就是为了能够正确实现C++代码调用其他C语言代码。加上extern "C"后,会指示编译器这部分代码按C语言的进行编译,而不是C++的。编译区别:由于C++支持函数重载,因此编译器编译函数的过程中会将函数的参数类型也加到编译后的代码中,而不仅仅是函数名;而C语言并不支持函数重载,因此编译C语言代码的函数时不会带上函数的参数类型,一般只包括函数名。 // extern示例:在C++程序里边声明该函数,会指示编译器这部分代码按C语言的进行编译 extern "C" int strcmp(const char* s1, const char* s2); // 在C++程序里边声明该函数 extern "C" { #include //string.h里边包含了要调用的C函数的声明 } //两种不同的语言,有着不同的编译规则,比如一个函数fun,可能C语言编译的时候为_fun,而C++则是__fun__ 7. 简述C++从代码到可执行二进制文件的过程

C++和C语言类似,一个C++程序从源码到执行文件,有四个过程:预编译、编译、汇编、链接。

预编译(Preprocessing):这个过程使用预处理器对源代码进行预处理,主要包括去注释、宏定义替换、头文件包含等操作。预处理后生成一个仅含预处理后的源代码的文件,通常以.i为后缀名。具体如下:

将所有的#define删除,并且展开所有的宏定义;处理所有的条件预编译指令,如#if、#ifdef;处理#include预编译指令,将被包含的文件插入到该预编译指令的位置;过滤所有的注释;添加行号和文件名标识。

编译(Compilation):这个过程将预处理后的源代码文件编译成汇编语言文件,即把C++源代码翻译成机器语言指令的过程。编译过程中会进行词法分析、语法分析、语义分析以及优化等一系列步骤,生成汇编代码文件,通常以.s为后缀名。具体如下:

词法分析:将源代码的字符序列分割成一系列的记号;语法分析:对记号进行语法分析,产生语法树;语义分析:判断表达式是否有意义;代码优化;目标代码生成:生成汇编代码;目标代码优化。

汇编(Assembly):这个过程主要是将编译后的汇编代码文件转换成机器码文件,即将汇编代码翻译成CPU能够执行的指令序列的过程。汇编器将汇编代码转换为目标文件,通常以.o为后缀名。

链接(Linking):将所有目标文件以及库文件链接起来形成一个完整的二进制可执行文件。链接器将目标文件、库文件以及一些链接信息组合成可执行文件,通常以.exe为后缀名。链接器完成的任务包括符号解析、重定位等。链接分为静态链接和动态链接:

静态链接:是在链接的时候就已经把要调用的函数或者过程链接到了生成的可执行文件中,就算你再去把静态库删除也不会影响可执行程序的执行;生成的静态链接库,Windows下以 .lib 为后缀,Linux下以 .a 为后缀。动态链接:是在链接的时候没有把调用的函数代码链接进去,而是在执行的过程中,再去找要链接的函数,生成的可执行文件中没有函数代码,只包含函数的重定位信息,所以当你删除动态库时,可执行程序就不能运行。生成的动态链接库,Windows下以 .dll 为后缀,Linux下以 .so 为后缀。 8. 说说 static 关键字的作用 定义全局静态变量和局部静态变量:在变量前面加上 static 关键字。初始化的静态变量会在数据段分配内存,未初始化的静态变量会在BSS(未初始化的数据)段分配内存。直到程序结束,静态变量始终会维持前值。只不过全局静态变量和局部静态变量的作用域不一样。定义静态函数:在函数返回类型前加上 static 关键字,函数即被定义为静态函数。静态函数只能在本源文件中使用。在变量类型前加上static关键字,变量即被定义为静态变量。静态变量只能在本源文件中使用。在C++中,static关键字可以用于定义类中的静态成员变量:使用静态数据成员,它既可以被当成全局变量那样去存储,但又被隐藏在类的内部。类中的 static 静态数据成员拥有一块单独的存储区,而不管创建了多少个该类的对象。所有这些对象的静态数据成员都共享这一块静态存储空间。在C++中,static关键字可以用于定义类中的静态成员函数:与静态成员变量类似,类里面同样可以定义静态成员函数。只需要在函数前加上关键字static 即可。如静态成员函数也是类的一部分,而不是对象的一部分。所有这些对象的静态数据成员都共享这一块静态存储空间。

「注意」:当调用一个对象的非静态成员函数时,系统会把该对象的起始地址赋给成员函数的this指针。而静态成员函数不属于任何一个对象,因此C++规定静态成员函数没有this指针(重点)。既然它没有指向某一对象,也就无法对一个对象中的非静态成员进行访问。

9. 说说数组和指针的区别 定义不同:数组是用于储存多个相同类型数据的集合,数组名是首元素的地址。指针相当于一个变量,但是它和其它变量不一样,它存放的是其它变量在内存中的地址,指针名指向了内存的首地址。内存分配:数组的内存分配是静态的,这意味着数组的大小在编译时就已经确定了。指针可以动态地分配内存,这意味着指针在运行时可以使用malloc()或类似函数动态地分配内存。初始化:数组可以在定义时初始化,也可以在之后进行初始化。指针在定义时可以初始化为NULL,但不会分配内存。使用:数组可以直接访问元素,例如,可以将数组的第一个元素称为arr[0]。指针必须先解除引用,才能访问指向的对象,例如,可以通过*p来访问指向的对象。算术运算:指针可以进行算术运算,如指向下一个地址、上一个地址、加上一个整数等。这些运算符在指针操作中非常实用。而数组的不同元素之间是可以进行算术运算的,但它们必须以整数为单位,并且指向的内存地址必须是连续的。赋值:同类型指针变量可以相互赋值;数组不行,只能一个一个元素的赋值或拷贝。求sizeof:求数组所占存储空间的内存大小为 sizeof(数组名) / sizeof(数据类型)。在32位平台下,无论指针的类型是什么,sizeof(指针名) 都是4,在64位平台下,无论指针的类型是什么,sizeof(指针名) 都是8。 10. 说说什么是函数指针,如何定义函数指针,有什么使用场景 函数指针是指向函数的指针,即它包含函数的地址。函数指针可以像普通指针一样传递给函数,也可以用作函数返回值。使用函数指针可以方便地调用不同的函数,以匹配参数和返回值类型。在C++中,定义函数指针需要指定函数名、参数类型和返回类型。例如,以下是一个指向接受两个整数参数并返回一个整数的函数的指针的定义: int (*funcPtr)(int, int);

这个定义中,funcPtr是指向函数的指针,它指向的函数接受两个整数参数并返回整数。要使用函数指针,需要将其初始化为一个函数的地址。例如,以下是将funcPtr初始化为函数add的地址的示例:

#include using namespace std; int add(int x, int y) { return x + y; } int main() { int (*funcPtr)(int, int) = &add; int result = (*funcPtr)(3, 4); // 调用函数指针 cout cout public: void breathe() { cout return a + b; } int main() { int a = 5, b = 3; // 调用内联函数 int c = add(a, b); cout pointer_name(parameter); } 将函数指针作为变量使用: int add(int x, int y) { return x + y; } int main() { int (*func_ptr)(int, int); func_ptr = add; int result = func_ptr(1, 2); return 0; }

在上面的例子中,我们先定义了一个函数指针 func_ptr,然后将函数 add 的地址赋值给它。接着,我们通过 func_ptr 来调用函数 add 并计算出结果。

从使用方式上来看,函数指针主要用于将函数作为数据传递、动态调用函数以及函数指针数组的构建。

指针函数的定义和用法

指针函数是返回指针类型的函数,它的返回值是一个指针。在C++中,指针函数的定义格式为:

data_type* function_name(parameter1_type, parameter2_type, ...)

其中,data_type 表示指针所指向的数据类型,function_name 是函数名称,parameter1_type、parameter2_type 等则是函数参数的类型。

指针函数的用法可以简单地归纳为以下两类:

返回指向堆内存的指针: int* create_array(int size) { int* arr = new int[size]; return arr; }

在上面的例子中,我们使用 new 关键字来创建一个动态数组,并返回它的指针。

返回指向静态或全局内存的指针: char* get_message() { static char message[] = "Hello world"; return message; }

在上面的例子中,我们定义了一个静态字符数组 message,并将其作为指针函数的返回值。

从使用方式上来看,指针函数主要用于返回指向堆内存或静态/全局内存的指针,以及处理复杂的数据结构和对象。

「总结」:函数指针和指针函数虽然都与指针有关,但是它们的含义和用法却大不相同。函数指针主要用于将函数作为数据传递、动态调用函数以及函数指针数组的构建,而指针函数主要用于返回指向堆内存或静态/全局内存的指针,以及处理复杂的数据结构和对象。

20. 说说const int *a, int const *a, const int a, int *const a, const int *const a分别是什么,有什么特点 const int a; // a是一个常量,不允许修改 const int* a; // a指针所指向的内存里的值不变,即 (*a) 不变 int const* a; // 同 const int *a; int* const a; // a指针所指向的内存地址不变,即a不变 const int* const a; // 都不变,即 (*a) 不变,a也不变 21. 说说使用指针需要注意什么 指针空值检查:在使用指针之前,需要检查它是否为 NULL。如果指针是NULL,则表示该指针不指向任何有效的内存位置,进一步操作可能导致程序崩溃。指针悬空问题:指针悬空是指指针指向的内存位置已经被释放或已经失效,但是指针仍然指向该位置,这时候对指针进行取值或者修改,会导致未知的错误。指针越界:当指针操作的内存范围超出了分配给它的内存区域,就会导致指针越界,这可能会导致程序崩溃或者数据被破坏。内存泄漏:使用动态分配的内存时,需要确保在使用完毕后进行释放,否则会导致内存泄漏,使得系统的可用内存变少。多级指针:如果使用多级指针,需要确保正确理解指针的级别及其所指向的内存区域,以避免出现不必要的错误。指针运算:在使用指针操作时,需要确保运算的正确性和安全性,否则会破坏内存数据,导致程序崩溃。指针类型:在声明和使用指针时,需要确保指针类型与其所指向的内存位置的类型相匹配,否则会导致数据类型不匹配的错误。指针别名:指针别名是指两个或多个指针指向同一内存位置,这时候如果对一个指针进行修改,会影响其它指针所指向的内存位置,这可能会导致不必要的错误。 22. 说说内联函数和函数的区别,内联函数的作用

区别:

内联函数比普通函数多了关键字 inline;内联函数避免了函数调用的开销,普通函数有调用的开销;普通函数在被调用的时候,需要寻址(函数入口地址),内联函数不需要寻址;内联函数有一定的限制,内联函数体要求代码简单,不能包含复杂的结构控制语句,普通函数没有这个要求。

内联函数的作用:内联函数在调用时,是将调用表达式用内联函数体来替换。避免函数调用的开销。

「注意」:

在内联函数内不允许用循环语句和开关语句:如果内联函数有这些语句,则编译将该函数视同普通函数那样产生函数调用代码,递归函数是不能被用来做内联函数的。内联函数只适合于只有1~5行的小函数。对一个含有许多语句的大函数,函数调用和返回的开销相对来说微不足道,所以也没有必要用内联函数实现。内联函数的定义必须出现在内联函数第一次被调用之前。内联声明只是建议,是否内联由编译器决定,所以实际并不可控。 23. 简述C++有几种传值方式,之间的区别是什么

传参方式有三种:值传递、引用传递、指针传递。

值传递:形参即使在函数体内值发生变化,也不会影响实参的值;引用传递:形参在函数体内值发生变化,会影响实参的值;指针传递:在指针指向没有发生改变的前提下,形参在函数体内值发生变化,会影响实参的值。

「总结」:值传递用于对象时,整个对象会拷贝一个副本,这样效率低。而引用传递用于对象时,不发生拷贝行为,只是绑定对象,更高效。指针传递同理,但不如引用传递安全。

代码示例:

#include using namespace std; void testfunc(int a, int* b, int& c) { // 形参a的值发生了改变,但是没有影响实参i的值 // 但形参*b、c的值发生了改变,影响到了实参*j、k的值 a += 1; (*b) += 1; c += 1; cout


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3