西邮linux兴趣小组2023面试题

西邮linux兴趣小组2023面试题

零、鼠鼠要被祸害了

用10位二进制编码为老鼠编号,每一瓶水代表一位上的数值,定为1,e.g.最后一位为一的喝一瓶,倒数第二位为1的喝一瓶…

最后会定位出有毒之水的编号。

算是一种2*10的坐标图确定坐标吧

自然界最容易找的就是0与1的状态,例如生与死。

一、输出自己的名字

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

此处考察的是函数的返回值,当我们在定义函数时设置一个有自己名字的数组,并在函数运行结束时返回这个数组的地址我们就可以实现输出,因为这个函数的返回值被定义为指针类型,在主函数里我们将这个数组的地址赋值给一个字符指针a,这样输出a的时候相当于输出整个数组,便可以输出我们的名字。

e.g

#include<stdio.h>
char *welcome() {
    char *arr="erthern";
    return arr;
}
int main(void) {
char *a = welcome();
printf("Hi, 我相信 %s 可以面试成功!\n", a);
printf("%d",a);
return 0;
}
//输出
Hi, 我相信 erthern 可以面试成功!

二、欢迎来到 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);
}

ptr0和ptr1是两个字符数组的指针,对二者解引用后均为数组首元素W故开始if条件下的语句。

这里考察printf函数返回值,其返回值是格式化输出的字符串长度即""内替换后所有内容视为字符串的长度。

diff是两个地址的差值。

//输出
Hello, Linux Group - 2023
Pointer Difference: 1431667044

三、一切都翻番了吗

① 请尝试解释一下程序的输出。
② 请谈谈对 sizeof()strlen()的理解吧。
③ 什么是 sprintf(),它的参数以及返回值又是什么呢?
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

输出:arr是一个字符数组,具体如下:

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));//第一个是对整个函数取地址又解引用,输出整个数组的内存大小,第二个是数组第一个元素的地址,第三个是short类型数据的大小为两个字节
printf("%d\n", sprintf(str, "0x%x", num) == num);//第一步是将num的十六进制数追加写入到str字符数组里,返回值是写入的字符总数即长度,不包括\0,然后与num判断大小,不相等故输出0
printf("%zu\t%zu\n", strlen(&str[0] + 1), strlen(arr + 0));    }//str被写入ox加三位(因为出short类型num转换成十六进制只有三位),第一个取str首元素地址的下一个元素的地址开始计算,只有4的长度,第二个是中间有一个\0,只读取到前一个元素,所以是5.

sizeof:变量占用内存的空间大小

strlen:求字符串长度

sprintf:将格式化输出内容转而写入字符数组,返回写入长度

四、奇怪的输出

程序的输出结果是什么?解释一下为什么出现该结果吧~
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);
}

这里考察的是位运算

异或可视为不进位加法

&可用于取模运算,比%快,少了数据转换的复杂度

五、乍一看就不想看的函数

    这道题的考察点有三个,一为函数的定义,二为逻辑运算符,三为数据在内存的储存形式
	此函数的功用为实现两个数据的加法。
这个 func()函数的功能是什么?是如何实现的?
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)));
}

(1)&为按为与,<<是向左缩进,^按位异或

(2)逻辑运算中参与运算的数据是二进制补码的形式

(3)采用递归思想

即a^b后,0+0=0,1+1=0,0+1=1

同时,a&b将1+1得到的进位1提取,<<1提前一位

当没有进位时便得到了a+b

六、自定义过滤

请实现 filter()函数:过滤满足条件的数组元素。
提示:使用函数指针作为函数参数并且你需要为新数组分配空间。
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};
int length = sizeof(array) / sizeof(array[0]);
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;
}

要自定义过滤数组,需要定义filter()函数。

此处涉及的知识点:1.函数的定义

​ 2.数据类型的定义

过程:

1、定义一个函数指针predicate作为筛选标准

2、为输出的数组提供内存

3、将符合的数据输出

如下是代码补完:

#include<stdio.h>
#include<stdlib.h>
typedef int (*Predicate)(int);
int *filter(int *array,int length,Predicate predicate,int *resultlength){
    int i=0,t=0;
    int *p=(int*)malloc(sizeof(int)*length);
        for(i;i<length;i++){
        if(predicate(array[i])) {
            p[t]=array[i];
            t++;
            }
        }
    *resultlength=t;
    return p;
}
int isPositive(int num){
    return num>0;
}
int main(void){
    int array[]={-3,-2,-1,0,1,2,3,4,5,6};
    int length=sizeof(array)/sizeof(array[0]);
    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;
}

七、静态

① 如何理解关键字 static?
② static 与变量结合后有什么作用?
③ static 与函数结合后有什么作用?
④ static 与指针结合后有什么作用?
⑤ static 如何影响内存分配?

修饰变量时将变量从栈区的变量移到静态区,使其生命周期延续到整个程序(比如在循环内定义的变量值可以脱离循环使用)。

若修饰全局变量或者函数则会将其外部属性转换成内部属性。

八、救命!指针!

数组指针是什么?指针数组是什么?函数指针呢?用自己的话说出来更好哦,下面数据类
型的含义都是什么呢?
int (*p)[10];
const int* p[10];
int (*f1(int))(int*, int);

1、数组指针是指向数组的指针,第一个就是数组指针,定义了一个int类型指针p指向一个有十个元素的数组,不知数组名

2、指针数组是存储指针变量的数组,第二个将整个数组p定义成了指针,const修饰后都指向常量

3、函数指针是指向函数体的指针,f1指针指向一个两个int类型形参的指针

九、咋不循环了

#include<stdio.h>
#include<stdlib.h>
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;
}
[1]
i=0,j=1,k=2

argc是命令行参数的技术器,至少为1,不断自增后溢出再增到0,退出循环

先计算j和k的或,虽然j=0但是k不等于0,故为真,&&前面i也不为0,后缀++要语句运行结束才计算。

十、到底是不是TWO

#include<stdio.h>
#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%d\n",nums,magic_cal(nums,2));
}

nums的生命周期只持续在if判断里面,出来还是1

且当多个++nums相乘时运算顺序会产生混乱

不知道每一个nums 的值是多少

十一、克隆困境

试着运行一下程序,为什么会出现这样的结果?
直接将 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;
}

直接赋值是将s2的地址直接赋值给s1因此两个都输出s2的数值

此时释放的内存只有s2的name,造成了s1.name的内存泄露

十二、你好我是内存

作为一名合格的 C-Coder,一定对内存很敏感吧~来尝试理解这个程序吧!
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);
}//将arr的指针与结构体匹配从string的地址开始翻译,00为止

此处考察的是内存储存的大小端模式,思路参见2022年纳新题第十二题

//输出
Welcome to XUPT , welcome to Xiyou Linux Group [2023]

大小端存储模式

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值