C语言面试题

1、关键字    

static
    ​1、函数体内的变量,这个变量只被声明一次。
​    2、在模块内的变量,只能被模块内函数使用,不能被模块外函数访问,表示本地全局变量

extern
    1、引用同一文件变量,使用在声明之前时,可以使用关键字extern,让声明在程序任意位置。
    2、引用另一个文件中的变量,extern可以引用其他文件中的全局变量,而且extern只需要指明数据类型和数据名称
    3、引用另一个文件中的函数,可以不用包含头文件引用函数。

new/delete malloc/free
​    1、new/delete是操作符,malloc/free是库函数
​    2、new/delete可以调用构造函数/析构函数,m/f 只是分配内存。

struct 和 union区别
​     1、联合体公用一块地址空间,联合体变量长度等于最长的成员的长度
​     2、联合体对不同成员赋值,会将其他成员重写。

const
​    1、定义变量为常量
​    2、修饰参数为常量
    3、修饰返回值为常量
    总结:将一个变量变为只读模式

sizeof和strlen
​    1、sizeof是运算符,strlen是函数
​    2、sizeof可以用类型、函数作为参数,strlen只能计算 char*,还必须以/0结尾
​    3、sizeof编译的时候计算,strlen是运行期计算,表示字符串长度,不是内存大小。

typedef和 define
    1、都是替对象取一个别名,增强程序的可读性
    2、typedef用来定义类型别名,不止包含内部类型还包含自定义类型,方便记忆
    3、define为预处理指令,不做正确性检查,只有带入之后才能发现 
    4、define不仅可以给类型取别名,还能定义常量、变量、编译开关。
    5、define没有作用域限制,typedef有。
    
define和const ,谁定义常量最好
    1、define只是文本替换,声明周期止于编译期,不分配内存空间,存在于代码段。const常量存在于数据段,堆栈中分配了空间。
    2、const有数据类型,编译器可以对const进行安全检查。
    3、const有保护常量不被修改的作用,提高程序的健壮性。
    总结:一般倾向于用const定义常量

2、内存
C语言五大区域:
    栈  区:    由编译器自动分配释放    存放函数形参和局部变量
    堆  区:    由程序员分配和释放        调用malloc来进行分配
    代码区:                            存放程序的二进制代码
    文字常量区:                        存放字符串、数字等常量
    全局区(静态存储区):                存放全局变量和静态变量

什么是代码段,数据段,bss段,堆,栈?
    代码段:存放程序 执行代码 的一块区域,通常是只读
    数据段:存放 已初始化的全局变量 和 已初始化为非0的静态变量
    BSS 段:未初始化的全局变量 和 未初始化的静态变量或者初始化为0的静态变量
    数据段和BSS段本质上都是静态区,存放全局变量和静态变量的
    堆:    存放进程中被动态分配的内存段。
    栈:    存放程序临时变量

堆和栈的区别
    1、申请方式。栈为操作系统自动分配/释放,堆为手动
    2、申请大小,栈空间有限,向低地址拓展的连续区域,堆是向高地址拓展的不连续区域,链表储存的空闲地址。
    3、申请效率,栈是系统自动分配,速度快,不可控。堆是由new分配,速度比较慢,容易产生内存碎片。

栈的作用
    1、储存临时(局部)变量
    2、多线程编程的基础。每个线程至少有一个栈用来存储临时变量和返回的值。

为什么不能共用一个栈:
    1、内核栈大小有限,用户程序调用次数可能很多。
    2、用户栈空间不能提供相应保护措施    
    
为什么堆的空间是不连续的?    
    1、堆包含一个链表来维护已用和空闲的内存块。
    2、分配的空间在逻辑地址(虚拟地址)上是连续的,但在物理地址上是不连续的

什么是用户栈和内核栈?
    内核栈 :内存中属于操作系统空间的一块区域。
    作用:
        1、保存中断现场
        2、保存调用的参数、返回值、函数局部变量

    用户栈:用户进程空间的一块区域,
    作用:
        用于保存用户空间子程序间调用的参数,返回值以及局部变量。    
    
