Hi,大家好,这里是鲨鱼编程, 本次为大家准备了23个经典的问题。不过一定要注意,这些只适合面试参考,更多的知识和对C语言深入理解还需要大家自己平常勤加练习啊!!!!
注意了!!!需要pdf版本的可以关注鲨鱼编程公众号后,发送消息:C语言面试问题。即可领取pdf版。
1.const的作用有哪些,谈一谈你对const的理解?
const是C++中的关键字,它的作用是用来声明一个变量为常量,即该变量的值在声明后就不能被修改。const可以应用于不同的数据类型,包括基本数据类型、指针、类等。使用const可以使代码更加安全、可读性更高,同时也可以优化编译器的优化。
2. 描述char、const char、char const、const char const的区别?
char 表示一个指向字符型数据的指针,可以用来修改所指向的字符数据。const char表示一个指向字符型数据的指针,该指针所指向的字符数据是不可修改的。char const表示一个指向字符型数据的常量指针,该指针指向的字符数据可以被修改,但是该指针本身的值是不可修改的。const char const表示一个指向字符型数据的常量指针,该指针指向的字符数据是不可修改的,同时该指针本身的值也是不可修改的。
3. 指针常量和常量指针有什么区别?
指针常量和常量指针是两个不同的概念。指针常量是指一个指针,该指针的值是不可修改的,但是所指向的数据可以被修改。常量指针是指一个指针,该指针所指向的数据是不可修改的,但是指针本身的值可以被修改。换句话说,指针常量是一个指针,它指向的是可变的数据,但是指针本身的值是不可变的;而常量指针是一个指针,它指向的是不可变的数据,但是指针本身的值是可变的。
4. static的作用是什么,什么情况下用到static?
static是C++中的一个关键字,它可以用于不同的上下文中,但主要的作用是控制变量、函数、类的作用域和生命周期。当static修饰一个变量时,该变量的生命周期与程序的生命周期一样长,即在程序运行期间一直存在。此外,static还可以用于隐藏函数和变量,使得它们仅在当前文件中可见,这样可以避免在不同文件中的命名冲突。
在C++中,常见的用到static的情况有:
- 在函数内部定义一个static变量,可以保证该变量在函数调用结束后仍然存在,且其值不会丢失。
- 在类中定义一个static成员变量或static成员函数,可以使得该变量或函数与类的实例无关,而且可以在类外部直接访问。
- 在文件中定义一个static全局变量或函数,可以将其作用域限制在当前文件中,避免与其他文件中的同名变量或函数冲突。
5. 全局变量与局部变量的区别?
全局变量和局部变量都是C++中的变量,它们的主要区别在于作用域和生命周期。全局变量是在程序的任何地方都可以访问的变量,其作用域是整个程序,生命周期则与程序的生命周期一样长,即全局变量在程序开始执行时创建,在程序结束时销毁。而局部变量仅在定义它的代码块中可见,其作用域是该代码块,生命周期则随着代码块的执行而创建和销毁,当代码块执行完毕时,局部变量也会被销毁。
另外,全局变量和局部变量在内存中的存储方式也不同。全局变量在程序的数据段中分配内存,而局部变量通常在栈中分配内存。
6. 宏定义的作用是什么?
宏定义是C++中的一种预处理指令,用于定义一个常量或一个代码片段。宏定义的作用是可以在代码中使用宏名来代替一个表达式或语句,从而简化代码,提高代码的可读性和可维护性。在C++中,宏定义通常使用#define关键字来定义,它的语法格式为:
#define 宏名 值或代码片段
其中,宏名是一个标识符,值或代码片段可以是任意合法的C++代码,包括常量、表达式、函数等。在C++中,宏定义通常用于定义常量、简化代码、实现代码的条件编译等场景。需要注意的是,在使用宏定义时,应该避免定义过长或过于复杂的宏,以免影响代码的可读性和可维护性。
7. 内存对齐的概念?为什么会有内存对齐?
内存对齐是指在分配内存时,按照一定规则将数据类型的存储地址调整为某个特定的倍数。这个特定的倍数称为对齐边界,通常是数据类型大小的整数倍。内存对齐的目的是为了提高存取数据的效率,因为许多计算机系统要求数据存储在特定的地址上,如果数据没有按照对齐边界进行对齐,就需要进行额外的处理,降低了访问速度。
8. inline 内联函数的特点有哪些?它的优缺点是什么?
inline函数是一种特殊的函数,它的主要特点是可以将函数的代码直接嵌入到调用该函数的代码中,从而避免了函数调用的开销。inline函数的优点是可以提高程序的执行效率,减少函数调用的开销,尤其是当函数体较小且多次调用时,效果更为明显。缺点是可能会增加代码的长度,导致代码膨胀,影响程序的性能。
9. 如何用C 实现 C++ 的面向对象特性(封装、继承、多态)
封装:在C语言中,可以使用结构体来封装数据和函数,将数据和函数放在同一个结构体中,使用结构体变量来调用函数和访问数据。同时,可以使用函数指针来实现类似于C++中的虚函数机制。
继承:在C语言中,可以使用结构体嵌套来实现继承,即在一个结构体中嵌套另一个结构体,从而实现对父类中成员的继承。同时,可以使用函数指针来实现类似于C++中的虚函数机制。
多态:在C语言中,可以使用函数指针来实现多态,即在不同的结构体中定义相同的函数指针,然后在调用函数时,根据实际传入的结构体类型,动态地确定要调用的函数指针。
10. memcpy怎么实现让它效率更高?
memcpy是C语言中的一个库函数,用于在内存之间复制一定数量的字节。为了提高memcpy的效率,可以采用以下方法:
尽可能使用内存对齐,这样可以减少内存访问的次数。
使用SIMD指令(如SSE、AVX等)实现并行复制,这样可以多个字节同时复制,提高复制速度。
对于较大的数据块,可以使用多线程并行复制,从而进一步提高效率。
11. typedef和define有什么区别?
typedef和define都是C语言中用于定义别名的关键字,但它们有以下区别:
- typedef仅仅是定义了一个类型的别名,而define可以定义任何文本的别名,包括类型、变量、函数等。
- typedef在编译器进行类型检查时比define更加安全,因为它会检查类型的正确性。
- 使用typedef定义别名时,可以使用类型名作为新的类型名,而define只能定义一个标识符作为别名。
- 在C++中,typedef可以使用模板来定义别名,而define不支持。
- 总的来说,typedef更加推荐使用,因为它比define更加安全、可读性更高,同时也更加灵活。
12. extern有什么作用,extern C有什么作用?
extern是C语言中的一个关键字,用于声明一个变量或函数的外部链接。它的作用是告诉编译器这个变量或函数是在其他文件中定义的,需要在链接时进行链接。extern C是用于C++语言的一个扩展,用于告诉编译器这个函数是使用C语言的函数命名规则,而不是C++的函数命名规则,从而避免了C++中函数名的重载问题。
13. 如何避免野指针?
避免野指针的方法有以下几种:
- 在指针定义时初始化为NULL或0,这样可以避免未初始化的指针。
- 对于指针变量,在使用前进行判断是否为空指针。
- 在指针变量生命周期结束时,将其置为NULL,避免成为野指针。
- 对于动态分配的内存,在释放内存后将指针置为NULL,避免成为野指针。
14. 如何计算结构体长度?
计算结构体长度可以使用sizeof运算符,其返回值为结构体在内存中所占的字节数。例如,sizeof(struct MyStruct)可以计算出结构体MyStruct的长度。
15. sizeof和strlen有什么区别?
sizeof和strlen都是C语言中的运算符,但它们的作用不同。sizeof可以计算一个变量或类型的大小,以字节为单位,可以用于任何类型,包括基本类型、数组、结构体、指针等。strlen是用于计算一个字符串的长度,以字符为单位,只能用于字符数组或指向字符数组的指针。
16. 知道条件变量吗?条件变量为什么要和锁配合使用?
条件变量是多线程编程中的一种同步原语,用于实现线程之间的等待和通知机制。条件变量通常需要和锁配合使用,因为条件变量的等待和通知操作都是在临界区内进行的,需要保证同步和互斥。在等待条件变量时,线程会释放锁,从而允许其他线程访问临界区;在条件变量被通知时,线程会重新获取锁,从而继续执行临界区内的代码。这样可以避免忙等和死锁的问题,提高了多线程程序的效率和可靠性。
17. 什么是指针,如何使用指针?
指针是一个变量,它存储的是另一个变量的内存地址。使用指针可以实现对变量的间接访问,从而进行动态内存分配、传递参数、访问数组等操作。声明指针时需要指定指针所指向的数据类型,使用取地址符&获取变量的内存地址,使用解引用符*来访问指针所指向的变量。
18. 什么是动态内存分配,如何进行动态内存分配?
答:动态内存分配是指在程序运行时根据需要动态地分配内存空间,以存储变量或数据结构。在C语言中,可以使用malloc函数来进行动态内存分配,它的原型为void* malloc(size_t size),其中size表示需要分配的内存大小,返回值为分配的内存首地址。分配的内存空间通常需要在不需要时使用free函数进行释放,以避免内存泄漏。
19. 什么是结构体,如何定义和使用结构体?
答:结构体是一种由多个不同数据类型的变量组成的数据类型,它可以用来表示一个实体的多个属性或字段。在C语言中,可以使用struct关键字定义结构体类型,例如:
struct student {
char name[20];
int age;
float score;
};
定义结构体变量时需要使用结构体类型和变量名,例如:
struct student stu;
访问结构体变量的成员需要使用点运算符,例如:
stu.age = 20;
20. 什么是指针数组,如何定义和使用指针数组?
指针数组是由一组指针变量组成的数组,每个指针变量都指向一个特定的数据类型。在C语言中,可以使用指针数组来存储一组字符串或指向结构体的指针。定义指针数组时需要指定指针变量的类型和数组的大小,例如:
int *p[10];
定义了一个名为p的指针数组,它有10个元素,每个元素都是一个指向int类型的指针变量。访问指针数组的元素需要使用下标运算符[]和指针解引用符,例如:
*p[0] = 10;
21. 什么是静态变量和局部变量,它们之间有什么区别?
答:静态变量是指在函数外部或块作用域内定义的变量,它们在程序开始执行时被初始化,仅在程序运行期间分配一次内存空间,且在整个程序运行期间都存在。局部变量是指在函数内部定义的变量,它们在函数被调用时被分配内存空间,在函数执行完毕后被销毁。静态变量和局部变量之间的主要区别在于生命周期和作用域。静态变量具有全局作用域,在整个程序中都可以被访问,而局部变量只在所定义的函数内部可见。
22. 什么是文件操作,如何进行文件操作?
文件操作是指程序对计算机文件进行读取、写入、追加、删除等操作。在C语言中,可以使用标准库中的fopen、fclose、fread、fwrite、fseek等函数来进行文件操作。其中,fopen函数用于打开文件,返回一个文件指针;fclose函数用于关闭文件;fread和fwrite函数用于读取和写入文件数据;fseek函数用于定位文件读写位置。进行文件操作需要注意文件打开模式、文件读写位置、错误处理等问题。
23. 什么是递归,何使用递归实现程序功能?
递归是指函数调用自身的过程。在C语言中,可以使用递归来实现一些程序功能,例如计算斐波那契数列、遍历二叉树等。使用递归时需要注意递归结束条件、递归调用次数、栈空间占用等问题。递归调用过深可能会导致栈空间不足,从而导致程序崩溃。因此,在使用递归时需要仔细考虑程序设计和优化。