西邮 Linux 兴趣小组 2026 纳新面试题0. 树懒闪电的二进制车牌树懒闪电要办一张二进制车牌:16 个按钮里有四个连续按钮的数是 21、34、55、89,每个按钮最多按一次、不能按相邻的两个,按下数字之和即车牌号。屏幕显示 11010100101,该按哪几个按钮?其十进制是多少?提示: 这 16 个数构成递推数列,每项等于前两项之和。解析:这十六个数构成的是斐波那契数列,已经知道了四个连续的数,那么就可以算出来其它的数来。二进制数转十进制数的方法是,从右往左,每一位的数字乘以2的对应位次次方(位次从 0 开始计数),再将所有结果相加。数字之和的二进制表示给了出来,则其十进制数可以求出来。根据总和算按下的按钮。答案按下的按钮为:2 13 89 15971. 一句印不完的欢迎词这句欢迎词是永无止境的吗?请解释运行结果:printf 的返回值扮演了什么角色,while 是否真的停不下来?intmain(){while(1){printf("Hi! ");if(!printf("The 202%d, Welcome to Xiyou Linux Group!\n",printf("guys! "))){break;}}}解析printf是有返回值的,返回值是其成功打印的字符个数,包括空格,标点等。!是 C 语言里的逻辑非运算符,可以直接理解成:不、反过来、取反。若值是0,为假,if循环语句不执行,即不执行break。如果值为非0,为真,if循环语句执行,即执行break。执行了break,while才能停止。答案死循环,无限输出Hi! guys! The 2026, Welcome to Xiyou Linux Group!2. 失忆的交换生两位交换生都帮 a 和 b 换座位:第一位换完就忘,第二位却成功了。请解释运行结果:函数修改外部变量的必要条件是什么?voidswap_val(intx,inty){inttmp=x;x=y;y=tmp;}voidswap_ptr(int*x,int*y){inttmp=*x;*x=*y;*y=tmp;}intmain(){inta=10,b=20;swap_val(a,b);printf("swap_val: a=%d, b=%d\n",a,b);swap_ptr(&a,&b);printf("swap_ptr: a=%d, b=%d\n",a,b);}解析函数传参其实就是在内存上重新申请了一块空间来储存所传的数据。因此,新空间上数据的改变无法让原空间上的数据改变,这是两组不同的数据。只有获取了原数据的地址,外部函数才能更改原数据。即传址调用。答案swap_val: a=10, b=20swap_ptr: a=20, b=103. sizeof 的视力表请预测输出,并解释每个 sizeof 和 strlen 的结果:注意字符串中间的 \0、数组退化与指针类型。voidinspect(chartext[],int(*matrix)[4]){printf("%zu %zu %zu %zu\n",sizeof(text),sizeof(matrix),sizeof(*matrix),strlen(text));}intmain(){chara[]="Linux\0Group";char*p=a;intb[2][4]={{1,2,3,4},{5,6,7,8}};printf("%zu %zu %zu\n",sizeof(a),sizeof(p),sizeof(a+0));printf("%d %d\n",a[5]=='\0',strcmp(a,"Linux"));inspect(a,b);}解析:数组作为函数参数会退化为指针。数组名参与运算会变成指针。sizeof(数组名)或&(数组名)时,数组名代表整个数组,否则是数组首元素的地址。64 位下指针大小都是 8 字节。答案sizeof(a)=12sizeof(p)=8sizeof(a+0)=800inspect中:sizeof(text)=8sizeof(matrix)=8sizeof(*matrix)=16strlen(text)=54. XOR 密钥:藏在字节里的悄悄话一串数字里藏着一句悄悄话。请解释代码如何用位运算把数字还原成字符:mask 怎么构造,为什么异或后恰好是原文?intmain(){intnums[]={167,150,134,144,138,179,150,145,138,135,184,141,144,138,143};intsize=sizeof(nums)/sizeof(nums[0]);for(inti=0;i<size;i++){intmask=0;intbitval=1;intbits=8;while(bits-->0){mask|=bitval;bitval<<=1;}printf("%c",nums[i]^mask);if(i==size-1){printf("\n");}}}解析1.位运算符:& 按位与:对应两个二进制位,只有两位都是 1,结果位才是 1;只要有一个是 0,结果就是 0。| 按位或:对应两个二进制位,只要有一个是 1,结果位就是 1;两位全 0 才是 0。^ 按位异或:对应两个二进制位,不一样(一个 0 一个 1)结果就是 1;一样(全 0 或全 1)结果就是 0。while (bits-- > 0) { mask |= bitval; bitval <<= 1;的作用是:将mask的每一位都变成1将数组中的元素与改变后的mask按位异或,相当于将各个元素按位取反,达到解密的效果。答案XiyouLinuxGroup5. 宏召唤术:括号去哪儿了这两个宏看着人畜无害,展开后却各有脾气。请写出四行 printf 的输出,并解释原因。#defineSQUARE(x)x*x#defineMAX(a,b)((a)>(b)?(a):(b))intmain(){inti=3;printf("%d\n",SQUARE(i+1));printf("%d\n",MAX(i,5));printf("%d\n",MAX(i++,5));printf("%d\n",i);}解析宏定义是纯文本替换,不会自动加括号,不考虑运算优先级答案75546. p 与 q 的步幅之争p 和 q 指向同一个数组,“步幅”却大不相同。输出是什么?p + 1 和 q + 1 各跨过多少字节?intmain(){inta[4]={1,2,3,4};int*p=a;int(*q)[4]=&a;printf("%td %td\n",(char*)(p+1)-(char*)p,(char*)(q+1)-(char*)q);printf("%d %d\n",*(p+2),*(*q+2));}解析当&(数组名)或sizeof(数组名)时,数组名代表的是整个数组,否则,数组名就是数组首元素的地址。short 占2个字节; int 类型占四个字节;char 占一个字节;long 占6个字节;long long 占8个字节;指针 + 1,移动的字节数 = 指向类型的大小。答案4 163 37. 记性特别好的 x这个 x 走遍千山万水仍记得来时的路。请预测每行输出,并解释 static 局部变量在递归中的行为。intvisit(intn){staticintx=0;if(n==0)returnx;x+=n;printf("before %d %d\n",n,x);intresult=visit(--n);printf("after %d %d %d\n",n,x,result);returnx+result;}intmain(){printf("first = %d\n",visit(3));printf("second = %d\n",visit(2));}解析static的作用:作用于局部变量使该局部变量的生命周期变长,可以从程序开始存在于程序结束。但该局部变量的作用域未变。作用于全局变量使该全局变量只能在本文件中起作用,其他文件无法调用。作用于函数使其作用域限制在本文件中递归的过程:主函数↓调用 visit(3)┌───────────────────────────────┐│ visit(3) │ x = 0+3 = 3,打印 before 3 3│ return x + result → 6+18=24 │←──┐ 拿到下层返回的result=18,算出24,返回给主函数└───────────────────────────────┘ │↓调用 visit(2) │┌───────────────────────────────┐ ││ visit(2) │ │ x = 3+2 = 5,打印 before 2 5│ return x + result → 6+12=18 │←──┐ 拿到下层返回的result=12,算出18,返回给上一层└───────────────────────────────┘ │↓调用 visit(1) │┌───────────────────────────────┐ ││ visit(1) │ │ x = 5+1 = 6,打印 before 1 6│ return x + result → 6+6=12 │←──┐ 拿到下层返回的result=6,算出12,返回给上一层└───────────────────────────────┘ │↓调用 visit(0) │┌───────────────────────────────┐ ││ visit(0) │ ││ return x → 6 │───┘ 触发终止条件,直接返回当前的 x=6└───────────────────────────────┘答案before 3 3before 2 5before 1 6after 0 6 6after 1 6 12after 2 6 18first = 24before 2 8before 1 9after 0 9 9after 1 9 18second = 278. 谁能动 const 大神的奶酪一眼以为“const 就全不能动”,逐条判断却错一片。请判断九个操作是否合法,并说明原因。structP{intx;constinty;};intmain(){structPp1={11,22},p2={33,44};conststructPp3={55,66};structP*constptr1=&p1;conststructP*ptr2=&p2;conststructP*constptr3=&p3;ptr1->x=111;ptr2->x=333;ptr3->x=555;ptr1->y=222;ptr1=&p2;ptr2->y=444;ptr2=&p1;ptr3->y=666;ptr3=&p1;}解析const的作用:修饰变量后,此变量不可更改。修饰指针: const在 * 左边,指针指向的内容不能更改;const在 * 的右边,指针不能改。const在 * 中间,什么都不能改。修饰函数,函数内部不会修改传入的数据。答案操作是否合法原因ptr1->x = 11合法ptr1 是普通指针,指向普通结构体,x 是非 const 成员ptr2->x = 333非法ptr2 指向 const 结构体,不能通过它修改任何成员ptr3->x = 555非法ptr3 指向 const 结构体,不能修改成员ptr1->y = 222非法y 本身就是结构体里的 const 成员,任何方式都不能改ptr2 = &p1合法ptr2 本身不是 const 指针,可以改指向;指向常量的指针可以指向非 const 变量ptr2->y = 444非法y 本身是 const,且 ptr2 指向 const 结构体ptr3 = &p1非法ptr3 是常量指针,指针本身不能修改指向ptr3->y = 666非法指向 const 结构体,且 y 本身是 const*ptr3.x = ...非法双重 const 限制,既不能改指向也不能改指向的内容9. 当函数变成了数字在这里,函数既能装进数组,也能被加减乘除。这段代码写得标准吗?注意 INT_MIN 和 0xFFFFFFFF。typedefint(*BinOp)(int,int);intadd(inta,intb){returna+b;}intsub(inta,intb){returna-b;}intmul(inta,intb){returna*b;}BinOp ops[3]={add,sub,mul};int(*get_op(charc))(int,int){switch(c){case'+':returnadd;case'-':returnsub;default:returnmul;}}intmain(){printf("%d\n",get_op('*')(7,-2));printf("%d\n",ops[1](INT_MIN,20));printf("%d\n",get_op('+')(0xFFFFFFFF,2027));}解析:0XFFFFFFFF作为 32 位有符号 int,补码表示的是-1INT_MIN - 2:有符号整数溢出,结果是2^31-20。答案52147483646282610. 字节战队排排站:大端、小端与内存对齐同一片内存,不同视角看到不同世界。请写出全部输出,并解释大端、小端与内存对齐的原理structdata_box{intnum;union{unsignedintu32_val;unsignedcharbytes[4];charstring[32];}un;shorttag;longlongmagic;intbuf[4];};intmain(){intarr[]={0x00000000,0x6F796958,0x694C2075,0x2078756E,0x756F7247,0x00000070,0x44556677,0x8899aabb};printf("%s\n",((structdata_box*)arr)->un.string);printf("byte0 = 0x%02X\n",((structdata_box*)arr)->un.bytes[0]);printf("byte1 = 0x%02X\n",((structdata_box*)arr)->un.bytes[1]);printf("byte2 = 0x%02X\n",((structdata_box*)arr)->un.bytes[2]);printf("byte3 = 0x%02X\n",((structdata_box*)arr)->un.bytes[3]);}答案Xiyou Linux Group byte0=0x58byte1=0x69byte2=0x79byte3=0x6F小端模式:数据的低字节存在内存低地址,高字节存在高地址。大端模式:高字节存在低地址。共用体:所有成员共享同一块内存,大小等于最大成员的大小。内存对齐:结构体成员按自身大小对齐内存,整体大小是最大对齐数的整数倍。
西邮 Linux 兴趣小组 2026 纳新面试题0. 树懒闪电的二进制车牌树懒闪电要办一张二进制车牌:16 个按钮里有四个连续按钮的数是 21、34、55、89,每个按钮最多按一次、不能按相邻的两个,按下数字之和即车牌号。屏幕显示 11010100101,该按哪几个按钮?其十进制是多少?提示: 这 16 个数构成递推数列,每项等于前两项之和。解析:这十六个数构成的是斐波那契数列,已经知道了四个连续的数,那么就可以算出来其它的数来。二进制数转十进制数的方法是,从右往左,每一位的数字乘以2的对应位次次方(位次从 0 开始计数),再将所有结果相加。数字之和的二进制表示给了出来,则其十进制数可以求出来。根据总和算按下的按钮。答案按下的按钮为:2 13 89 15971. 一句印不完的欢迎词这句欢迎词是永无止境的吗?请解释运行结果:printf 的返回值扮演了什么角色,while 是否真的停不下来?intmain(){while(1){printf("Hi! ");if(!printf("The 202%d, Welcome to Xiyou Linux Group!\n",printf("guys! "))){break;}}}解析printf是有返回值的,返回值是其成功打印的字符个数,包括空格,标点等。!是 C 语言里的逻辑非运算符,可以直接理解成:不、反过来、取反。若值是0,为假,if循环语句不执行,即不执行break。如果值为非0,为真,if循环语句执行,即执行break。执行了break,while才能停止。答案死循环,无限输出Hi! guys! The 2026, Welcome to Xiyou Linux Group!2. 失忆的交换生两位交换生都帮 a 和 b 换座位:第一位换完就忘,第二位却成功了。请解释运行结果:函数修改外部变量的必要条件是什么?voidswap_val(intx,inty){inttmp=x;x=y;y=tmp;}voidswap_ptr(int*x,int*y){inttmp=*x;*x=*y;*y=tmp;}intmain(){inta=10,b=20;swap_val(a,b);printf("swap_val: a=%d, b=%d\n",a,b);swap_ptr(&a,&b);printf("swap_ptr: a=%d, b=%d\n",a,b);}解析函数传参其实就是在内存上重新申请了一块空间来储存所传的数据。因此,新空间上数据的改变无法让原空间上的数据改变,这是两组不同的数据。只有获取了原数据的地址,外部函数才能更改原数据。即传址调用。答案swap_val: a=10, b=20swap_ptr: a=20, b=103. sizeof 的视力表请预测输出,并解释每个 sizeof 和 strlen 的结果:注意字符串中间的 \0、数组退化与指针类型。voidinspect(chartext[],int(*matrix)[4]){printf("%zu %zu %zu %zu\n",sizeof(text),sizeof(matrix),sizeof(*matrix),strlen(text));}intmain(){chara[]="Linux\0Group";char*p=a;intb[2][4]={{1,2,3,4},{5,6,7,8}};printf("%zu %zu %zu\n",sizeof(a),sizeof(p),sizeof(a+0));printf("%d %d\n",a[5]=='\0',strcmp(a,"Linux"));inspect(a,b);}解析:数组作为函数参数会退化为指针。数组名参与运算会变成指针。sizeof(数组名)或&(数组名)时,数组名代表整个数组,否则是数组首元素的地址。64 位下指针大小都是 8 字节。答案sizeof(a)=12sizeof(p)=8sizeof(a+0)=800inspect中:sizeof(text)=8sizeof(matrix)=8sizeof(*matrix)=16strlen(text)=54. XOR 密钥:藏在字节里的悄悄话一串数字里藏着一句悄悄话。请解释代码如何用位运算把数字还原成字符:mask 怎么构造,为什么异或后恰好是原文?intmain(){intnums[]={167,150,134,144,138,179,150,145,138,135,184,141,144,138,143};intsize=sizeof(nums)/sizeof(nums[0]);for(inti=0;i<size;i++){intmask=0;intbitval=1;intbits=8;while(bits-->0){mask|=bitval;bitval<<=1;}printf("%c",nums[i]^mask);if(i==size-1){printf("\n");}}}解析1.位运算符:& 按位与:对应两个二进制位,只有两位都是 1,结果位才是 1;只要有一个是 0,结果就是 0。| 按位或:对应两个二进制位,只要有一个是 1,结果位就是 1;两位全 0 才是 0。^ 按位异或:对应两个二进制位,不一样(一个 0 一个 1)结果就是 1;一样(全 0 或全 1)结果就是 0。while (bits-- > 0) { mask |= bitval; bitval <<= 1;的作用是:将mask的每一位都变成1将数组中的元素与改变后的mask按位异或,相当于将各个元素按位取反,达到解密的效果。答案XiyouLinuxGroup5. 宏召唤术:括号去哪儿了这两个宏看着人畜无害,展开后却各有脾气。请写出四行 printf 的输出,并解释原因。#defineSQUARE(x)x*x#defineMAX(a,b)((a)>(b)?(a):(b))intmain(){inti=3;printf("%d\n",SQUARE(i+1));printf("%d\n",MAX(i,5));printf("%d\n",MAX(i++,5));printf("%d\n",i);}解析宏定义是纯文本替换,不会自动加括号,不考虑运算优先级答案75546. p 与 q 的步幅之争p 和 q 指向同一个数组,“步幅”却大不相同。输出是什么?p + 1 和 q + 1 各跨过多少字节?intmain(){inta[4]={1,2,3,4};int*p=a;int(*q)[4]=&a;printf("%td %td\n",(char*)(p+1)-(char*)p,(char*)(q+1)-(char*)q);printf("%d %d\n",*(p+2),*(*q+2));}解析当&(数组名)或sizeof(数组名)时,数组名代表的是整个数组,否则,数组名就是数组首元素的地址。short 占2个字节; int 类型占四个字节;char 占一个字节;long 占6个字节;long long 占8个字节;指针 + 1,移动的字节数 = 指向类型的大小。答案4 163 37. 记性特别好的 x这个 x 走遍千山万水仍记得来时的路。请预测每行输出,并解释 static 局部变量在递归中的行为。intvisit(intn){staticintx=0;if(n==0)returnx;x+=n;printf("before %d %d\n",n,x);intresult=visit(--n);printf("after %d %d %d\n",n,x,result);returnx+result;}intmain(){printf("first = %d\n",visit(3));printf("second = %d\n",visit(2));}解析static的作用:作用于局部变量使该局部变量的生命周期变长,可以从程序开始存在于程序结束。但该局部变量的作用域未变。作用于全局变量使该全局变量只能在本文件中起作用,其他文件无法调用。作用于函数使其作用域限制在本文件中递归的过程:主函数↓调用 visit(3)┌───────────────────────────────┐│ visit(3) │ x = 0+3 = 3,打印 before 3 3│ return x + result → 6+18=24 │←──┐ 拿到下层返回的result=18,算出24,返回给主函数└───────────────────────────────┘ │↓调用 visit(2) │┌───────────────────────────────┐ ││ visit(2) │ │ x = 3+2 = 5,打印 before 2 5│ return x + result → 6+12=18 │←──┐ 拿到下层返回的result=12,算出18,返回给上一层└───────────────────────────────┘ │↓调用 visit(1) │┌───────────────────────────────┐ ││ visit(1) │ │ x = 5+1 = 6,打印 before 1 6│ return x + result → 6+6=12 │←──┐ 拿到下层返回的result=6,算出12,返回给上一层└───────────────────────────────┘ │↓调用 visit(0) │┌───────────────────────────────┐ ││ visit(0) │ ││ return x → 6 │───┘ 触发终止条件,直接返回当前的 x=6└───────────────────────────────┘答案before 3 3before 2 5before 1 6after 0 6 6after 1 6 12after 2 6 18first = 24before 2 8before 1 9after 0 9 9after 1 9 18second = 278. 谁能动 const 大神的奶酪一眼以为“const 就全不能动”,逐条判断却错一片。请判断九个操作是否合法,并说明原因。structP{intx;constinty;};intmain(){structPp1={11,22},p2={33,44};conststructPp3={55,66};structP*constptr1=&p1;conststructP*ptr2=&p2;conststructP*constptr3=&p3;ptr1->x=111;ptr2->x=333;ptr3->x=555;ptr1->y=222;ptr1=&p2;ptr2->y=444;ptr2=&p1;ptr3->y=666;ptr3=&p1;}解析const的作用:修饰变量后,此变量不可更改。修饰指针: const在 * 左边,指针指向的内容不能更改;const在 * 的右边,指针不能改。const在 * 中间,什么都不能改。修饰函数,函数内部不会修改传入的数据。答案操作是否合法原因ptr1->x = 11合法ptr1 是普通指针,指向普通结构体,x 是非 const 成员ptr2->x = 333非法ptr2 指向 const 结构体,不能通过它修改任何成员ptr3->x = 555非法ptr3 指向 const 结构体,不能修改成员ptr1->y = 222非法y 本身就是结构体里的 const 成员,任何方式都不能改ptr2 = &p1合法ptr2 本身不是 const 指针,可以改指向;指向常量的指针可以指向非 const 变量ptr2->y = 444非法y 本身是 const,且 ptr2 指向 const 结构体ptr3 = &p1非法ptr3 是常量指针,指针本身不能修改指向ptr3->y = 666非法指向 const 结构体,且 y 本身是 const*ptr3.x = ...非法双重 const 限制,既不能改指向也不能改指向的内容9. 当函数变成了数字在这里,函数既能装进数组,也能被加减乘除。这段代码写得标准吗?注意 INT_MIN 和 0xFFFFFFFF。typedefint(*BinOp)(int,int);intadd(inta,intb){returna+b;}intsub(inta,intb){returna-b;}intmul(inta,intb){returna*b;}BinOp ops[3]={add,sub,mul};int(*get_op(charc))(int,int){switch(c){case'+':returnadd;case'-':returnsub;default:returnmul;}}intmain(){printf("%d\n",get_op('*')(7,-2));printf("%d\n",ops[1](INT_MIN,20));printf("%d\n",get_op('+')(0xFFFFFFFF,2027));}解析:0XFFFFFFFF作为 32 位有符号 int,补码表示的是-1INT_MIN - 2:有符号整数溢出,结果是2^31-20。答案52147483646282610. 字节战队排排站:大端、小端与内存对齐同一片内存,不同视角看到不同世界。请写出全部输出,并解释大端、小端与内存对齐的原理structdata_box{intnum;union{unsignedintu32_val;unsignedcharbytes[4];charstring[32];}un;shorttag;longlongmagic;intbuf[4];};intmain(){intarr[]={0x00000000,0x6F796958,0x694C2075,0x2078756E,0x756F7247,0x00000070,0x44556677,0x8899aabb};printf("%s\n",((structdata_box*)arr)->un.string);printf("byte0 = 0x%02X\n",((structdata_box*)arr)->un.bytes[0]);printf("byte1 = 0x%02X\n",((structdata_box*)arr)->un.bytes[1]);printf("byte2 = 0x%02X\n",((structdata_box*)arr)->un.bytes[2]);printf("byte3 = 0x%02X\n",((structdata_box*)arr)->un.bytes[3]);}答案Xiyou Linux Group byte0=0x58byte1=0x69byte2=0x79byte3=0x6F小端模式:数据的低字节存在内存低地址,高字节存在高地址。大端模式:高字节存在低地址。共用体:所有成员共享同一块内存,大小等于最大成员的大小。内存对齐:结构体成员按自身大小对齐内存,整体大小是最大对齐数的整数倍。