C语言内存分配方式
    1、静态储存区分配
    2、栈上分配
    3、堆上分配    
    
内存泄漏
    申请了没有释放,由程序申请的一块内存,没有任何指针指向它,这个内存就泄露了。

避免内存泄漏方法
    1、分配的内存以链表管理,使用完毕后从链表删除,程序结束的时候检查链表
    2、良好的编程习惯,在设计内存的程序段,检验出内存泄漏,使用了内存分配的函数,使用完毕后将使用的相应函数释放掉

3、指针
数组指针和指针数组
    数组指针,本质是一个指针,指向一个数组
    指针数组,本质是一个数组,里面装的是指针。

函数指针和指针函数
    函数指针,本身是一个指针,指向一个函数的地址
    指针函数,本身是一个函数,返回值是指针。

指针和数组名区别
    指针保存的是地址,数组保存的是数据,只有一个数组名表示第一个元素的地址
    指针间接访问,数组直接下标或者偏移量
    sizeof 有区别,指针为指针大小,数组为全体数据大小

指针常量,常量指针、指向常量的指针*************
    int *const p 指向地址不变,地址值可变
    int const *p 指向地址可变,地址值不能边
    const int * const p 都不能变

指针与引用区别
    都是地址,指针是地址,应用是别名
    引用本质是指针常量,对象不变,对象的值可变
    ++不同,指针是地址自增,引用是对象自增
    指针需要解引用
    指针可为空,引用不行
    sizeof不同 一个是指针大小一个是对象大小

野指针
    指向不可用内存的指针,指针被创建时如果没有初始化就是野指针
    指针被free、delete时没有指向NULL就是野指针
    指针超出了变量的地址范围

4、预处理
预处理器标识#error的目的是什么?
    遇到#error就会生成一个编译错误提示信息,并停止编译

#include"" 和 include<>区别
    <>号先搜索标准库搜索系统文件比较快,“”号先搜索工作路径搜索自定义文件比较快

头文件作用
    通过文件调用库功能,源码保护
    头文件加强类型安全检查,编译器报错

5、 变量
全局变量和静态变量
    全局变量作用域为程序块,局部变量为当前函数
    全局变量储存在静态区,后者为栈
    全局变量生命周期为主函数,局部变量生命周期在局部函数中,甚至循环体内

重载与覆盖
1、覆盖是子类和父类的关系,垂直关系,重载是一个类之间的关系,水平关系

2、覆盖一对一,重载多个方法

3、覆盖由对象类型决定,重载根据调用的参数表决定

C语言函数调用方法
    使用栈来支持函数调用操作,栈被用来传递参数,返回值,局部变量等。
    函数调用主要操作栈帧结构

select函数
int select(int maxfdp,fd_set *readfds,fd_set *writefds,fd_set *errorfds,struct timeval *timeout);
1
fork wait exec函数
1、附近产生的子进程使用fork拷贝出一个父进程的副本

数组的下标可以为负数吗?
可以,数组下标指地址偏移量,根据偏移量能定位得到目标地址。

inline函数和宏定义的区别
1、内联函数在编译时展开,而宏在预编译时展开。

2、在编译的时候,内联函数直接被嵌入到目标代码中去,而宏只是一个简单的文本替换。

3、内联函数可以进行诸如类型安全检查、语句是否正确等编译功能,宏不具有这样的功能。

4、宏不是函数,而inline是函数。

5、宏在定义时要小心处理宏参数,一般用括号括起来,否则容易出现二义性。而内联函数不会出现二义性。

6、inline可以不展开,宏一定要展开。因为inline指示对编译器来说,只是一个建议,编译器可以选择忽略该建议,不对该函数进行展开。

7、宏定义在形式上类似于一个函数,但在使用它时,仅仅只是做预处理器符号表中的简单替换,因此它不能进行参数有效性的检测,也就不能享受C++编译器严格类型检查的好处,另外它的返回值也不能被强制转换为可转换的合适的类型,这样,它的使用就存在着一系列的隐患和局限性。

宏和函数的优缺点
1、函数调用时,先求出实参表达式的值,然后带入形参。而使用带参数的函数只是进行简单的字符替换

