C语言面试题大全及详细答案(企业实战版)-1_第1页
C语言面试题大全及详细答案(企业实战版)-1_第2页
C语言面试题大全及详细答案(企业实战版)-1_第3页
C语言面试题大全及详细答案(企业实战版)-1_第4页
C语言面试题大全及详细答案(企业实战版)-1_第5页
已阅读5页,还剩7页未读, 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

C语言面试题大全及详细答案(企业实战版)本题库整理互联网、嵌入式、后端开发岗位高频C语言面试题,剔除书面化空洞表述,答案贴合实际开发场景,覆盖基础语法、核心难点、易错点、实操编程,适合求职面试、笔试刷题使用。一、C语言基础语法高频题1、简述C语言的特点答:C语言是结构化、过程式的编译型编程语言,核心特点如下:1.语法简洁、关键字少,代码执行效率极高,接近汇编语言;2.支持底层操作,可直接操作内存地址、硬件寄存器,适合嵌入式、系统开发;3.结构化编程,支持顺序、分支、循环三种逻辑,代码可读性、可维护性强;4.可移植性好,跨平台适配性强,主流操作系统、嵌入式设备均支持C语言编译运行;5.没有面向对象、垃圾回收机制,内存管理、资源释放需要开发者手动处理;6.兼具高级语言的易用性和低级语言的底层操控能力,是操作系统、驱动、底层软件的核心开发语言。2、简述变量的生命周期和作用域答:作用域:指变量可以被访问、使用的代码范围,分为局部作用域和全局作用域。1.局部变量:定义在函数、代码块内部,仅在当前函数/代码块内有效,外部无法访问;2.全局变量:定义在所有函数外部,整个源文件均可访问,跨文件可通过extern声明使用。生命周期:指变量在内存中存在的时间。1.局部变量:程序执行进入代码块时开辟内存,代码块执行结束后立即释放内存;2.全局变量:程序启动时分配内存,整个程序运行期间常驻内存,程序退出后释放;3.static静态局部变量:首次执行初始化时分配内存,程序结束才释放,生命周期等同于全局变量,但作用域仅限当前函数。3、static关键字的三大作用答:static是静态修饰符,在C语言中有三种核心用途,面试高频考点:1.修饰局部变量:延长变量生命周期至程序结束,只会初始化一次,多次调用函数时变量值会保留上一次的结果;2.修饰全局变量:限制变量作用域,仅当前源文件可访问,其他文件无法通过extern引用,避免全局变量跨文件冲突;3.修饰函数:将函数变为静态函数,仅当前源文件可调用,隐藏函数接口,防止跨文件函数重名冲突。4、const关键字的作用及用法答:const用于修饰只读变量,被修饰的值不可修改,核心作用是代码防错、规范编程、节省内存。1.修饰普通变量:constinta=10;变量a值固定,无法二次赋值修改;2.修饰指针变量(高频易错):-constint*p:指针指向的值不可改,指针本身的地址可以改;-int*constp:指针本身的地址不可改,指向的值可以改;-constint*constp:指针地址和指向的值都不可修改;3.修饰函数形参:防止函数内部意外修改传入的参数数据,保护原始数据;4.修饰全局常量:常量存储在只读数据区,不占用栈内存,防止数据被篡改。5、define和const的区别答:两者均可定义常量,核心区别如下:1.处理阶段不同:define是预处理指令,预编译阶段直接文本替换,无类型检查;const是变量修饰符,编译阶段处理,有严格的数据类型校验;2.类型差异:define无数据类型,纯粹文本替换,容易产生运算优先级错误;const有明确数据类型,语法更严谨;3.内存占用:define常量不占用内存,仅做替换;const常量会分配只读内存空间;4.调试性:const变量可调试查看值,define替换后无变量标识,无法调试;5.作用域:define默认全局有效,可通过#undef取消定义;const遵循变量作用域规则。二、指针核心高频题(面试重点)1、什么是指针?指针和指针变量的区别答:指针:就是内存地址,是内存单元的编号,是一个纯数值;指针变量:专门用来存储内存地址的变量,本质是一个变量,占用固定内存(32位系统4字节,64位系统8字节)。简单总结:指针是地址本身,指针变量是存放地址的容器。日常开发中所说的操作指针,本质都是操作指针变量。2、野指针是什么?如何避免野指针?答:野指针定义:指向未知、非法内存地址的指针,指针变量没有初始化,或指向的内存已被释放、回收。野指针危害:程序崩溃、段错误、内存踩踏、数据异常,且bug隐蔽,极难排查。产生原因:1.指针变量未初始化,默认指向随机内存地址;2.指针指向的局部变量内存释放后,指针未置空;3.指针越界访问内存。避免方法:1.指针定义时立即初始化,默认赋值为NULL;2.内存释放、变量销毁后,立刻将指针置为NULL;3.使用指针前先判断是否为NULL,非空再操作;4.严格控制指针访问范围,避免越界。3、空指针和野指针的区别答:1.空指针(NULL):指向地址为0的指针,是系统预留的只读非法地址,有明确指向,可通过if判断规避,操作空指针会直接报空指针错误,问题易排查;2.野指针:指向随机未知内存地址,无明确指向,无法判断规避,会导致随机崩溃、内存错乱,bug隐蔽性极强。核心区别:空指针是可控的非法指针,野指针是不可控的随机非法指针。4、二级指针的作用、使用场景答:二级指针是指向指针变量的指针,定义格式:int**p;核心使用场景:1.修改一级指针本身的值:普通一级指针传参只能修改指针指向的数据,无法修改指针指向的地址,二级指针可以直接修改一级指针的指向;2.操作二维数组:通过二级指针遍历、操作二维数组数据;3.动态开辟一维、二维指针数组:批量管理多个指针变量;4.字符串数组操作:存储多个字符串,char**str可管理多个字符串指针。5、指针数组和数组指针的区别(高频必考)答:两者名称相似、极易混淆,核心区分看优先级:[]优先级高于*1.指针数组:int*p[5];本质是数组,数组的每个元素都是int类型指针,占用5个指针大小的内存,主要用于存放多个指针、多个字符串。2.数组指针:int(*p)[5];本质是指针,专门指向一个包含5个int元素的数组,仅占一个指针大小内存,主要用于遍历二维数组。三、内存管理高频题1、C语言内存分区详解答:程序运行时,内存主要分为5个区域,从低地址到高地址依次为:1.代码区:存放程序编译后的二进制指令,只读,程序运行期间不可修改;2.全局/静态区:存放全局变量、static静态变量,程序启动分配、退出释放,分为已初始化区和未初始化区;3.常量区:存放字符串常量、const修饰的只读常量,只读属性,修改会触发段错误;4.栈区(stack):自动分配释放,存放局部变量、函数形参、函数返回地址,栈空间有限,默认几MB,超出会栈溢出;5.堆区(heap):手动分配释放,由malloc、calloc、realloc开辟,空间大、灵活,全程需要开发者手动free释放,否则造成内存泄漏。2、malloc、calloc、realloc的区别答:三者均为堆区动态内存开辟函数,核心区别如下:1.malloc:仅开辟指定大小内存,不初始化,内存中是随机脏数据,原型:void*malloc(size_tsize);2.calloc:开辟n个大小为size的内存,开辟后自动初始化为0,原型:void*calloc(size_tn,size_tsize);效率略低于malloc;3.realloc:重新调整已开辟堆内存的大小,可扩容、可缩容,原型:void*realloc(void*ptr,size_tsize);注意:realloc扩容时,若原内存后方空间充足,直接追加空间;空间不足则重新开辟新内存、拷贝数据、释放原内存。3、什么是内存泄漏?产生原因及解决办法答:内存泄漏:堆区动态开辟的内存,使用结束后没有手动free释放,且程序丢失该内存的指针,导致内存无法回收,直至程序退出。产生原因:1.malloc/calloc/realloc开辟内存后,未对应free释放;2.指针重新赋值,丢失原堆内存地址,无法释放;3.函数内开辟堆内存,返回前未释放,且无外部指针接收。解决办法:1.遵循谁开辟谁释放原则,动态内存使用完毕立即free;2.free后立刻将指针置为NULL,避免野指针;3.复杂逻辑统一封装内存申请、释放接口,避免遗漏。4、栈溢出的原因和解决方案答:栈溢出原因:1.函数递归深度过大,层层堆积栈帧,耗尽栈空间;2.函数内部定义超大局部数组、结构体,占用过多栈内存;3.死循环调用函数,无限创建栈帧。解决方案:1.减少递归深度,递归改循环;2.超大变量从栈区移至堆区,动态开辟内存;3.优化代码逻辑,杜绝死循环调用。四、函数与结构体高频题1、形参和实参的区别答:1.实参:调用函数时传入的真实参数,可以是常量、变量、表达式,占用调用函数的内存;2.形参:函数定义时括号内的参数变量,仅在函数调用时分配内存,函数结束立即释放;核心特点:C语言函数参数传递为值传递,形参是实参的临时拷贝,修改形参不会影响实参;如需修改实参,需要传递指针地址。2、函数值传递和地址传递的区别答:1.值传递:传递变量本身的值,函数内部修改的是拷贝后的临时变量,无法修改外部原始变量,适合只读数据传递;2.地址传递(指针传递):传递变量的内存地址,函数内部通过地址直接操作原始变量内存,可以修改外部数据,适合大数、数组、结构体传递,避免拷贝开销。3、结构体结构体对齐规则、内存对齐原理答:C语言结构体默认开启内存对齐,目的是适配CPU数据读取规则,提升读取效率(CPU按固定字节块读取内存,未对齐会多次读取,效率低下)。对齐规则:1.结构体每个成员的偏移地址,必须是自身大小的整数倍;2.结构体整体大小,必须是结构体中最大基本数据类型的整数倍;3.可通过#pragmapack(n)手动指定对齐字节。示例:structTest{chara;intb;};char占1字节,后补3字节对齐,int占4字节,整体大小8字节。4、结构体和联合体的区别答:1.内存存储方式不同:结构体成员占用独立内存,互不重叠;联合体所有成员共用同一块内存,同一时间只能使用一个成员;2.内存大小不同:结构体大小遵循内存对齐规则,为所有成员占用内存总和+对齐填充字节;联合体大小为最大成员的内存大小;3.使用场景不同:结构体用于存储一组关联的不同类型数据;联合体用于节省内存、数据类型转换(嵌入式位域解析常用)。五、预处理与编译原理1、C语言程序编译的四个阶段答:完整编译流程分为四步,求职笔试高频考点:1.预处理:处理#define宏替换、#include头文件包含、#ifdef条件编译,删除注释、展开代码,生成.i文件;2.编译:对预处理后的代码进行语法、语义检查,翻译成汇编代码,生成.s汇编文件;3.汇编:将汇编指令转为机器码,生成.o目标文件(二进制文件,不可运行);4.链接:合并多个目标文件、库文件,解析符号地址,分配虚拟内存,生成可执行文件。2、头文件重复包含的问题及解决方法答:多个源文件同时包含同一个头文件,会导致函数、变量重复定义,编译报错。两种标准解决方式:1.条件编译防护(通用、跨平台):#ifndefHEAD_NAME#defineHEAD_NAME//头文件核心内容#endif2.编译器指令:#pragmaonce(简洁,部分老旧编译器不支持)3、宏函数和普通函数的区别答:1.处理阶段:宏函数预处理阶段文本替换,普通函数编译阶段处理;2.参数检查:宏函数无类型检查,易出错;普通函数有严格参数校验;3.运行效率:宏函数无函数调用开销,执行快;普通函数有压栈、跳转、出栈开销;4.代码体积:宏函数每次调用都会展开代码,代码冗余、体积大;普通函数仅一份代码,调用跳转执行;5.递归支持:宏函数不支持递归,普通函数支持递归调用。六、高频易错编程坑题1、全局变量和局部变量的初始化默认值答:1.全局变量、static静态变量:未手动初始化时,系统默认自动初始化为0;2.普通局部变量:未初始化时,默认是随机脏数据,不会自动清零,直接使用会导致数据异常。2、数组名的两大核心特性答:1.多数场景下,数组名等价于数组首元素的地址;2.两个特殊场景数组名不做地址转换:sizeof(数组名)获取整个数组的字节大小;&数组名获取数组整体的地址。3、strlen和sizeof的区别(必考)答:1.sizeof:是运算符,编译阶段计算,获取变量、数组、数据类型占用的总字节数,包含结束符\0;2.strlen:是库函数,运行阶段计算,统计字符串中有效字符个数,不包含\0,遇到\0立即停止统计;核心区别:sizeof统计内存大小,strlen统计有效字符长度。4、return和exit的区别答:1.return:是函数返回语句,仅退出当前函数,返回函数执行结果,不会终止程序;main函数中return0代表正常退出程序;2.exit():是系统库函数,直接终止整个程序,无论在哪个函数调用,都会结束进程,exit(0)正常退出,exit(-1)异常退出。七、实操编程面试题(带完整代码答案)1、实现字符串反转函数完整代码:c

