C语言经典面试题及答案100道
# C语言经典面试题及答案100道
## 基础概念部分
1. **什么是C语言?**
- 答:C语言是一种通用的、过程式的计算机编程语言,由Dennis Ritchie于1972年在贝尔实验室开发,主要用于系统软件开发。
2. **C语言的特点是什么?**
- 答:特点包括:结构化语言、高效性、可移植性、丰富的运算符、内存管理、指针操作等。
3. **解释C语言中的关键字和标识符的区别**
- 答:关键字是C语言预定义的保留字,有特殊含义;标识符是用户定义的变量、函数等名称,不能与关键字冲突。
4. **C语言中的基本数据类型有哪些?**
- 答:基本数据类型包括:int、char、float、double和void。
5. **什么是变量?如何声明变量?**
- 答:变量是存储数据的命名内存位置。声明语法:`数据类型 变量名;` 如 `int age;`
## 运算符与表达式
6. **解释C语言中的算术运算符**
- 答:+ (加)、- (减)、* (乘)、/ (除)、% (取模)、++ (自增)、-- (自减)
7. **什么是运算符优先级?**
- 答:决定表达式求值顺序的规则,如 * / % 优先级高于 + -
8. **++i和i++有什么区别?**
- 答:++i是先自增再使用,i++是先使用再自增
9. **什么是三元运算符?**
- 答:条件运算符 `?:`,语法:`条件 ? 表达式1 : 表达式2`
10. **sizeof运算符的作用是什么?**
- 答:返回变量或数据类型的字节大小
## 控制结构
11. **C语言中有哪些控制语句?**
- 答:if-else、switch、for、while、do-while、break、continue、goto
12. **if和switch的区别是什么?**
- 答:if适用于范围判断和条件组合,switch适用于离散值匹配
13. **break和continue的区别?**
- 答:break终止整个循环,continue跳过当前迭代继续下一次循环
14. **如何实现无限循环?**
- 答:`while(1)` 或 `for(;;)`
15. **goto语句的优缺点是什么?**
- 答:优点:灵活跳转;缺点:破坏程序结构,难以维护
## 函数
16. **什么是函数?如何定义函数?**
- 答:函数是完成特定任务的代码块。定义:`返回类型 函数名(参数列表) { 函数体 }`
17. **函数声明和函数定义的区别?**
- 答:声明告诉编译器函数签名,定义提供函数实现
18. **什么是递归函数?**
- 答:直接或间接调用自身的函数
19. **什么是内联函数?**
- 答:用inline声明的函数,编译器尝试在调用处展开代码以减少函数调用开销
20. **main函数的返回值有什么意义?**
- 答:返回0表示成功,非0表示错误代码
## 数组与字符串
21. **如何声明和初始化数组?**
- 答:`int arr[5];` 或 `int arr[] = {1,2,3};`
22. **数组和指针的关系是什么?**
- 答:数组名是指向数组首元素的常量指针
23. **如何传递数组给函数?**
- 答:传递数组名(指针)和大小,如 `void func(int arr[], int size)`
24. **什么是二维数组?**
- 答:数组的数组,如 `int matrix[3][3];`
25. **字符串和字符数组的区别?**
- 答:字符串是以'\0'结尾的字符数组
## 指针
26. **什么是指针?**
- 答:存储内存地址的变量
27. **如何声明指针变量?**
- 答:`数据类型 *指针名;` 如 `int *ptr;`
28. **&和*运算符的作用是什么?**
- 答:&取地址,*解引用
29. **什么是空指针?**
- 答:值为NULL的指针,不指向任何有效内存
30. **什么是野指针?**
- 答:指向无效内存或已释放内存的指针
## 结构体与联合体
31. **什么是结构体?如何定义?**
- 答:用户自定义的复合数据类型。定义:
```c
struct Student {
char name[50];
int age;
};
```
32. **结构体和数组的区别?**
- 答:数组存储同类型元素,结构体可存储不同类型元素
33. **如何访问结构体成员?**
- 答:使用点运算符(.)或箭头运算符(->)
34. **什么是联合体?**
- 答:所有成员共享同一内存空间的数据结构
35. **结构体和联合体的区别?**
- 答:结构体成员有独立内存空间,联合体成员共享内存
## 动态内存管理
36. **malloc和calloc的区别?**
- 答:malloc分配未初始化的内存,calloc分配并初始化为0
37. **什么是内存泄漏?**
- 答:分配的内存未释放导致内存浪费
38. **free函数的作用是什么?**
- 答:释放动态分配的内存
39. **realloc函数的作用?**
- 答:调整已分配内存块的大小
40. **动态内存分配失败怎么处理?**
- 答:检查返回的指针是否为NULL,并采取适当措施
## 文件操作
41. **文件打开模式有哪些?**
- 答:"r"(读),"w"(写),"a"(追加),"r+"(读写),"w+"(读写),"a+"(读写追加)
42. **fopen和fclose的作用?**
- 答:fopen打开文件,fclose关闭文件
43. **文件读写函数有哪些?**
- 答:fgetc/fputc, fgets/fputs, fread/fwrite, fprintf/fscanf
44. **什么是文件指针?**
- 答:FILE类型的指针,指向文件流
45. **如何检测文件结束?**
- 答:feof函数或读取函数返回EOF
## 预处理器
46. **#include的作用是什么?**
- 答:包含头文件内容
47. **#define的用途?**
- 答:定义宏常量或宏函数
48. **宏和函数的区别?**
- 答:宏在预处理期展开,函数在运行时调用;宏无类型检查
49. **条件编译指令有哪些?**
- 答:#if, #ifdef, #ifndef, #else, #elif, #endif
50. **#pragma的作用?**
- 答:提供编译器特定指令
## 位操作
51. **C语言中的位运算符有哪些?**
- 答:&(与)、|(或)、^(异或)、~(取反)、<<(左移)、>>(右移)
52. **如何设置特定位?**
- 答:使用或操作 `var |= (1 << bit_position)`
53. **如何清除特定位?**
- 答:使用与操作 `var &= ~(1 << bit_position)`
54. **如何检查特定位?**
- 答:`if(var & (1 << bit_position))`
55. **交换两个变量的值,不使用临时变量?**
- 答:使用异或操作:
```c
a ^= b;
b ^= a;
a ^= b;
```
## 复杂指针
56. **什么是指针的指针?**
- 答:存储指针地址的指针,如 `int **pp;`
57. **函数指针是什么?**
- 答:指向函数的指针,如 `int (*funcPtr)(int, int);`
58. **如何使用函数指针?**
- 答:
```c
int add(int a, int b) { return a+b; }
int (*funcPtr)(int, int) = add;
funcPtr(2,3);
```
59. **什么是void指针?**
- 答:通用指针类型,可指向任何数据类型
60. **如何对void指针进行算术运算?**
- 答:必须先转换为具体类型的指针
## 存储类别
61. **auto、static、register、extern的区别?**
- 答:auto(默认,自动存储期)、static(静态存储期)、register(建议寄存器存储)、extern(外部链接)
62. **局部变量和全局变量的区别?**
- 答:局部变量在函数内定义,全局变量在函数外定义
63. **static关键字的作用?**
- 答:对变量:保持值不变;对函数:限制作用域到当前文件
64. **extern关键字的作用?**
- 答:声明变量或函数在其他文件中定义
65. **volatile关键字的作用?**
- 答:防止编译器优化,指示变量可能被意外修改
## 高级话题
66. **typedef的作用是什么?**
- 答:为现有类型创建别名
67. **枚举类型是什么?**
- 答:用户定义的整数常量集合
68. **const关键字的作用?**
- 答:定义常量,防止修改
69. **什么是回调函数?**
- 答:通过函数指针调用的函数
70. **解释左值和右值**
- 答:左值可出现在赋值左侧,有内存位置;右值是临时值
## 常见算法实现
71. **实现冒泡排序**
- 答:
```c
void bubbleSort(int arr[], int n) {
for(int i=0; i<n-1; i++)
for(int j=0; j<n-i-1; j++)
if(arr[j] > arr[j+1])
swap(&arr[j], &arr[j+1]);
}
```
72. **实现二分查找**
- 答:
```c
int binarySearch(int arr[], int l, int r, int x) {
while(l <= r) {
int mid = l + (r-l)/2;
if(arr[mid] == x) return mid;
if(arr[mid] < x) l = mid+1;
else r = mid-1;
}
return -1;
}
```
73. **实现链表反转**
- 答:
```c
struct Node* reverse(struct Node* head) {
struct Node *prev = NULL, *current = head, *next = NULL;
while(current != NULL) {
next = current->next;
current->next = prev;
prev = current;
current = next;
}
return prev;
}
```
74. **实现斐波那契数列**
- 答:
```c
int fibonacci(int n) {
if(n <= 1) return n;
return fibonacci(n-1) + fibonacci(n-2);
}
```
75. **实现字符串反转**
- 答:
```c
void reverseString(char* str) {
int l = 0, r = strlen(str)-1;
while(l < r) {
char temp = str[l];
str[l] = str[r];
str[r] = temp;
l++; r--;
}
}
```
## 常见问题
76. **什么是段错误?**
- 答:访问非法内存地址导致的错误
77. **如何避免内存泄漏?**
- 答:确保每个malloc/calloc都有对应的free
78. **什么是缓冲区溢出?**
- 答:向缓冲区写入超出其容量的数据
79. **如何防止缓冲区溢出?**
- 答:使用安全函数如strncpy代替strcpy,检查边界
80. **什么是悬垂指针?**
- 答:指向已释放内存的指针
## 代码分析题
81. **以下代码输出什么?为什么?**
```c
int main() {
int i = 5;
printf("%d %d %d", i++, i++, i++);
return 0;
}
```
- 答:输出不确定,因为参数求值顺序未定义
82. **以下代码有什么问题?**
```c
char *str = "Hello";
str[0] = 'h';
```
- 答:试图修改字符串常量,导致未定义行为
83. **以下代码输出什么?**
```c
int main() {
int a = 10, b = 20;
if(a = b)
printf("Equal");
else
printf("Not equal");
return 0;
}
```
- 答:输出"Equal",因为使用了赋值(=)而非比较(==)
84. **以下宏定义有什么问题?**
```c
#define SQUARE(x) x*x
```
- 答:当参数是表达式时会有问题,如SQUARE(2+3)展开为2+3*2+3=11而非25
85. **以下代码输出什么?**
```c
int main() {
int a[] = {1,2,3,4,5};
int *ptr = (int*)(&a+1);
printf("%d %d", *(a+1), *(ptr-1));
return 0;
}
```
- 答:输出"2 5",因为&a+1跳过整个数组,ptr-1指向最后一个元素
## 编程题
86. **编写程序检查素数**
- 答:
```c
int isPrime(int n) {
if(n <= 1) return 0;
for(int i=2; i*i<=n; i++)
if(n%i == 0) return 0;
return 1;
}
```
87. **编写程序实现strcpy**
- 答:
```c
void my_strcpy(char *dest, const char *src) {
while((*dest++ = *src++) != '\0');
}
```
88. **编写程序计算字符串长度**
- 答:
```c
int my_strlen(const char *str) {
int len = 0;
while(*str++) len++;
return len;
}
```
89. **编写程序交换两个数**
- 答:
```c
void swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
```
90. **编写程序计算阶乘**
- 答:
```c
int factorial(int n) {
if(n == 0) return 1;
return n * factorial(n-1);
}
```
## 综合问题
91. **大端和小端的区别?如何检测?**
- 答:大端:高位在前;小端:低位在前。检测代码:
```c
int checkEndian() {
int i = 1;
char *c = (char*)&i;
return *c ? 1 : 0; // 1为小端,0为大端
}
```
92. **解释栈和堆的区别**
- 答:栈:自动管理,大小固定,存储局部变量;堆:手动管理,大小灵活,存储动态分配内存
93. **什么是内存对齐?为什么重要?**
- 答:数据在内存中的起始地址是其大小的整数倍。提高访问效率,某些硬件要求对齐
94. **解释可变参数函数的实现**
- 答:使用stdarg.h中的va_list、va_start、va_arg、va_end宏
95. **什么是守护进程?如何创建?**
- 答:在后台运行的进程。创建步骤:fork()、setsid()、改变工作目录、关闭文件描述符等
## 最新标准
96. **C99和C11的主要新特性?**
- 答:C99://注释、变长数组、bool类型、复合字面量等;C11:多线程、匿名结构体/联合体等
97. **restrict关键字的作用?**
- 答:指示指针是访问数据的唯一方式,帮助编译器优化
98. **_Generic关键字的作用?**
- 答:提供类似C++函数重载的功能
99. **原子操作在C11中如何实现?**
- 答:使用<stdatomic.h>头文件中的原子类型和操作
100. **C语言未来的发展方向?**
- 答:更好的并行支持、安全性增强、与现代硬件特性匹配等
这些题目涵盖了C语言面试中的主要知识点,包括基础概念、语法细节、内存管理、算法实现等。准备面试时,建议不仅要记住答案,还要理解背后的原理,并能实际编写代码演示。