1. 大小和长度竟然不是一个意思
sizeof()
和strlen()
有什么异同之处?他们对于不同参数的结果有什么不同?请试举例子说明。
1 | int main(void) { |
sizeof()是一个运算符,计算的是所占内存空间的字节数(包括最后的’\0’),strlen()是一个函数,遇到\0就会结束,返回字符串的长度,所以s的大小是16,长度是12
2. 箱子的大小和装入物品的顺序有关
test1
和test2
都含有:1个short
、1个int
、1个double
,那么sizeof(t1)
和sizeof(t2)
是否相等呢?这是为什么呢?
1 | struct test1 { |
sizeof(t1)和sizeof(t2)的大小都是16,结构体的大小存在内存对齐,test1的大小是4+2+2+8=16,test2的大小是2+2+4+8=16
结构体大小计算遵循以下原则:
1.第一个成员在与结构体变量偏移量为0的地址处.(即结构体的首地址处,即对齐到0处)
2.其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
3.结构体的总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
4.如果嵌套了结构体,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
3. 哦,又是函数
想必在高数老师的教导下大家十分熟悉函数这个概念。那么你了解计算机程序设计中的函数吗?请编写一个
func
函数,用来输出二维数组arr
中每个元素的值。
1 | /*在这里补全func函数的定义*/void func(int arr[][13]) |
1 | void func(int arr[][13]) |
4.就不能换个变量名吗?
- 请结合下面的程序,简要谈谈
传值
和传址
的区别。- 简要谈谈你对C语言中变量的生命周期的认识。
1 | int ver = 123; |
传值到函数结束,释放内存空间,并不能修改实际变量的值,转址由于传的是地址,可以通过地址修改变量的值
局部变量的生命周期是从局部变量创建到函数结束,全局变量,静态局部变量,静态全局变量的生命周期都是从程序创建到程序销毁
5. 套娃真好玩!
请说明下面的程序是如何完成求和的?
1 | unsigned sum(unsigned n) { return n ? sum(n - 1) + n : 0; } |
表达式?结果1:结果2
表达式为true返回结果1,否则返回结果2
sum(100)返回的结果是sum(99)+100=100+99+sum(98),最终到sum(2)=sum(1)+2=sum(0)+1+2=0+1+2
通过递归对1-100求和,结果是5050
6. 算不对的算术
1 | void func(void) { |
7. 指针和数组的恩怨情仇
8. 移形换位之术
下面有
a
、b
、c
三个变量和4个相似的函数。
- 你能说出使用这三个变量的值或地址作为参数分别调用这5个函数,在语法上是否正确吗?
- 请找出下面的代码中的错误。
const int
和int const
是否有区别?如果有区别,请谈谈他们的区别。const int *
和int const *
是否有区别?如果有区别,请谈谈他们的区别。
1 | int a = 1; |
在语法上是正确的
func2中n的类型是const int *是常量指针,不能通过指针改变变量的值,所以 *n+=1是错的func3中n的类型是int *const是指针常量,不能再指向其他的地址,所以n=&a是错的,func4中n的类型是const int *const既不能通过指针改变变量的值,也不能再指向其他的地址
const int和int const没有区别,const int*和int const *也没有区别
区分常量指针和指针常量的关键就在于星号的位置,我们以星号为分界线,如果const在星号的左边,则为常量指针,如果const在星号的右边则为指针常量
9. 听说翻转字母大小写不影响英文的阅读?
请编写
convert
函数用来将作为参数的字符串中的大写字母转换为小写字母,将小写字母转换为大写字母。返回转换完成得到的新字符串。
1 | char *convert(const char *s); |
1 | char* convert(const char* s); |
10. 交换礼物的方式
- 请判断下面的三种
Swap
的正误,分别分析他们的优缺点。- 你知道这里的
do {...} while(0)
的作用吗?- 你还有其他的方式实现
Swap
功能吗?
1 |
|
前两种是正确的,第三种只是传递了a,b变量的值而没有传递地址,函数结束后会释放掉a,b的内存,a,b的值并没有改变
用do{…}while(0);包裹住要操作的#define,无论你外面怎么操作,都不会影响#define的操作
还可以通过以下方式实现swap功能
1 | void swap(int* a,int* b) |
11. 据说有个东西叫参数
你知道
argc
和argv
的含义吗?请解释下面的程序。你能在不使用argc
的前提下,完成对argv
的遍历吗?
1 | int main(int argc, char *argv[]) { |
argc即arguments count表示传入main函数的参数个数
argv即arguments value/vector参数值,表示传入main函数的参数序列或指针,并且第一个参数argv[0]一定是程序的名称
1 | int main(int argc,char* argv[]) |
12. 人去楼空
这段代码有是否存在错误?谈一谈静态变量与其他变量的异同。
1 | int *func1(void) { |
静态变量只会初始化一次,可以多次赋值,在数据区进行存储
作用域:只能在函数内部使用
生命周期:从程序创建到程序销毁
func3有错误修改如下
1 | int *func3(void){ |
13. 奇怪的输出
1 | int main(void) { |
int转化为char,636c6557对应的二进制0110 0011 0110 1100 0110 0101 0101 0111最后的0101 0111=87刚好是W以此类推,输出Welcome to xiyou Linux group 2021
14. 请谈谈对从「C语言文件到可执行文件」的过程的理解
(1)预处理阶段。预处理器(cpp)根据字符#开头的命令,修改原始的C程序。
(2)编译阶段。将c语言文件从高级语言转为汇编语言。
(3)汇编阶段。将汇编语言转化为二进制语言。
(4)链接阶段。将使用的头文件与本文件链接起来。
15. (选做) 堆和栈
你了解程序中的栈和堆吗?它们在使用上有什么区别呢?请简要说明。
栈:栈由操作系统自动分配释放 ,用于存放函数的参数值、局部变量、函数返回地址、寄存器内容等。函数中定义的局部变量按照先后定义的顺序依次压入栈中(从高地址开始放),栈中存储的数据的生命周期随着函数的执行完成而结束。栈的效率比较高。
堆:由开发人员分配和释放(由malloc()函数申请,free()函数释放)
16. (选做) 多文件
一个程序在不使用任何头文件的情况下,如何使用另一个文件中的函数。
17. (选做) GNU/Linux
与文件
- 你知道如何在
GNU/Linux
下如何使用命令行创建文件与文
件夹吗?- 你知道
GNU/Linux
下的命令ls 的每一列的含义吗?- 你知道
GNU/Linux
下文件的访问时间、修改时间、创建时间如何查看吗?并简单说说他们的区别。
恭喜你做完了整套面试题,快来参加西邮Linux兴趣小组的面试吧!
西邮 Linux兴趣小组面试时间:
2021年10月25日至2021年10月31日晚8点。
听说面试来的早一点更能获得学长学姐的好感哦。我们在FZ103等你!