#include<stdio.h>

#include<string.h>

voidstr_reverse(char*str)

{

if(str==NULL)return;//空指针校验

intlen=strlen(str);

inti=0,j=len-1;

//首尾交换字符

while(i<j)

{

chartemp=str[i];

str[i]=str[j];

str[j]=temp;

i++;

j--;

}

}

intmain()

{

charbuf[]="helloc";

str_reverse(buf);

printf("反转结果:%s\n",buf);

return0;

}2、实现冒泡排序完整代码:c

#include<stdio.h>

voidbubble_sort(intarr[],intn)

{

inti,j;

//外层控制排序轮数

for(i=0;i<n-1;i++)

{

//内层相邻元素比较交换

for(j=0;j<n-1-i;j++)

{

if(arr[j]>arr[j+1])

{

inttemp=arr[j];

arr[j]=arr[j+1];

arr[j+1]=temp;

}

}

}

}

intmain()

{

intarr[]={9,5,2,7,1,3};

intlen=sizeof(arr)/sizeof(arr[0]);

bubble_sort(arr,len);

for(inti=0;i<len;i++)

{

printf("%d",arr[i]);

}

return0;

}3、写一个判断素数的函数c

#include<stdio.h>

#include<math.h>

//返回1是素数,0不是

intis_prime(i

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论