西邮Linux兴趣小组2022纳新面试题题解
感谢 Zhilu 重新录入题目原件。好人一生平安。
- 本题目只作为
Xiyou Linux兴趣小组
2022纳新面试的有限参考。- 为节省版面,本试题的程序源码省去了
#include
指令。- 本试题中的程序源码仅用于考察C语言基础,不应当作为C语言「代码风格」的范例。
- 题目难度随机排列。
所有题目编译并运行于x86_64 GNU/Linux
环境。学长寄语:
长期以来,西邮Linux兴趣小组的面试题以难度之高名扬西邮校内。我们作为出题人也清楚的知道这份试题略有难度。请别担心。若有同学能完成一半的题目,就已经十分优秀。 其次,相比于题目的答案,我们对你的思路和过程更感兴趣,或许你的答案略有瑕疵,但你正确的思路和对知识的理解足以为你赢得绝大多数的分数。最后,做题的过程也是学习和成长的过程,相信本试题对你更加熟悉的掌握C语言的一定有所帮助。祝你好运。我们FZ103见!Copyright © 2022 西邮Linux兴趣小组, All Rights Reserved.
本试题使用采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。
0. 我的计算器坏了?!
2^10=1024
对应于十进制的4位,那么2^10000
对应于十进制的多少位呢?
计算一个数十进制的位数,我们以10为底求该数的对数,再取整+1,同理计算一个数对应的二进制的位数,以2为底求该数的对数再+1,[10000*log2]+1大概是3011位
1. printf还能这么玩?
尝试着解释程序的输出。
int main(void) {
if ((3 + 2 < 2) > (3 + 2 > 2))
printf("Welcome to Xiyou Linux Group\n");
else
printf("%d\n", printf("Xiyou Linux Group - 2%d", printf("")));
}
printf返回打印字符的个数
所以输出结果是Xiyou Linux Group -2022
2. 你好你好你好呀!
- 程序的输出有点奇怪,请尝试解释一下程序的输出吧。
- 请谈谈对
sizeof()
及strlen()
的理解吧。
int main(void)
{
char p0[] = "Hello,Linux";
char *p1 = "Hello,Linux";
char p2[11] = "Hello,Linux";
printf("p0==p1: %d, strcmp(p0,p2): %d\n", p0 == p1, strcmp(p0, p2));
printf("sizeof(p0): %zu, sizeof(p1): %zu, sizeof(*p2): %zu \n",
sizeof(p0), sizeof(p1), sizeof(*p2));
printf("strlen(p0): %zu, strlen(p1): %zu\n", strlen(p0), strlen(p1));
}
sizeof()
是基本的运算符 得到目标所占内存的大小
strlen()
是包含在<string.h>
库里的库函数 针对字符串 返回字符传的长度(字符个数)
- answer:>
sizeof(*p2)是第一个字符的首地址,大小为1,strlen计算的是长度所以大小都为11
3. 换个变量名不行吗?
请结合本题,分别谈谈你对C语言中「全局变量」和「局部变量」的「生命周期」理解。
int a = 3;
void test()
{
int a = 1;
a += 1;
{
int a = a + 1;
printf("a = %d\n", a);
}
printf("a = %d\n", a);
}
int main(void)
{
test();
printf("a= %d\n", a);
}
三次打印
- 打印
随机值
因为在其作用域中 a变量仅声明 未进行定义 - 打印
a = 2
此处的a是test函数中定义的a - 打印
a= 3
此处的a是全局变量a
4. 内存对不齐
union
与struct
各有什么特点呢,你了解他们的内存分配模式吗。
typedef union
{
long l;
int i[5];
char c;
} UNION;
typedef struct
{
int like;
UNION coin;
double collect;
} STRUCT;
int main(void)
{
printf("sizeof (UNION) = %zu \n", sizeof(UNION));
printf("sizeof (STRUCT) = %zu \n", sizeof(STRUCT));
}
union共用一块内存空间,union大小为24,strict大小为40
关于内存对其>
结构体内存对齐: >https://www.zhihu.com/question/27862634
联合体相关知识点: >https://blog.csdn.net/m0_57180439/article/details/120417270?ops_request_misc=&request_id=&biz_id=102&utm_term=%E8%81%94%E5%90%88%E4%BD%93%E7%9B%B8%E5%85%B3%E7%9F%A5%E8%AF%86%E7%82%B9&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-1-120417270.142^v65^control,201^v3^control_1,213^v2^t3_esquery_v1&spm=1018.2226.3001.4187
- 答案: >
-
输出 sizeof(UNION) = 24 sizeof(STRUCT) = 40
5. Bitwise
- 请使用纸笔推导出程序的输出结果。
- 请谈谈你对位运算的理解。
int main(void)
{
unsigned char a = 4 | 7;
a <<= 3;
unsigned char b = 5 & 7;
b >>= 3;
unsigned char c = 6 ^ 7;
c = ~c;
unsigned short d = (a ^ c) << 3;
signed char e = -63;
e <<= 2;
printf("a: %d, b: %d, c: %d, d: %d \n", a, b, c, (char)d);
printf("e: %#x \n", e);
}
- |是或,两个位都为0,结果才为0,4是0100,7是0111,4|7结果是0111=7,左移三次7*2=14,14 *2=28,28 *2=56
- 所以a=56
- &是与,两个位都为1时结果才为1,5是0101,7是0111,5&7结果是0101=5,5右移三次5/2=2,2/2=1,1/2=0
- 所以b=0
- ^是异或,两个位相同为0,相异为1,6是0110,7是0111,结果是0001,~是取反,结果是1111 1110,
- 所以c=254
- a是0011 1000,c是1111 1110,a^c的结果是0000 0000 1100 0110左移3位是0000 0110 0011 0000转换为char是0011 0000=48,e是1011 1111补码是1100 0001左移2位是0000 0100=4,
- 所以e=4
位运算:>https://www.runoob.com/w3cnote/bit-operation.html
整形提升和算数转换:> https://blog.csdn.net/iqrmshrt/article/details/124923765
数据储存(源码反码补码):> https://zhuanlan.zhihu.com/p/99082236
- 答案: >
输出 a: 56,b: 0,c: 255,d: 56 e: 0x4
6. 英译汉
请说说下面数据类型的含义,谈谈
const
的作用。
char *const p
。char const *p
。const char *p
。
- 关于const
int x = 1,y = 2; // a 与 b 都是整型常量,值都不能修改,只读变量 const int a = 0; int const b = 0; const int *px = &a;// px 不是常量 *px 是常量 int * const py = &y;// py 是常量 *py 不是常量 const int * const pp = &x;// pp 与 *pp 都是常量 /* 1、如果 const 在 * 前面,修饰的是数据类型,指向的内容不 能修改 2、如果 const 在 * 后面,修饰的是变量,变量是常量 3、如果 const 在 * 前后都有,都是常量 */
7. 汉译英
请用变量
p
给出下面的定义:
- 含有10个指向
int
的指针的数组。- 指向含有10个
int
数组的指针。- 含有3个「指向函数的指针」的数组,被指向的函数有1个
int
参数并返回int
。
函数指针的声明及相关知识点;https://blog.csdn.net/Topdandan/article/details/79698811
- 答案: >
int *p [10]; int (*p)[10]; int (*p[3])(int);
8. 混乱中建立秩序
你对排序算法了解多少呢?
请谈谈你所了解的排序算法的思想、稳定性、时间复杂度、空间复杂度。提示:动动你的小手敲出来更好哦~
就… 算法 (网上纸己搜)
9. 手脑并用
请实现ConvertAndMerge函数:
拼接输入的两个字符串,并翻转拼接后得到的新字符串中所有字母的大小写。提示:你需要为新字符串分配空间。
char* convertAndMerge(/*补全签名*/);
int main(void) {
char words[2][20] = {
"Welcome to Xiyou ", "Linux Group 2022"};
printf("%s\n", words[0]);
printf("%s\n", words[1]);
char *str = convertAndMerge(words);
printf("str = %s\n", str);
free(str);
}
- 动态规划内存:>https://blog.csdn.net/m0_62391199/article/details/125840627?ops_request_misc=&request_id=&biz_id=102&utm_term=%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92%E5%86%85%E5%AD%98&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-1-125840627.142^v65^control,201^v3^control_1,213^v2^t3_esquery_v1&spm=1018.2226.3001.4187
- answer:>
char* convertAndMerge(char word[][20]); int main(void) { char words[2][20] = { "Welcome to Xiyou ", "Linux Group 2022"}; printf("%s\n", words[0]); printf("%s\n", words[1]); char* str = convertAndMerge(words); printf("str = %s\n", str); free(str); } char* convertAndMerge(char word[][20]) { char *a = (char *)malloc(sizeof(char)*20*2); sprintf(a,"%s%s",word[0],word[1]); return a ; }
10. 给你我的指针,访问我的心声
程序的输出有点奇怪,请尝试解释一下程序的输出吧。
int main(int argc, char **argv) {
int arr[5][5];
int a = 0;
for (int i = 0; i < 5; i++) {
int *temp = *(arr + i);
for (; temp < arr[5]; temp++) *temp = a++;
}
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
printf("%d\t", arr[i][j]);
}
}
}
这里是输出:>
0 1 2 3 4
25 26 27 28 29
45 46 47 48 49
60 61 62 63 64
70 71 72 73 74
开始变得有意思了 为什么这么输出呢;
因为 二位数组地址的存放是连续的
- 未开始时
arr[][]内部是
[0] 0 0 0 0//temp位置
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
- 所以 当外层循环 i=0 跑完时
// i = 0 时
0 1 2 3 4
5 6 7 8 9
10 11 12 13 14
15 16 17 18 19
20 21 22 23 24
[*]//当我的指针走到[*]时 出循环
i++;
然后 temp = *(arr+i)
进入循环 继续++ 赋值
0 1 2 3 4
[5] 6 7 8 9 //[temp]位置 即开始++赋值的位置
10 11 12 13 14
15 16 17 18 19
20 21 22 23 24
0 1 2 3 4
25 26 27 28 29
30 31 32 33 34
35 36 37 38 39
40 41 42 43 44
[*]//结束
然后同理
0 1 2 3 4
25 26 27 28 29
[30] 31 32 33 34 //启始位置下移
35 36 37 38 39
40 41 42 43 44
循环++赋值 直到temp位置 和 arr[5]
重合
拿到答案:>
0 1 2 3 4
25 26 27 28 29
45 46 47 48 49
60 61 62 63 64
70 71 72 73 74
11. 奇怪的参数
你了解argc和argv吗?
直接运行程序argc的值为什么是1?
程序会出现死循环吗?
#include <stdio.h>
int main(int argc, char **argv)
{
printf("argc = %d\n", argc);
while (1)
{
argc++;
if (argc < 0)
{
printf("%s\n", (char *)argv[0]);
break;
}
}
}
- argc即arguments count表示传入main函数的参数个数
- argv即arguments value/vector参数值,表示传入main函数的参数序列或指针,并且第一个参数argv[0]一定是程序的名称
- argc为1,即该程序的路径名argc为int类型,不断+1,会数值溢出从而argc<0,break跳出循环
argc和argv:> https://cloud.tencent.com/developer/article/1669043
变量溢出:> https://blog.csdn.net/a26013/article/details/121177294
这里 argc和argv的用处不大 这二者在系统编程中运用较多\
12. 奇怪的字符
程序的输出有点奇怪,请尝试解释一下程序的输出吧。
int main(int argc, char **argv)
{
int data1[2][3] = {
{
0x636c6557, 0x20656d6f, 0x58206f74},
// u o y i n i L \0
{
0x756f7969, 0x6e694c20, 0x00000000}};
int data2[] = {
0x47207875, 0x70756f72, 0x32303220, 0x00000a32};
char *a = (char *)data1;
char *b = (char *)data2;
char buf[1024];
strcpy(buf, a);
strcat(buf, b);
printf("%s \n", buf);
if(*buf='W') printf("LE");
else printf("BE");
}
此程序将十六进制的内存编码进行分割 将int长度的编码分割成char长度进行输出
要注意的是 计算机是小端存储 在切割时 先打印的是0x57
也就是 W
大小端的储存格式;> https://blog.51cto.com/iteyer/3240050
ascll碼转换;
- 输出:>
Welcome to Xiyou Linux Group 2022
13. 小试宏刀
- 请谈谈你对
#define
的理解。- 请尝试着解释程序的输出。
#include <stdio.h>
#define SWAP(a, b, t) t = a; a = b; b = t
#define SQUARE(a) a *a
#define SWAPWHEN(a, b, t, cond) if (cond) SWAP(a, b, t)
int main() {
int tmp;
int x = 1;
int y = 2;
int z = 3;
int w = 3;
SWAP(x, y, tmp);
printf("x = %d, y = %d, tmp = %d\n", x, y, tmp);
if (x > y) SWAP(x, y, tmp);
printf("x = %d, y = %d, tmp = %d\n", x, y, tmp);
SWAPWHEN(x, y, tmp, SQUARE(1 + 2 + z++ + ++w) == 100);
printf("x = %d, y = %d,tmp=%d\n", x, y, tmp);
printf("z = %d, w = %d ,tmp = %d\n", z, w, tmp);
}
考察的是宏的相关问题
简而言之 宏定义会在预编译阶段被编译器插入到源代码中;
下面是预编译后的内容
int main()
{
int tmp;
int x = 1;
int y = 2;
int z = 3;
int w = 3;
tmp = x; x = y; y = tmp;
printf("x = %d y = %d tmp = %d\n", x, y, tmp);
if (x > y)
tmp = x; x = y; y = tmp;
printf("x = %d y = %d tmp = %d\n", x, y, tmp);
if (1 + 2 + z++ + ++w *1 + 2 + z++ + ++w == 100) tmp = x; x = y; y = tmp;
printf("x = %d, y = %d\n", x, y);
printf("x = %d y = %d tmp = %d\n", z, w, tmp);
}
- 输出:>
x = 2 y = 1 tmp = 1 x = 1 y = 2 tmp = 2 x = 2, y = 2 x = 5 y = 5 tmp = 2
14. GNU/Linux命令 (选做)
你知道以下命令的含义和用法吗:
注:
嘿!你或许对Linux命令不是很熟悉,甚至你没听说过Linux。
但别担心,这是选做题,不会对你的面试产生很大的影响!
了解Linux是加分项,但不了解也不扣分哦!
ls
rm
whoami
请问你还了解哪些GNU/Linux的命令呢。
关于Linux常用的指令:> https://cloud.tencent.com/developer/article/1540697
恭喜你做到这里!你的坚持战胜了绝大多数看到这份试题的同学。
或许你自己对答题的表现不满意,但别担心,请自信一点呐。
坚持到达这里已经证明了你的优秀。
还在等什么,快带上你的笔记本电脑,来FZ103面试吧!
西邮Linux兴趣小组2021纳新面试题题解
感谢 Zhilu 重新录入题目原件。好人一生平安。
注:
- 本题目仅作
西邮Linux兴趣小组
2021纳新面试题的有限参考。- 为节省版面本试题的程序源码中省略了
#include
指令。- 本试题中的程序源码仅用于考察C语言基础,不应当作为C语言代码风格的范例。
- 题目难度与序号无关。
- 所有题目均假设编译并运行
x86_64 GNU/Linux
环境。Copyright © 2021 西邮Linux兴趣小组, All Rights Reserved.
本试题使用采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。
1. 大小和长度竟然不是一个意思
sizeof()
和strlen()
有什么异同之处?他们对于不同参数的结果有什么不同?请试举例子说明。
int main(void) {
char s[] = "I love Linux\0\0\0";
int a = sizeof(s);
int b = strlen(s);
printf("%d %d\n", a, b);
}
同 22-1
2. 箱子的大小和装入物品的顺序有关
test1
和test2
都含有:1个short
、1个int
、1个double
,那么sizeof(t1)
和sizeof(t2)
是否相等呢?这是为什么呢?
struct test1 {
int a;
short b;
double c;
};
struct test2 {
short b;
int a;
double c;
};
int main(void) {
struct test1 t1;
struct test2 t2;
printf("sizeof (t1) : %d\n", sizeof(t1));
printf("sizeof(t2): %d\n", sizeof(t2));
}
同 22-4
3. 哦,又是函数
想必在高数老师的教导下大家十分熟悉函数这个概念。那么你了解计算机程序设计中的函数吗?请编写一个
func
函数,用来输出二维数组arr
中每个元素的值。
/*在这里补全func函数的定义*/
int main(void) {
int arr[10][13];
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 13; j++) {
arr[i][j] = rand();
}
}
func(arr);
}
- answer:>
void func(int n,char arr[][13]) { int i; for(i=0;i<n;i++) { printf("%s\n",i,arr[i]); } }//下面两个的函数体内部结构和这个一样,后面的不展开写了
4.就不能换个变量名吗?
- 请结合下面的程序,简要谈谈
传值
和传址
的区别。- 简要谈谈你对C语言中变量的生命周期的认识。
int ver = 123;
void func1(int ver) {
ver++;
printf("ver = %d\n", ver);
}
void func2(int *pr) {
*pr = 1234;
printf("*pr = %d\n", *pr);
pr = 5678;
printf("ver = %d\n", ver);
}
int main() {
int a = 0;
int ver = 1025;
for (int a = 3; a < 4; a++) {
static int a = 5;
printf("a = %d\n", a);
a = ver;
func1(ver);
int ver = 7;
printf("ver = %d\n", ver);
func2(&ver);
}
printf("a = %d\tver = %d\n", a, ver);
}
-
传值**/**传址
- 传值:传值相当于单纯把值传给别人,相当于复制粘贴的操作,传值不会改变传值方的值。
- 传址:传地址相当于将地址赋给了对方,也就是说两个参数此时就是绑在一起的蚂蚱,它们指向同一片地址。传址后两个参数只要有一个发生改变,另一个参数就会随之改变。
-
变量的生命周期
- 变量类型主要有全局变量、局部变量和静态变量。
- 局部变量:定义在函数体内部的变量,作用域仅限于函数体内部。离开函数体就会无效,再调用就是出错。
- 全局变量:所有的函数外部定义的变量,它的作用域是整个程序,也就是所有的源文件,包括.c和.h文件。
- 静态变量(static):变量在运行区间结束后内存不释放,地址不变。
- 名称重复时 将取
最小的作用域
//这么理解应该可以
- 变量类型主要有全局变量、局部变量和静态变量。
5. 套娃真好玩!
请说明下面的程序是如何完成求和的?
unsigned sum(unsigned n) {
return n ? sum(n - 1) + n : 0; }
int main(void) {
printf("%u\n", sum(100)); }
-
简单递归
-
函数作用是求和
- 输出
5050
- 输出
-
关于递归
- 归根结底还是进行函数调用
为了解决a 要先解决b
要解决b 要先解决c当c解决了 b就解决了 从而a就解决了
- 换成递归
为了解决a 要先解决a1
要解决a2 要先解决a3当a3解决了 a2就解决了 从而a就解决了
6. 算不对的算术
void func(void) {
short a = -2;
unsigned int b = 1;
b += a;
int c = -1;
unsigned short d = c * 256;
c <<= 4;
int e = 2;
e = ~e | 6;
d = (d & 0xff) + 0x2022;
printf("a=0x%hx\tb=0x%x\td=0x%hx\te=0x%x\n", a, b, d, e);
printf("c=Ox%hhx\t\n", (signed char)c);
}
数据的补码方式存储
和位运算
动笔写
不懂原理的跳22-5的链接
- 输出:>
a=0xfffe b=0xffffffff d=0x2022 e=0xffffffff c=0xf0
7. 指针和数组的恩怨情仇
int main(void) {
int a[3][3] = {
{
1, 2, 3}, {
4, 5, 6}, {
7, 8, 9}};
int(*b)[3] = a;
++b;
b[1][1] = 10;
int *ptr = (int *)(&a + 1);
printf("%d %d %d \n", a[2][1], **(a + 1), *(ptr - 1));
}
答案 10 4 9
8. 移形换位之术
下面有
a
、b
、c
三个变量和4个相似的函数。
- 你能说出使用这三个变量的值或地址作为参数分别调用这5个函数,在语法上是否正确吗?
- 请找出下面的代码中的错误。
const int
和int const
是否有区别?如果有区别,请谈谈他们的区别。const int *
和int const *
是否有区别?如果有区别,请谈谈他们的区别。
int a = 1;
int const b = 2;
const int c = 3;
void funco(int n) {
n += 1;
n = a;
}
void func1(int *n) {
*n += 1;
n = &a;
}
void func2(const int *n) {
*n += 1;
n = &a;
}
void func3(int *const n) {
*n += 1;
n = &a;
}
void func4(const int *const n) {
*n += 1;
n = &a;
}
有关const
的问题 前面有解释 和const
和*
的位置有关 判断是顶端const还是底端const
9. 听说翻转字母大小写不影响英文的阅读?
请编写
convert
函数用来将作为参数的字符串中的大写字母转换为小写字母,将小写字母转换为大写字母。返回转换完成得到的新字符串。
char *convert(const char *s);
int main(void) {
char *str = "XiyouLinux Group 2022";
char *temp = convert(str);
puts(temp);
}
answer:>
char *convert(const char *s)
{
char *k=(char*)malloc(N);
char *t=s;
char *q=k;
memset(k,0,N);
char str[N];
for(;*s!='\0';*s++,k++)
{
if(*s>='a'&&*s<='z')
*k=toupper(*s);
else if(*s>='A'&&*s<='Z')
*k=tolower(*s);
else
*k=*s;
}
t=q;
return t;
}
10. 交换礼物的方式
- 请判断下面的三种
Swap
的正误,分别分析他们的优缺点。- 你知道这里的
do {...} while(0)
的作用吗?- 你还有其他的方式实现
Swap
功能吗?
#define Swap1(a, b, t) \
do {
\
t = a; \
a = b; \
b = t; \
} while (0)
#define Swap2(a, b) \
do {
\
int t = a; \
a = b; \
b = t; \
} while (0)
void Swap3(int a, int b) {
int t = a;
a = b;
b = t;
}
前两种方法正确,最后一种错误。
传值和传址问题
11. 据说有个东西叫参数
你知道
argc
和argv
的含义吗?请解释下面的程序。你能在不使用argc
的前提下,完成对argv
的遍历吗?
int main(int argc, char *argv[]) {
printf("argc = %d\n", argc);
for (int i = 0; i < argc; i++)
printf("%s\n", argv[i]);
}
22-11
补充> argv
是以NULL
结尾的
可以用while(argv++!=NULL) printf("%s",*argv);
来循环输出
12. 人去楼空
这段代码有是否存在错误?谈一谈静态变量与其他变量的异同。
int *func1(void) {
static int n = 0;
n = 1;
return &n;
}
int *func2(void) {
int *p = (int *)malloc(sizeof(int));
*p = 3;
return p;
}
int *func3(void) {
int n = 4;
return &n;
}
int main(void) {
*func1() = 4;
*func2() = 5;
*func3() = 6;
}
静态变量具有全局作用域 在声明后重复定义 但声明仅仅只有一次 后续碰到声明会越过
13. 奇怪的输出
int main(void) {
int data[] = {
0x636c6557, 0x20656d6f, 0x78206f74,
0x756f7969, 0x6e694c20, 0x67207875,
0x70756f72, 0x32303220, 0x00000a31};
puts((const char*)data);
}
和22年的题目一样
14. 请谈谈对从「C语言文件到可执行文件」的过程的理解
预处理 编译 汇编 链接
15. (选做) 堆和栈
你了解程序中的栈和堆吗?它们在使用上有什么区别呢?请简要说明。
栈中变量的内存由系统自行释放
堆中的内存需要手动free()
int* fun()
{
//.....
int a;//栈区
int *b =(int *)malloc(sizeof(/*num*/));//堆区
return b;
}
int main()
{
int *a=fun();
free(a);
}
上述栈区的a在fun()结束时就已经释放掉
而b的数据 在free()后才释放
16. (选做) 多文件
一个程序在不使用任何头文件的情况下,如何使用另一个文件中的函数。
extern
关键字
17. (选做) GNU/Linux
与文件
- 你知道如何在
GNU/Linux
下如何使用命令行创建文件与文
件夹吗?- 你知道
GNU/Linux
下的命令ls 的每一列的含义吗?- 你知道
GNU/Linux
下文件的访问时间、修改时间、创建时间如何查看吗?并简单说说他们的区别。
恭喜你做完了整套面试题,快来参加西邮Linux兴趣小组的面试吧!
西邮 Linux兴趣小组面试时间:
2021年10月25日至2021年10月31日晚8点。
听说面试来的早一点更能获得学长学姐的好感哦。我们在FZ103等你!
西邮Linux兴趣小组2020纳新试题题解
感谢 Zhilu 重新录入题目原件。好人一生平安。
注:
- 本题仅作为面试有限参考
- 为节省版面,省去所有
#include
指令- 题目难度与序号无关
- 若无特殊声明,均假设在
Linux x86_64 GCC
编译器环境下
1. 请试着解释其输出。
int main(int argc , char *argv[]) {
unsigned char a = 255;
char ch = 128;
a -= ch;
printf("a = %d ch = %d\n", a, ch);
}
- 输出:>
a = 127 ch = -128
- 当右值的数据长度大于左值的数据长度时 赋值过程将发生截断
- 当同等长度的无符号数和有符号数进行运算时 会将有符号数转化为无符号数
2. 下面代码的运行输出结果是什么,并说说你的理解。
int main(int argc, char *argv[]) {
char *str = "Xi You Linux Group 20";
printf("%d\n", printf(str));
return 0;
}
printf()的返回值 看22年的题
3. 这段代码的输出结果是什么?为什么会出现这样的结果?
int i = 2;
void func() {
if(i != 0) {
static int m = 0;
int n = 0;
n++;
m++;
printf("m = %d, n = %d\n", m, n);
i--;
func();
} else {
return;
}
}
int main(int argc, char *argv[]) {
func();
return 0;
}
- 输出
m = 1, n = 1 m = 2, n = 1
- 递归和静态变量
4. 下面程序会出现什么结果?为什么会出现这样的结果?
int main(int argc, char * argv[]) {
char ch = 'A';
int i = 65;
unsigned int f = 33554433;
*(int *)&f >>= 24;
*(int *)&f = *(int *)&f + '?';
printf("ch = %c i = %c f = %c\n", ch, i, *(int *)&f);
return 0;
}
- 输出
ch = A i = A f = A
位运算 类型转换
5. 下面代码的运行输出结果是什么,并说说你的理解。
int main(int argc, char *argv[]) {
int a[2][2];
printf("&a = %p\t&a[0] = %p\t&a[0][0] = %p\n", &a, &a[0], &a[0][0]);
printf("&a+1 = %p\t&a[0]+1 = %p\t&a[0][0]+1= %p\n", &a+1, &a[0]+1, &a[0][0]+1);
return 0;
}
- 输出
&a = 0x7fffffffda80 &a[0] = 0x7fffffffda80 &a[0][0] = 0x7fffffffda80 &a+1 = 0x7fffffffda90 &a[0]+1 = 0x7fffffffda88 &a[0][0]+1= 0x7fffffffda84
数组的实质–>存放数据的地址
6. 下列程序的功能是什么?有什么问题,你能找出问题并解决它吗?
int* get_array() {
int array[1121];
for (int i = 0; i < sizeof(array) / sizeof(int); i++) {
array[i] = i;
}
return array;
}
int main(int argc, char *argv[]) {
int *p = get_array();
}
问题:> 传回的array指向的内存在get_array()
返回时就被销毁了(//21年里说的栈区)
7. 下面代码的运行输出结果是什么,并说说你的理解。
int main(int argc, char *argv[]) {
char str[] = "XiyouLinuxGroup";
char *p = str;
char x[] = "XiyouLinuxGroup\t\106F\bamily";
printf("%zu %zu %zu %zu\n", sizeof(str), sizeof(p), sizeof(x), strlen(x));
return 0;
}
- 输出
16 8 25 24
sizeof()实际运算的个体
16–str内存占用的大小
8 --指针的大小
25–x的大小
24–x串的长度
8. 如下程序,根据打印结果,你有什么思考?
int add(int *x, int y) {
return *x = (*x^y) + ((*x&y)<<1);
}
int a;
int main(int argc, char *argv[]) {
int b = 2020;
if(add(&b, 1) || add(&a, 1)) {
printf("XiyouLinuxGroup%d\n", b);
printf("Waiting for y%du!\n", a);
}
if(add(&b, 1) && a++) {
printf("XiyouLinuxGroup%d\n", b);
printf("Waiting for y%du!\n", a);
}
return 0;
}
- 输出
XiyouLinuxGroup2021 Waiting for y0u!
9. 在下段程序中,我们可以通过第一步打印出a
的地址,假如在你的机器上面打印结果是0x7ffd737c6db4
;我们在第二步用scanf
函数将这个地址值输入变量c
中;第三步,随机输入一个数字,请问最终输出了什么结果,你知道其中的原理吗?
void func() {
int a = 2020;
unsigned long c;
printf("%p\n", &a);
printf("我们想要修改的地址:");
scanf("%lx", &c);
printf("请随便输入一个数字:");
scanf("%d", (int *)c);
printf("a = %d\n", a);
}
10. 请问一个C语言程序从源代码到可执行文件中间会进行哪些过程,你能简单描述一下每个环节都做了什么事情吗?
预处理 编译 汇编 链接
11. 请解释一下这行代码做了什么?
puts((char*)(int const[]){
0X6F796958,0X6E694C75,0X72477875,
0X3270756F,0X313230,0X00000A
});
打印XiyouLinuxGroup2021
和前两年一样
12. 请随机输入一串字符串,你能解释一下输出结果吗?
int main(int argc, char *argv[]) {
char str[1121];
int key;
char t;
fgets(str, 1121, stdin);
for(int i = 0; i < strlen(str) - 1; i++) {
key = i;
for(int j = i + 1; j < strlen(str); j++) {
if(str[key] > str[j]) {
key = j;
}
}
t = str[key];
str[key] = str[i];
str[i] = t;
}
puts(str);
return 0;
}
排序算法
依次找最小值 放在第i个位置
14. Linux 实操题
请通过命令创建一个目录,在该目录中创建几个后缀为
.Linux
的文件,然后通过命令查询这几个文件的基本属性信息(如文件大小,文件创建时间等),之后使用命令查看该目录下文件名含有“.Linux
”的文件的数量(不包括子目录下的文件),把得到的数字写入到一个文件中,最后删除此目录。
前面的linux命令操作有