面试题(C语言)知识总结

本文总结了C语言面试中常见的知识点,包括结构体的字节对齐、共用体、枚举、变量问题以及函数的相关知识。讲解了结构体的柔性数组、C++中struct与C的区别、共用体的内存对齐、枚举的使用规则,以及局部变量与全局变量的关系。还讨论了堆栈的区别、程序编译过程,并提及了动态内存管理、三目运算符的使用限制和中断服务子程序(ISR)的设计注意事项。

http://emb.hqyj.com/jobs/

1 结构体

结构体的字节对齐

struct A
{
	char  a;
	int   b;
	short c;
};

首先计算每个成员变量的对齐方式:

  • a:1字节
  • b:4字节
  • c:2字节

所以最大字节对齐为MAX(1,4,2)= 4,所以整个机构体就是4字节对齐。

前一个结构体成员分配空间后,然后对齐(对齐方式 = 下一个结构体成员的对齐方式),如:a要满足b的4字节对齐,所以要空3个字节。

最后一个成员要满足整个结构体的对齐方式,所以成员c后面要空2字节。

结构体的柔性数组

struct A
{
	char  a;
	int   b;
	short c;
	char  d[0];//柔性数组
};

c++的struct  和  c的struct区别

1.c++中,class和struct的区别:

  • 成员访问权限->class的成员访问权限为private,而struct的成员访问权限为public
  • 默认的继承方式->class的默认继承方式为private,而struct的默认继承方式为public

2.struct在C和C++之间的区别

  • c中,struct是用户自定义数据类型,而c++中,struct是抽象数据类型,支持成员定义函数;
  • c中的struct是没有权限设置的,但是在c++中,给strcut添加了权限设置,增加了访问权限;
  • c中的struct只是变量的聚合体,可以封装数据,但是不可以隐藏,不可以定义函数成员;但是C++中的struct可以定义函数成员

下面结构体大小

struct A{
    char a;
    short b;
    char c;
    int d;
};
class A g;
cout<<sizeof(g);  //12

 

2 共用体

共用体也存在字节对齐。

 

3 枚举

只能给枚举变量  赋  枚举值。

声明枚举变量三种方法
1、先声明枚举类型后定义枚举类型变量

enum WeekdayType  
{  
    sun,mou,tue,wed,thu,fri,sat  
};  
enum WeekdayType today,yesterday,tomorrow;

2、声明枚举类型的同时定义枚举类型变量

enum WeekdayType  
{  
    sun,mou,tue,wed,thu,fri,sat   
}today,yesterday,tomorrow;

3、直接定义枚举类型变量

enum  
{  
    sun,mou,tue,wed,thu,fri,sat  
}today,yesterday,tomorrow;

c语言中只有enum可以实现真正的常量,而const只是限制符。


4 变量问题

局部变量能否和全局变量重名?  

 答:能,局部会屏蔽全局。要用全局变量,需要使用如"::A" ;局部变量可以与全局变量同名,在函数内引用这个变量时,会用到同名的局部变量,而不会用到全局变量。对于有些编译器而言,在同一个函数内可以定义多个同名的局部变量,比如在两个循环体内都定义一个同名的局部变量,而那个局部变量的作用域就在那个循环体内。

如何引用一个已经定义过的全局变量?   

答:extern  可以用引用头文件的方式,也可以用extern关键字,如果用引用头文件方式来引用某个在头文件中声明的全局变理,假定你将那个编写错了,那么在编译期间会报错,如果你用extern方式引用时,假定你犯了同样的错误,那么在编译期间不会报错,而在连接期间报错。

全局变量可不可以定义在可被多个.C文件包含的头文件中?为什么?   

答:可以,在不同的C文件中以static形式来声明同名全局变量。

可以在不同的C文件中extern声明同名的全局变量,前提是其中只能有一个C文件中对此变量赋初值,此时连接不会出错.  

 

5 函数

C语言源程序的基本单位是:函数。

 

 

 

 

 

 

 

杂项===============================

堆和栈的区别

堆栈空间分配

栈(操作系统):由操作系统自动分配释放 ,存放函数的参数值局部变量的值等。其操作方式类似于数据结构中的栈。

堆(操作系统): 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收,分配方式倒是类似于链表

生长方向:对于堆来讲,生长方向是向上的,也就是向着内存地址增加的方向;对于栈来讲,它的生长方向是向下的,是向着内存地址减小的方向增长。

①栈使用的是一级缓存, 他们通常都是被调用时处于存储空间中,调用完毕立即释放。

②堆则是存放在二级缓存中,生命周期由虚拟机的垃圾回收算法来决定(并不是一旦成为孤儿对象就能被回收)。所以调用这些对象的速度要相对来得低一些。

栈:是桶型结构。堆:是树型结构

 

堆栈:什么是堆栈?又该怎么理解呢?

注意:其实堆栈本身就是栈,只是换了个抽象的名字。

 

程序编译的过程?

主要经过四个过程:预处理、编译、汇编和链接

 

