西邮Linux小组22-20纳新面试题目及题解

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

三次打印

  1. 打印 随机值 因为在其作用域中 a变量仅声明 未进行定义
  2. 打印 a = 2 此处的a是test函数中定义的a
  3. 打印 a= 3 此处的a是全局变量a

4. 内存对不齐

unionstruct各有什么特点呢,你了解他们的内存分配模式吗。

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的作用。

  1. char *const p
  2. char const *p
  3. 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给出下面的定义:

  1. 含有10个指向int的指针的数组。
  2. 指向含有10个int数组的指针。
  3. 含有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. 箱子的大小和装入物品的顺序有关

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

同 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. 移形换位之术

下面有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的问题 前面有解释 和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. 据说有个东西叫参数

你知道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]);
}

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 重新录入题目原件。好人一生平安。

注:

  1. 本题仅作为面试有限参考
  2. 为节省版面,省去所有#include指令
  3. 题目难度与序号无关
  4. 若无特殊声明,均假设在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
  1. 当右值的数据长度大于左值的数据长度时 赋值过程将发生截断
  2. 当同等长度的无符号数和有符号数进行运算时 会将有符号数转化为无符号数

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 = 0x7ffcfe86ddf0     &a[0] = 0x7ffcfe86ddf0          &a[0][0] = 0x7ffcfe86ddf0
      &a+1 = 0x7ffcfe86de00   &a[0]+1 = 0x7ffcfe86ddf8        &a[0][0]+1= 0x7ffcfe86ddf4
    

数组的实质–>存放数据的地址

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命令操作有


DONE

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值