若你正处于准备C语言面试的状态,径直去背答案是无法确保能通过的,因为面试官更为看重的是你对其背后原理是否真的理解。下面这11个问题几乎在每次面试当中都会出现,弄明白它们能够让你的通过率显著提高。
声明与定义的区别常被混淆
有不少人将声明跟定义给混淆在一起,然而于面试期间这可是首个会被扣分的要点。声明仅仅是向编译器表明某个变量或者函数是存在着的,像是extern int a;这般,它并不会去赋予内存。而定义却是切切实实地分配内存空间的,就好像int a = 10;这样。一个变量或者函数是能够具备很多次声明的,不过却仅仅能够拥有一次定义。在2025年当我于腾讯进行面试之际,面试官先是询问了这个概念,随后便叫我在一个涉及多文件的项目里去找出重复定义的差错。
实际进行编码操作的时候,头文件当中放置的是声明,源文件当中放置的是定义。刚刚接触的新手容易在头文件当中定义变量,当多个源文件都包含这个头文件时,在链接阶段就会出现报重复定义错误的情况。字节跳动所出的面试题里面就有一道专门用来考察这个陷阱的题目,题目给出了一段会报错的代码让你来定位问题所在。
四种存储类说明符各有分工
1. auto是最为常见的,局部变量若不加修饰缺省便是它,然而实际上百分之九十九的人都不会特意去写auto。2. register是建议编译器将变量放置于寄存器里,现代编译器的优化能力十分强大,这个关键字基本上被忽略,面试官更多的是考查你是否知道它的历史。
对于static的作用,需要区分成两种情形去记:当它用于修饰局部变量的时候,它会使得变量拥有更长的生命周期,让函数退出之后数值不会消失不见了,下一次进行调用的时候呈现的依旧是上一次的数值;当它用于修饰全局变量或者函数的时候,它限定作用域仅仅能够在当前的文件范围之内。而出 extern这一情况呢,它是用作去引用那一些在其他文件之中所定义的全局变量。我在华为参与面试之际被问到过这样一个问题:在唯独一个文件里定义static int b ,在另外除开这个文件的其他文件之中使用extern int b ,那是否能够访问得到呢?答案是不可以访问到。
inline只是给编译器的建议
inline关键字用以告知编译器,将函数代码直接嵌入至调用之处,以此省去函数调用时的压栈出栈开销。然而需要留意,编译器具备完全的权力去忽略此项建议,特别是在函数体过大或者存在递归的情形下。在2024年Linux内核6.8版本发布之际,还曾探讨过一些inline函数的优化争议,面试官有可能会借助这个例子来询问你在怎样的情况之下inline会失效。
好多人觉得运用了inline函数就必定会被内联,这属于误解,现代编译器的优化等级像 -O2之类甚至会自行裁夺哪些普通函数该被内联,手动添加inline反倒显得多余,微软面试题里曾让应聘者剖析一段内联函数的汇编代码,用以推断编译器是否真的进行了内联。
volatile防止变量被意外优化
volatile关键字向编译器传达,该变量存在于程序外部被修改的可能性,凡每次使用此变量均需从内存地址进行读取操作,而绝不可从寄存器缓存中获取相关值。在嵌入式开发领域常常会碰到这种情况,就比如,读取硬件状态寄存器时会遇到,或者像是多个线程共享的全局变量这种情况也会碰到。
有一位在小米,从事驱动工作的朋友,曾经分享过,他们在面试的时候,必定会问到volatile,给出的代码当中存在一个while循环,此循环用于等待某个内存地址的值发生变化,要是不加volatile的话,经过编译器优化之后,有可能会直接读取一次寄存器,进而陷入死循环,另外,volatile并不能保证原子性,很多人错误地认为它能够当作线程同步来使用,这属于严重的认知偏差。
const不仅是只读这么简单
初始化之后,const修饰的变量就不可以再进行修改了,这一点大家都是明白的。然而,在面试的时候,更加倾向于询问const和#define之间的区别。const常量是存在数据类型的,在编译阶段会开展类型检查,可是宏定义仅仅是进行纯文本替换。2023年C11标准发布之后,constexpr使得常量表达方式变得更加严谨,不过面试的时候依旧热衷于拿传统const来提问。
这里存在一个高频考点,它是指向常量的指针以及常量指针。其中,“const int * p”属于指向常量的指针范畴,也就是说,p能够指向其他地方,然而却不可以借助p去修改其所指向的内容。另外,“int const p”则是常量指针,这意味着p在初始化之后便无法再指向别的地方了,不过其所指向的内容是能够被修改的。腾讯曾经在一年的校招笔试题里,特意给出了一段关于指针的操作内容,要求你去判断哪一行代码会出现编译报错的情况。
指针数组与数组指针别搞反
存放指针的数组:此短语的重点在于“数组”,也就是说数组当中的每一个元素皆是指针,就像int arr[10],arr属于一个拥有10个元素的数组,而且每个元素均为int指针。指向数组的指针:重点在于“指针”,即这个指针所指向的是一个数组,例如int (p)[10],p是一个指针,其指向存放10个int的数组。
这两个于操作二维数组之际格外易于混淆,阿里2024年面试题要求运用数组指针去遍历二维数组,在现场撰写代码之时,有人将其写成指针数组,编译之时直接报出类型不相符,另外还有一道经典考题,char str[]和char (str)[]的差异,前者是字符串数组,后者是指向字符数组的指针。
堆和栈的管理方式天差地别
栈内存是由系统自动去进行管理的,局部变量处于这里,函数参数也在这儿,其分配速度是极其快的,它的大小通常仅仅只有几MB,要是超出了这个范围就会导致栈溢出。堆内存则是需要程序员亲自手动去申请然后释放的,它的大小在理论上来说只要有多少内存便能够使用多少,然而要是管理出现不当的情况就会造成内存泄漏。
当初美团在面试之际考过场景类型的题目,具体是这样的,有一个服务器程序持续运行了一个星期之后就变慢了,接着运用top去查看内存的占用情况,发现其呈现出持续增长的态势,然后问你该怎么去进行排查。答案是这样的,要看堆内存是不是存在未被释放的情况。栈上面的变量在函数结束以后就会自动被回收,如果不调用free的话占据堆上的空间就会一直持续占用着,一直到程序退出才不会占用。在2025年所统计的开源项目漏洞当中,发现堆内存相关的错误占比依旧超过了三成。
内存泄漏的根本原因是指针丢了
内存泄漏并非内存从物理层面消失不见,而是你已然丧失了对其的掌控。你借助 malloc 在堆上划分出了一块区域,然而保存这块区域地址的指针却遭到了覆盖,被重新进行了赋值,又或者在函数返回之前既没有保存该地址,也没有实施 free 操作,如此一来,这块内存便永远都无法被释放掉了。
360的面试官,曾给过我一个例子,函数当中进行了malloc操作,分配了100字节,中间调用了另外一个函数,指针被传递进去,在那个函数里面,把指针指向了NULL,返回之后,原来的指针就不存在了,外层也就没办法进行free操作了,这就是典型的指针被错误修改的情况,现代开发当中,常常会使用静态分析工具来检测内存泄漏,但是面试的时候,还是比较喜欢通过手写代码来找出问题。
字符串操作最容易踩坑
C语言里,处理字符串用的函数,好多都是魔鬼表现。strcpy这个,它不会去检查目标缓冲区大小,结果溢出这种情况就很常见;strlen它返回的是字符个数,可这个不包括结尾的'',新手常常就会少分配1字节;strcmp它比较的是内容并非地址,然而有人却用==直接去比指针。
百度在2024年进行校招时,出了一道改错题,其内容为,用char *p ="hello"这样的方式定义了字符串,之后又尝试去通过,p[0] = 'H'进行修改,结果直接导致崩溃,究其原因在于,字符串常量被存放在了只读数据段,对其进行修改就会触发段错误现象。而正确的做法应该是采用数组,也就是char p[] ="hello"。
文件操作要三步不能少
使用fopen来打开文件,通过fread、fwrite以及fprintf进行读写操作,利用fclose来关闭。有不少人写了fclose,然而前面在fopen失败的情况下却没有进行处理,从而致使出现空指针的操作情况。另外还有人在文件操作的过程中间出现了错误,提前进行了return,却忘记了fclose,进而造成了文件句柄的泄漏。
2025年,某大厂的面试题是,写一个函数,用于复制文件的内容,这个函数需要处理各种各样的异常情况。在评分标准里,打开失败、读取失败、写入失败、关闭失败这些情况都必须要考虑进去。并且,无论操作成功也好,还是失败也罢,都得保证资源能够被释放。使用goto统一进行收尾,这是一种比较常见的写法,到时候面试官会询问,是否存在更好的方式。

手写算法题不能只靠背
二进制里头,1的个数存在经典的解法,那便是n与(n - 1)进行操作,每一次都能将最低位的1消除掉,不停地循环若干次,就会有相应个数的1。把字符串转变为整数的时候,需要对正负号、溢出情况、非法字符以及空指针等方面加以考虑。而字符串的逆序操作,能够通过双指针在原地进行交换来达成。

面试快手之际,我碰到过这样的变种题目:将一个英文句子逆序,且不申请额外空间,同时单词内部顺序保持不变,单词之间进行逆序操作。先是整体进行逆序,随后逐个单词进行逆序,这乃是一个经典的分两步来走的策略。面试官所期望的并非单纯的死记硬背,而在于你讲解解题思路的时候,逻辑是不是清晰。

问到末尾,再向大伙提一个问题:你于C语言面试范围里碰见过得最超出意料的考题是啥呢?欢迎于评论区域予以分享,点赞并收藏此文章,待到下次面试之前时将其取出进行温习一回。


Comments NOTHING