2、函数调用实在程序运行时处理的,分配的临时的内存单元;而宏展开则是在编译时进行的,在展开时不分配i内存单元,不进行值的传递,也没有"返回值的概念"

3、函数实参形参都要定义类型,二者要求一致 ,宏不存在类型问题,宏没有类型,宏的参数只是一个符号代表,展开时代入指定的字符就行,宏定义时字串可以是任意内心的数据

4、函数只可以得到一个返回值,宏可以设法得到多个

5、使用宏次数多时,展开后源程序长,每次展开都使程序增长,而函数调用不使源程序变长。

6、宏的替换不占用时间,只占用编译时间,函数调用占用运行时间。

简单回答:宏由编译计算,增加编译时间,函数运行的时候计算,增加运行时间;函数的返回值入口参数有数据类型,宏只是简单的符号加减。

strcpy()和memcpy()的区别
1、复制的内容不同。strcpy只能复制字符串,而memcpy可以复制任意内容,例如字符数组、整型、结构体、类等。
2、复制的方法不同。strcpy不需要指定长度,它遇到被复制字符的串结束符"\0"才结束,所以容易溢出。memcpy则是根据其第3个参数决定复制的长度。
3、用途不同。通常在复制字符串时用strcpy,而需要复制其他类型数据时则一般用memcpy

\r 和 \n 的作用:

\r是表示回车(CR),ascii码值为13
注意回车和换行是不一样的
c语言编程时(windows系统)
\r 就是return 回到本行行首这就会把这一行以前的输出覆盖掉,但不会移动到下一行

\n表示将光标移动到下一行,但不会移动到行首。
单独一个\r或\n都不是一般意义上的回车+换行,\r\n放在一起才是。
通常在写程序的时候只要一个\n就可以了,这是因为编译器会自动将\n替换成\r\n。

1.7 容器与算法
map与set区别和底层实现
1、底层实现都是红黑树

2、map是键值对,关键字起到索引作用,值表示与索引相关联的数据,set是关键字的集合并且每个元素只包含一个关键字。

3、set迭代器是const不能修改元素值,map允许修改value不能修改key

4、map支持下标操作,set不支持,map可以用key作为下标,set用find


引用与指针的区别
1、引用必须被初始化,指针不必。

2、引用初始化以后不能被改变,指针可以改变所指的对象。

3、不存在指向空值的引用,但是存在指向空值的指针。

静态成员函数与非静态成员函数的区别
    前者没有 this 指针,后者有 this 指针。
    静态成员函数只要用来访问静态数据成员,而不访问非静态成员

1.9 面对对象
面向对象和面向过程有什么区别?
面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了;面向对象是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个事物在整个解决问题的步骤中的行为。

1、面对对象以对象为中心,面向过程以过程为中心

2、面对对象把代码封装成一个整体,其他对象不能直接修改其数据。面向过程直接使用程序来处理数据,各模块存在控制与被控制的关系。

3、面对对象是将问题分为不同的对象,给予对象赋予属性和行为。面对过程则是将事件分为不同的步骤,按照步骤完成编程。

面对对象的基本特点
1、封装: 把过程和数据封装起来,只有定义的接口才能调用

2、继承:子类继承父类的功能

3、多态:不同的对象对从父类继承的同一动作做出不同的反应,

4、抽象:不打算了解问题全部,只关注当前目标。过程抽象和数据抽象。过程抽象是指任何操作都被当成实体看待,不在乎它是不是由其他子函数完成。

1.11数据结构
链表和数组的区别
数组在内存中栈上按顺序存储的,而链表是在堆上随机存储的。
要访问数组中的元素可以按下标索引来访问,速度比较快,如果对他进行插入操作的话,就得移动很多元素,所以对数组进行插入操作效率很低. 由于连表是随机存储的,链表在插入,删除操作上有很高的效率(相对数组)
如果要访问链表中的某个元素的话,那就得从链表的头逐个遍历,直到找到所需要的元素为止,所以链表的随机访问的效率就比数组要低 。


 

  • 23
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值