西邮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);
}
题解:
结果:16 12
sizeof是运算符,计算的是你使用的操作数所占的空间字节大小,包括’\0’。
而strlen是函数,计算的是字符串的长度,遇到’\0’就停止不包括’\0’。
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));
}
题解:
结果:16 16
结构体内存对齐详细见:
https://blog.csdn.net/weixin_44343938/article/details/126932999?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522166890900816800182183666%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=166890900816800182183666&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2alltop_positive~default-1-126932999-null-null.142v65opensearch_v2,201v3add_ask,213v2t3_esquery_v1&utm_term=%E7%BB%93%E6%9E%84%E4%BD%93%E5%86%85%E5%AD%98%E5%AF%B9%E9%BD%90%E8%A7%84%E5%88%99&spm=1018.2226.3001.4187
3. 哦,又是函数
想必在高数老师的教导下大家十分熟悉函数这个概念。那么你了解计算机程序设计中的函数吗?请编写一个
func
函数,用来输出二维数组arr
中每个元素的值。
/*在这里补全func函数的定义*/
void func(int (&arr)[10][13])
{
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 13; j++)
{
printf("%d ", arr[i][j]);
}
printf("\n");
}
}
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);
}
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);
}
题解:
结果:
a = 5
ver = 1026
ver = 7
*pr = 1234
ver = 123
a = 4 ver = 1025
传值和传址:
传值:把A的数值传到B,改变B,A不会跟着变,B存的是跟A一样的值;
传址:把A的地址传到B,改变B,A同时跟着变,B存的只是A的地址(类似电脑的快捷方式)。
传址,相当于是把A的地址传给B,所以说改变B的时候,相当于改变A,所以说B变的时候A也跟着变。
【效率比较】
一般而言,传址比传值效率高。因为传值对整个类型进行了拷贝,而传址只复制了地址。比如,现有一个结构体,存储了大量的数据。传值拷贝了整个结构体,而传址只是拷贝了地址。
5. 套娃真好玩!
请说明下面的程序是如何完成求和的?
unsigned sum(unsigned n) { return n ? sum(n - 1) + n : 0; }
int main(void) { printf("%u\n", sum(100)); }
题解:
结果:5050
条件运算符 表达式1?表达式2:表达式3 如果表达式1的值为真,则求解表达式2,表达式为假,则求解表达式3
函数的递归思想,读者如有不懂,cv调试一下
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);
}
题解:
结果:
a=0xfffe b=0xffffffff d=0x2022 e=0xffffffff
c=Oxf0
依旧是运算符优先级:优先级:取反>左移>按位与>按位异或>按位或
%x代表以16进制的 输出32位
%hx 代表以16进制的 输出16位
%hhx 代表以16进制的 输出8位
7. 指针和数组的恩怨情仇
#include<stdio.h>
int main()
{
int a[3][3] = { {1,2,3},{4,5,6},{7,8,9} };
int(*b)[3] = a;//指向数组的指针
++b;//指向a首地址后一个元素
b[1][1] = 10;//a[2][1]=10
int* ptr = (int*)(&a + 1);//&a指向a数组开头,+1后指向下一个数组, 所以*(ptr - 1)=a[2][2]
printf("%d %d %d\n", a[2][1], **(a + 1), *(ptr - 1));//**(a+1)=a[1][1]
return 0;//结果为10 4 9
}
8. 移形换位之术
下面有
a
、b
、c
三个变量和4个相似的函数。
- 你能说出使用这三个变量的值或地址作为参数分别调用这5个函数,在语法上是否正确吗?
- 请找出下面的代码中的错误。
const int
和int const
是否有区别?如果有区别,请谈谈他们的区别。
const int *
和int const *
是否有区别?如果有区别,请谈谈他们的区别。
详细见:
https://blog.csdn.net/huangchijun11/article/details/72725463?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522166890979516782428632372%2522%252C%2522scm%2522%253A%252220140713.130212432.pc%255Fall.%2522%257D&request_id=166890979516782428632372&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allfirst_rank_ecpm_v1~pc_ctr_v2-1-72725463-null-null.142v65opensearch_v2,201v3add_ask,213v2t3_esquery_v1&utm_term=%60const%20int%20*%60%E5%92%8C%60int%20const%20*%60&spm=1018.2226.3001.4187
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 int 和int const都是指该int类型变量不能被修改,没有区别
const int和int const也没有区别,都是指指针指向的值不能被改变
9. 听说翻转字母大小写不影响英文的阅读?
请编写
convert
函数用来将作为参数的字符串中的大写字母转换为小写字母,将小写字母转换为大写字母。返回转换完成得到的新字符串。
char *convert(const char *s);
int main(void) {
char *str = "XiyouLinux Group 2022";
char *temp = convert(str);
puts(temp);
}
char* convert(const char* s)
{
int i;
char* tmp = (char*)malloc(sizeof(char) * strlen(s));
tmp[21] = '\0';
strcat(tmp, s);
for (i = 0; i < 21; i++) {
if (tmp[i] >= 96 && tmp[i] <= 122) {
tmp[i] -= 32;
}
else if (tmp[i] >= 65 && tmp[i] <= 90) {
tmp[i] += 32;
}
}
free(tmp);
return tmp;
}
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;
}
题解:
do while配合宏定义使用!
①swap1直接从原函数中传递参数,方便
②swap2是创建了一个变量t,用来交换,占用内存小
③swap3是错误的。它只是改变了变量a,b的值,并没有传地址,仅仅是在函数体内部改变了a,b的值,相当于没有对a,b做任何操作,函数运行后a,b的值不会发生改变。
//传地址
void Swap(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]);
}
int main(int argc, char*argv[])
{
int i=0;
while(argv[i]!=NULL)
printf("%s\n",argv[i++]);
return 0;
}
12. 人去楼空
这段代码有是否存在错误?谈一谈静态变量与其他变量的异同。
#include<stdio.h>
#include<stdlib.h>
int *func1(void)
{
static int n=0;//生存周期是从调用它开始到本函数结束
n=1;
return &n;//只能返回指针值也就是n的地址,因为静态变量的值一直保存,且地址一直存在(重点)
}
int *func2(void)
{
int*p=(int*)malloc(sizeof(int));
*p=3;
return p;//返回指向新分配内存的首地址
}
//错误
int *func3(void)
{
int n=4;
return n;//不可返回局部变量的地址(&n),作用完就被释放了。
}
13. 奇怪的输出
int main(void) {
int data[] = {0x636c6557, 0x20656d6f, 0x78206f74,
0x756f7969, 0x6e694c20, 0x67207875,
0x70756f72, 0x32303220, 0x00000a31};
puts((const char*)data);
}
同22-12
14. 请谈谈对从「C语言文件到可执行文件」的过程的理解
1.预处理(主要处理代码中以字符#开头的命令)
2.编译
3.汇编(把汇编语句转换为机器指令)
4.链接(链接器将所有二进制的目标文件和系统组件组合成一个可执行文件(.exe))
15. (选做) 堆和栈
你了解程序中的栈和堆吗?它们在使用上有什么区别呢?请简要说明。
https://blog.csdn.net/K346K346/article/details/80849966?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522166891059316800213074800%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=166891059316800213074800&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2alltop_positive~default-1-80849966-null-null.142v65opensearch_v2,201v3add_ask,213v2t3_esquery_v1&utm_term=%E6%A0%88%E5%92%8C%E5%A0%86&spm=1018.2226.3001.4187
16. (选做) 多文件
一个程序在不使用任何头文件的情况下,如何使用另一个文件中的函数。
17. (选做) GNU/Linux
与文件
- 你知道如何在
GNU/Linux
下如何使用命令行创建文件与文
件夹吗?- 你知道
GNU/Linux
下的命令ls 的每一列的含义吗?- 你知道
GNU/Linux
下文件的访问时间、修改时间、创建时间如何查看吗?并简单说说他们的区别。
恭喜你做完了整套面试题,快来参加西邮Linux兴趣小组的面试吧!
西邮 Linux兴趣小组面试时间:
2021年10月25日至2021年10月31日晚8点。
听说面试来的早一点更能获得学长学姐的好感哦。我们在FZ103等你!