2021面试题

西邮Linux兴趣小组2021纳新面试题题解

感谢 Zhilu 重新录入题目原件。好人一生平安。

注:

  • 本题目仅作西邮Linux兴趣小组2021纳新面试题的有限参考。
  • 为节省版面本试题的程序源码中省略了#include指令。
  • 本试题中的程序源码仅用于考察C语言基础,不应当作为C语言代码风格的范例。
  • 题目难度与序号无关。
  • 所有题目均假设编译并运行x86_64 GNU/Linux环境。

Copyright © 2021 西邮Linux兴趣小组, All Rights Reserved.
本试题使用采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。

1. 大小和长度竟然不是一个意思

sizeof()strlen()有什么异同之处?

他们对于不同参数的结果有什么不同?请试举例子说明。

sizeof与strlen的区别是,sizeof对象是各种数据类型,计算它们的大小,单位是字节,而strlen是针对字符串,用来计算字符串的长度,sizeof在计算字符串大小的时候会计算到字符串末尾的\0;而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);
}

2. 箱子的大小和装入物品的顺序有关

test1test2都含有: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,
根据结构体内存分配可知。

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);
}
void func(int a[][13]){
	for(int i=0;i<10;i++){
		for(int j=0;j<13;j++){
			printf("%d,",a[i][j]);
		}
	}
	
}

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);
}

传值即将数的数值传过去,对其进行操作并不会影响原来的数,而传址是将数的地址传过去,如果对地址加以操作,原数的数值也会随之而变化。
1 局部变量:“在函数内定义的变量”,

即在一个函数内部定义的变量,只在本函数范围内有效。

2 全局变量:“在函数外定义的变量”,

即从定义变量的位置到本源文件结束都有效。
      局部变量的生命周期就是变量所在的局部范围。
      全局变量的生命周期可以说是整个工程。

5. 套娃真好玩!

请说明下面的程序是如何完成求和的?

unsigned sum(unsigned n) { return n ? sum(n - 1) + n : 0; }
int main(void) { printf("%u\n", sum(100)); }

这里的函数内容是个三目运算符,判断结果为真,执行冒号前的语句,为假,执行冒号后的语句。首先给出100,为真,执行sum(n-1)+n;即100+99;为真,继续执行,如此递归循环,直至n=0时,跳出。所以函数完成了从100-1的累加。结果为100(100+1)/2=5050;

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

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));
}

b指向数组第一行,+1跑到第二行,此时b[1][1]就代表a数组的第三行,所以这里把8变成了9,**(a+1)代表的是数组第二行的第一个数,就是4,这里&a+1,就是跑到了数组最后一个元素的后面,然后强制转化为int再-1就是最后一个数9了。

8. 移形换位之术

下面有abc三个变量和4个相似的函数。

  • 你能说出使用这三个变量的值或地址作为参数分别调用这5个函数,在语法上是否正确吗?
  • 请找出下面的代码中的错误。
  • const intint 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 int 和int const没区别
const int *和int const *没区别
void func0(int n)是发送变量的值给n,a,b,c都√
void func1(int *n)发送地址给n,然后通过指针间接修改原变量的值,a,b,c都√
void func2(const int *n)向n发送一个地址,该指针所指向的是个常量,不能更改,a,b,c都×
void func3(int *const n)向n发送一个地址,然后n的值不能改变,a,b,c都错×
void func4(const int *const n)向n发送一个地址,n不能改变,n所指向的变量也不能改变,a,b,c都×

9. 听说翻转字母大小写不影响英文的阅读?

请编写convert函数用来将作为参数的字符串中的大写字母转换为小写字母,将小写字母转换为大写字母。返回转换完成得到的新字符串。

char *convert(const char *s){
char *str=(char*)s;
for(int i=0;i<strlen(s);i++){
if(str[i]>='A'&&str[i]<='Z'){ str[i] = str[i]+32;
}
if(str[i]>='a’ && str[i]<='z'){
str[i] = str[i]-32;
}
return str;
}
int main(void) {
  char *str = "XiyouLinux Group 2022";
  char *temp = convert(str);
  puts(temp);
}

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;
}

12对,3错
do{…}while(0)的作用是只循环一次;
可以使用指针。

11. 据说有个东西叫参数

你知道argcargv的含义吗?请解释下面的程序。你能在不使用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]);
}

argc是输入main的参数个数
argv是输入main的参数序列
argv0一般是表示程序名
若要遍历,即可while(argv++!=NULL)。

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;
}

func3中n为自动变量,函数结束后就被销毁,不可使用,func1中使用的是静态变量。到主函数时,函数调用也已结束,不可调用,func2中为mallloc,即动态内存分配,可跨函数使用。

13. 奇怪的输出

int main(void) {
  int data[] = {0x636c6557, 0x20656d6f, 0x78206f74,
                0x756f7969, 0x6e694c20, 0x67207875,
                0x70756f72, 0x32303220, 0x00000a31};
  puts((const char*)data);
}

这里date里存储的是16进制整形,随后又将其转化为char类型并输出,所以要根据数字对应的ascll码值进行转化,即两位对应一个字符,又因为c语言中存在大小端
大端存储模式:是指数据的低位字节序保存在内存的高地址中,而数据的高位字节序保存在内存的低地址中
小端存储模式:是指数据的低位字节序保存在内存的低地址中,而数据的高位字节序保存在内存的高地址中
所以最终打印时为倒序打印。

14. 请谈谈对从「C语言文件到可执行文件」的过程的理解

四个阶段:
(1)预处理阶段,预处理器(cpp)根据字符#开头的命令,修改原始的C程序。

(2)编译阶段,将c语言文件从高级语言转为汇编语言。

(3)汇编阶段,将汇编语言转化为二进制语言。

(4)链接阶段,将使用的头文件与本文件链接起来。

15. (选做) 堆和栈

你了解程序中的栈和堆吗?它们在使用上有什么区别呢?请简要说明。

栈是自动释放内存,自动分配,局部变量形参都是自动变量,在栈中,函数调用也是在栈中,根据变量定义的顺序,依次将变量函数压入栈中,调用结束依次释放
堆是malloc等函数分配内存,由程序要手动分配,手动释放,从分配到释放期间一直存在

16. (选做) 多文件

一个程序在不使用任何头文件的情况下,如何使用另一个文件中的函数。
使用exturn;

17. (选做) GNU/Linux与文件

  • 你知道如何在 GNU/Linux下如何使用命令行创建文件与文
    件夹吗?
  • 你知道GNU/Linux下的命令ls 的每一列的含义吗?
  • 你知道GNU/Linux下文件的访问时间、修改时间、创建时间如何查看吗?并简单说说他们的区别。
    mkdir创建目录
    touch创建文件夹

stat

恭喜你做完了整套面试题,快来参加西邮Linux兴趣小组的面试吧!

西邮 Linux兴趣小组面试时间:
2021年10月25日至2021年10月31日晚8点。
听说面试来的早一点更能获得学长学姐的好感哦。

我们在FZ103等你!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值