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

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

0.鼠鼠我啊,要被祸害了

  • Q:
    有 1000 瓶水,其中有一瓶有毒,小白鼠只要尝一点带毒的水,24 小时后就会准时死亡。
    至少要多少只小白鼠才能在 24 小时内鉴别出哪瓶水有毒?
  • A:
    将1000瓶水分别用二进制数表示,最多使用10位数,取10个空瓶子作为那10位,将对应位为1的水加入空瓶,最后取十只小鼠分别喝十瓶水,最后以小鼠的死亡给瓶子取值1,其它为0,可得毒水对应的二进制数。

1.先预测一下~

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

2.欢迎来到 Linux 兴趣小组

  • Q:
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);
}
  • A:
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("")));
}
//第一个%d=0;第二个%d=23
int diff = ptr0 - ptr1;
//diff=两地址差
printf("Pointer Difference: %d\n", diff);
}

3.一切都翻倍了吗

  • Q:
    ① 请尝试解释一下程序的输出。
    ② 请谈谈对 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));
}
  • A:
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));
    //sizeof(*&arr)=sizeof(arr)=7;sizeof(arr+0)=sizeof(long long)=8;sizeof(num=num2+4)=sizeof(short)=2,不对表达式求值
    printf("%d\n", sprintf(str, "0x%x", num) == num);
    //将字符串”0x522“写入str,“sprintf(str, "0x%x", num)==num”结果=0=%d
    printf("%zu\t%zu\n", strlen(&str[0] + 1), strlen(arr + 0));
    //strlen(&str[0]+1)=strlen(str+1)=从str[1]到'\0'(不包括)的字符个数=4;strlen(arr+0)=5
}

sizeof()对应数据类型在内存中所占用的字节数;
strlen()显示字符串的长度,即在`\0`前的字符个数。
③ sprintf()为输出函数,第一个参数为指向字符数组的指针,其它为格式化字符串;返回值为写入的字符总数,失败返回-1。

4.奇怪的输出

  • Q:
    程序的输出结果是什么?解释一下为什么出现该结果吧~
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:
    按顺序(补码):
    a=00100000;
    b=00011111;
    c=11111111;
    ch=11000000;
    输出:a=64,b=63,c=-1,ch=-128

5.乍一看就不想看的函数

  • Q:
    “人们常说互联网凛冬已至,要提高自己的竞争力,可我怎么卷都卷不过别人,只好用一些奇技淫
    巧让我的代码变得高深莫测。”
    这个 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)));
}
  • A:
    功能:求两数的和;
    实现:(a & b) << 1表示两数相加的进位a ^ b表示两数相加的原位。
    函数通过递归不断相加每次相加得到的进位和原位,没有进位时返回值。

6.自定义过滤

  • Q:
    请实现 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;
}
  • A:
int *filter(int *array, int length, Predicate predicate,int *resultLength)
{
    int s=0;
    for(int c=0;c<length;c++)
    {
        if(predicate(array[c]))s++;
    }
    *resultLength=s-1;
    int *fi=(int*)malloc(sizeof(int)*s);
    s=0;
    for(int c=0;c<length;c++)
    {
        if(predicate(array[c]))
        {
            fi[s]=array[c];
            s++;
        }
    }
    return fi;
}

7.静…态…

  • Q:
    ① 如何理解关键字 static?
    ② static 与变量结合后有什么作用?
    ③ static 与函数结合后有什么作用?
    ④ static 与指针结合后有什么作用?
    ⑤ static 如何影响内存分配?
  • A:
    ① static用来修饰变量的数据类型
    ② 与局部变量结合,使变量具有静态存储期;与全局变量结合,使其具有内部链接的文件作用域
    ③ 使函数成为静态函数
    ④ 使指针变量具有静态存储期
    ⑤ static修饰的变量在程序运行时分配内存,结束时释放

8.救命!指针

  • Q:
    数组指针是什么?指针数组是什么?函数指针呢?用自己的话说出来更好哦,下面数据类
    型的含义都是什么呢?
int (*p)[10];
const int* p[10];
int (*f1(int))(int*, int);
  • A:
    数组指针:指向数组的指针
    指针数组:数组元素为指针的数组
    函数指针:指向函数的指针,可通过指针使用函数
int (*p)[10];//指向含10个int元素的数组的指针
const int* p[10];//含有10个指向const数组的指针的数组
int (*f1(int))(int*, int);//返回值为指向返回值为int、参数为(int*,int)类型的函数的指针的函数声明

9.咋不循环了

  • Q:
    程序直接运行,输出的内容是什么意思?
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;
}
  • A:
    当argc溢出时,从最小值开始继续循环,到0时退出循环;i++ && j++ || k++;增加i和j,因为表达式i++ && j++的值为0,继续执行增加k;最终i=0,j=1,k=2

10.到底是不是 TWO

  • Q:
#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);
}
  • A:
    预处理后
int main(void) {
int nums = 1;
if(16 /2*2*2 == 2) //表达式为0
{
printf("I'm TWO(ノ>ω<)ノ\n");
} else {
int nums = ++nums*++nums*++nums+2*2*2;//块内创建nums并运算,出块后消失,块外nums依旧为1
}
printf("%d\n", nums);//输出1
}

11.克隆困境

  • Q:
    试着运行一下程序,为什么会出现这样的结果?
    直接将 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;
}
  • A:
    使s1中的指针也指向s2指向的内存空间,丢失了s1原本指向的内存空间,使其无法正确释放(free)
    解决方法:令以下代码取代s1 = s2;
strcpy(s1.name,s2.name);
s1.age=s2.age;

12.你好,我是内存

  • Q:
    作为一名合格的 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);
}
  • A:
struct structure {
    int foo;//占4字节
    union {
        int integer;
        char string[11];
        void *pointer;
    } node;//偏移4字节,占16字节
    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);
    //跳过前面的8个字节,按照char类型逐个读取字符,因为计算机为小端存储,所以读取顺序为
    //57 65 6c 63 6f 6d 65 20 74 6f 20 58 55 50 54 20 2c 20 77 65 6c 63
    //6f 6d 65 20 74 6f 20 58 69 79 6f 75 20 4c 69 6e 75 78 20 47 72 6f
    //75 70 20 5b 32 30 32 33 5d 00(不包括)
    //即Welcome to XUPT , welcome to Xiyou Linux Group [2023]
}

13.GNU/Linux (选做)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值