西邮linux兴趣小组2023年面试题题解

0鼠鼠我啊,要被祸害了

将所有药瓶编码后转为二进制,(1000)10=(1111101000)2,故需要十只老鼠,接着一次处理各个二进制编码,对为1的位老鼠喂药,对为0的老鼠不作处理,24小时后,死亡位为1,存活位为0,将数字转化为十进制就是有毒的药水。

1.先预测一下~

welcome函数中返回指向字符串的指针,并在主函数中打印出字符串。

char *welcome() {
 // 请你返回自己的姓名
}
int main(void) {
 char *a = welcome();
 printf("Hi, 我相信 %s 可以面试成功!\n", a);
 return 0;
}

首先定义一个welcome函数返回字符串的指针,然后在主函数中定义一个指针a赋值为welcome的返回值,并用%s打印出来。

2欢迎来到 Linux 兴趣小组

int main(void) {
 char *ptr0 = "Welcome to Xiyou Linux!";
 char ptr1[] = "Welcome to Xiyou Linux!";
 if (*ptr0 == *ptr1) {
 printf("%d\n", printf("Hello, Linux Group - 2%d", printf("")));
 }
 int diff = ptr0 - ptr1;
 printf("Pointer Difference: %d\n", diff);
}

首先声明指向"Welcome to Xiyou Linux!" 的指针ptr0,在声明内容为"Welcome to Xiyou Linux!"的数组ptr1,利用if语句比较两个数组首字符后发现相等,于是打印,先从最内层开始运行,发现返回值为0,将次外层的%d转换为0,由于此处有23个字符,所以给最外层返回23,于是最终输出为Hello, Linux Group - 2023`。

3一切都翻倍了吗

int main(void) {
 char arr[] = {'L', 'i', 'n', 'u', 'x', '\0', '!'}, str[20];
 short num = 520;
 int num2 = 1314;
    printf("%zu\t%zu\t%zu\n", sizeof(*&arr), sizeof(arr + 0),
 sizeof(num = num2 + 4));
 printf("%d\n", sprintf(str, "0x%x", num) == num);
 printf("%zu\t%zu\n", strlen(&str[0] + 1), strlen(arr + 0));
}

程序的输出如下

7 8 2 0 4 5

  1. strlen()包含于<string,h>中,一般用于返回字符串长度,是一个函数;而sizeof()是一个运算符,括号中可以加入变量类型或者变量,返回该变量类型所占字节大小。若加入数组名,则返回数组所占字节数,即数组长度*数组元素所占空间的大小。
  2. sprintf()将数据写入字符串中,第一个参数为待写入的目标字符串地址,后面的参数与printf相同,返回值为写入字符的总数(不包含控空字符)。若读取失败则返回负值。
  3. 解释程序的输出:*&arr相当于在sizeof中加入数组名,arr + 0返回值为arr的元素所占字节数,num = num2 + 4的返回值为short类型所占字节数。在printf("%d\n", sprintf(str, "0x%x", num) == num);中sprintf返回4,不等于num,,故給最前面的%d返回0。最后一行strlen()从str数组的第二项开始读,此时str数组中共有五个字符,故返回4。第二个从第一项开始读,故返回5。

4.奇怪的输出

int main(void) {
 char a = 64 & 127;
 char b = 64 ^ 127;
 char c = -64 >> 6;
 char ch = a + b - c;
 printf("a = %d b = %d c = %d\n", a, b, c);
 printf("ch = %d\n", ch);
}

输出如下

a = 64 b = 63 c = -1
ch = -128

(64)10=(1000000)2,(127)10=(1111111)2

64与127按位与运算的结果为64,,按位异或运算的结果为63,-64向右移位6位后结果为-1,最终ch的运算结果为-128.

5乍一看就不想看的函数

int func(int a, int b) {
 if (!a) return b;
 return func((a & b) << 1, a ^ b);
}
int main(void) {
 int a = 4, b = 9, c = -7;
 printf("%d\n", func(a, func(b, c)));
}
  • 要实现两个数的加法,可以利用异或和按位与运算实现。将两数的异或结果与直接加对比发现,只差二进制进位信息。而两数的按位与运算结果与进位信息只差左移一位,故将其左移一位。
  • 当进位信息为0时,异或结果即加法结果。故使用func函数递归,当a为0时,返回结果。
  • 图中为4+9+(-7)的结果。

6自定义过滤

typedef int (*Predicate)(int);
int *filter(int *array, int length, Predicate predicate,int *resultLength); /*补全函数*/
int isPositive(int num) { return num > 0; }
int main(void) {
 int array[] = {-3, -2, -1, 0, 1, 2, 3, 4, 5, 6};//array数组
 int length = sizeof(array) / sizeof(array[0]);//length=10
 int resultLength;
 int *filteredNumbers = filter(array, length, isPositive,&resultLength);
 for (int i = 0; i < resultLength; i++) 
 {
     printf("%d ", filteredNumbers[i]);
 }
 printf("\n");
 free(filteredNumbers);
 return 0;
}

补全后的函数如下:

#include <stdio.h>
#include <stdlib.h>
typedef int (*Predicate)(int);
int *filter(int *array, int length, Predicate predicate,int *resultLength); /*补全函数*/
int isPositive(int num) { return num > 0; }
int main(void) {
 int array[] = {-3, -2, -1, 0, 1, 2, 3, 4, 5, 6};//array数组
 int length = sizeof(array) / sizeof(array[0]);//length=10
 int resultLength;
 int *filteredNumbers = filter(array, length, isPositive,&resultLength);
 for (int i = 0; i < resultLength; i++) 
 {
     printf("%d ", filteredNumbers[i]);
 }
 free(filteredNumbers);
 return 0;
}
int *filter(int *array,int length,Predicate predicate,int *resultlength)
{
     int *arr=(int *)malloc(sizeof(int)*length);
     int numb=0;
     for(int i=0;i<length;i++)
     {
        if(predicate(array[i]))
        {
            arr[numb]=array[i];
            numb++;
        }
     }
        *resultlength=numb;
        return arr;
     
}

该函数为定义一个能过滤数组大于0的元素的元素,为此使用filter()在传入四项对应的参数后,在创建一个新数组arr来存储大于0的元素,并将元素个数传递回主调函数。

7静…态…

  • static修饰静态变量
  • static修饰局部变量时会改变该变量的生命周期(与程序一致),变得不会销毁变量,一直有效。
  • static修饰全局变量时会改变其链接属性,从外部链接改为内部链接,作用域变小。
  • static修饰函数时同理,变为内部链接,其他源文件不能使用该函数。
  • static修饰指针时也会使其作用域变小,生命周期不变。
  • static修饰的东西,在编译时就会为其分配内存空间,直到程序结束时才销毁。

8救命!指针!

  • 数组指针是指向数组的指针。eg: int (* pi) [4]

  • 指针数组是内部元素均为指针的数组。eg:int * pi [4]

  • 函数指针是指向函数的指针。eg: int (*func) (int)

  • int (*p)[10];
    

    声明了一个指向含十个int类型元素的指针p。

  • const int* p[10];
    

​ 声明了一个不可更改指向的值的内含十个指针元素的数组p。

  • int (*f1(int))(int*, int);
    

    将f1函数的返回值设为指向参数为 int*,int且返回值为int的函数指针。

    9咋不循环了

    int main(int argc, char* argv[]) {
     printf("[%d]\n", argc);
     while (argc) {
     ++argc;
     }
     int i = -1, j = argc, k = 1;
     i++ && j++ || k++;
     printf("i = %d, j = %d, k = %d\n", i, j, k);
     return EXIT_SUCCESS;
    }
    
    • 该函数中,argc是传递给命令行参数的数量,至少为1,是它本身。argv是一个指向字符串的指针,每个字符串是一个命令行参数,地一个元素是程序的名称。
    • int类型为32位,argc由0开始递增,到最大时变为最小的负数,并递增到0退出循环。
    • 此时j=0,0与-1与结果为0,0与1或结果为1,并打印出递增后的结果,为0,1,2。

    10.到底是不是 TWO

    #define CAL(a) a * a * a
    #define MAGIC_CAL(a, b) CAL(a) + CAL(b)
    int main(void) {
     int nums = 1;
     if(16 / CAL(2) == 2) {
     printf("I'm TWO(ノ>ω<)ノ\n");
     } else {
     int nums = MAGIC_CAL(++nums, 2);
     }
     printf("%d\n", nums);
    }
    

    宏定义相当于直接带入,在if语句中没有给立方运算带括号,无效进入else语句,然而在if语句内创建的变量在if语句外是失效的,所以nums还是最开始定义的1,最后打印出来1。

    11克隆困境

    试着运行一下程序,为什么会出现这样的结果? 直接将 s2 赋值给 s1 会出现哪些问题,应该如何解决?请写出相应代码。

    struct Student {
     char *name;
     int age;
    };
    void initializeStudent(struct Student *student, const char *name,
     int age) {
     student->name = (char *)malloc(strlen(name) + 1);
     strcpy(student->name, name);
     student->age = age;
    }
    int main(void) {
     struct Student s1, s2;
     initializeStudent(&s1, "Tom", 18);
     initializeStudent(&s2, "Jerry", 28);
     s1 = s2;
     printf("s1 的姓名: %s 年龄: %d\n", s1.name, s1.age);
     printf("s2 的姓名: %s 年龄: %d\n", s2.name, s2.age);
     free(s1.name);
     free(s2.name);
     return 0;
    }
    

    运行结果为

    s1 的姓名: Jerry 年龄: 28
    s2 的姓名: Jerry 年龄: 28
    
    • 首先封装一个结构体类型Student,其中包含了一个char字符串和一个int类型值。
    • 在initializeStudent函数中传入Student的指针,字符串指针和int值,手动为naem分配空间后将name指针指向它,然后将name和age加入结构体中。
    • 主函数在声明两个Stduent类型后分别封装入元素,然后将s1的值修改为s2,此时&s1与&s2共同指向s2,打印。
    • 随后释放空间时由于两指针相同,多free了一次,原来的s2还没释放。释放完还要给指针赋值null。

    12你好,我是内存

    struct structure {
     int foo;
     union {
     int integer;
     char string[11];
     void *pointer;
     } node;
     short bar;
     long long baz;
     int array[7];
    };
    int main(void) {
     int arr[] = {0x590ff23c, 0x2fbc5a4d, 0x636c6557, 0x20656d6f,
     0x58206f74, 0x20545055, 0x6577202c, 0x6d6f636c,
     0x6f742065, 0x79695820, 0x4c20756f, 0x78756e69,
     0x6f724720, 0x5b207075, 0x33323032, 0x7825005d,
     0x636c6557, 0x64fd6d1d};
     printf("%s\n", ((struct structure *)arr)->node.string);
    }
    

    结果如下

    Welcome to XUPT , welcome to Xiyou Linux Group [2023]
    

    structure结构体的最大的对齐数为8,最后一行中首先将arr数组强制转换成指向structure的指针,然后解引用到node联合体中的string数组中,foo首先占前面四个字节(小端序存储字符),然后union对齐到第八个字节处,由57开始打印,最终输出为图上,一直到空字符\0结束。

13.GNU/Linux (选做)
注:嘿!你或许对 Linux 命令不是很熟悉,甚至你没听说过 Linux。但别担心,这是选做题,了解
Linux 是加分项,但不了解也不扣分哦!
你知道 cd 命令的用法与 / . ~ 这些符号的含义吗?
请问你还懂得哪些与 GNU/Linux 相关的知识呢~

cd加目录名为进入或切换到该文件夹中。
当表示相对路径时,路径名前面不是/或者~,而表示绝对路径时,即从根目录或者家目录开始的路径,在路径名前面加/或~。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值