1). 使用的时候要记得指针的长度.
2). malloc的时候得确定在那里free.
3). 对指针赋值的时候应该注意被赋值指针需要不需要释放.
4). 动态分配内存的指针最好不要再次赋值.
5). 在C++中应该优先考虑使用智能指针.

i++和++i的区别是什么?

int main()
{
    int i = 1;
    printf("%d,%d\n", ++i, ++i);    //3,3
    printf("%d,%d\n", ++i, i++);    //5,3
    printf("%d,%d\n", i++, i++);    //6,5
    printf("%d,%d\n", i++, ++i);    //8,9
    system("pause");
    return 0;
}

i++是先传参,再计算。

++i是先让printf的计算完后,再传参。

 

 三目运算符

在C中三目运算符(? :)的结果仅仅可以作为右值,比如如下的做法在C编译器下是会报错的,但是C++中却是可以是通过的。这个进步就是通过引用来实现的,因为下面的三目运算符的返回结果是一个引用,然后对引用进行赋值是允许的。

int main(void)
{
        int a = 8;
        int b = 6;
        (a>b ? a : b) = 88;
        cout<<a; //output 88
    return 0;
}

下面的代码就使用了__interrupt关键字去定义了一个中断服务子程序(ISR),请评论一下这段代码的错误。

__interrupt double compute_area (double radius)
{
    double area = PI * radius * radius;
    printf(" Area = %f", area);
    return area;
}

1). ISR 不能返回一个值。如果你不懂这个,那么你不会被雇用的。

2). ISR 不能传递参数。如果你没有看到这一点,你被雇用的机会等同第一项。

3). 在许多的处理器/编译器中,浮点一般都是不可重入的。有些处理器/编译器需要让额处的寄存器入栈,有些处理器/编译器就是不允许在ISR中做浮点运算。此外,ISR应该是短而有效率的,在ISR中做浮点运算是不明智的。

4). 与第三点一脉相承,printf()经常有重入和性能上的问题。

如果你丢掉了第三和第四点,我不会太为难你的。不用说,如果你能得到后两点,那么你的被雇用前景越来越光明了。

不能传参数 不能有返回值 不能有打印语句 不应该使用浮点运算

堆内存碎片产生原因,及处理方法

内存碎片分为:内部碎片和外部碎片。
内部碎片

  • 内部碎片就是已经被分配出去(能明确指出属于哪个进程)却不能被利用的内存空间;
  • 内部碎片是处于区域内部或页面内部的存储块。占有这些区域或页面的进程并不使用这个存储块。而在进程占有这块存储块时,系统无法利用它。直到进程释放它,或进程结束时,系统才有可能利用这个存储块。(有点占着茅坑不拉屎的意思)

外部碎片

  • 内存块太小了无法分配给申请内存空间的新进程的内存空闲区域。
  • 由于它们的地址不连续或其他原因,使得系统无法满足当前申请。

主要有两点,一是申请的内存地址是跟页或段有关系,必须是倍数关系,一般是4,8,16的倍数。二是申请的内存空间必须是连续的,无法跨地址。所以就会产生碎片。
处理办法,没有绝对的好办法。

  1. 结构体的对齐;
  2. 用完内存及时释放;
  3. 或者是使用内存池,就可以按自己需要来管理内存,比如对于申请小片的内存就不要使用新的内存快,而是使用之前用过已经释放的,这样之后如果要申请大空间那就可以申请也会减少碎片。

 

参考:

https://blog.youkuaiyun.com/kuweicai/article/details/82779648

 

重要:

https://www.docin.com/p-939418421-f3.html

https://www.docin.com/p-947819291-f7.html

乐播投屏是一款简单好用、功能强大的专业投屏软件,支持手机投屏电视、手机投电脑、电脑投电视等多种投屏方式。 多端兼容与跨网投屏:支持手机、平板、电脑等多种设备之间的自由组合投屏,且无需连接 WiFi,通过跨屏技术打破网络限制,扫一扫即可投屏。 广泛的应用支持:支持 10000+APP 投屏,包括综合视频、网盘与浏览器、美韩剧、斗鱼、虎牙等直播平台,还能将央视、湖南卫视等各大卫视的直播内容一键投屏。 高清流畅投屏体验:腾讯独家智能音画调校技术,支持 4K 高清画质、240Hz 超高帧率,低延迟不卡顿,能为用户提供更高清、流畅的视觉享受。 会议办公功能强大:拥有全球唯一的 “超级投屏空间”,扫码即投,无需安装。支持多人共享投屏、远程协作批注,PPT、Excel、视频等文件都能流畅展示,还具备企业级安全加密,保障会议资料不泄露。 多人互动功能:支持多人投屏,邀请好友加入投屏互动,远程也可加入。同时具备一屏多显、语音互动功能,支持多人连麦,实时语音交流。 文件支持全面:支持 PPT、PDF、Word、Excel 等办公文件,以及视频、图片等多种类型文件的投屏,还支持网盘直投,无需下载和转格式。 特色功能丰富:投屏时可同步录制投屏画面,部分版本还支持通过触控屏或电视端外接鼠标反控电脑,以及在投屏过程中用画笔实时标注等功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值