西邮Linux兴趣小组2022纳新题解

目录

0.我的计算器坏了?!

1.printf还能这样玩? 

 2.你好你好你好呀!

3.换一个变量名不行吗?

 4.内存对不齐

 5.Bitwise

6.英译汉 

7.汉译英 

8.混乱中建立秩序 

9.首脑并用 

10.给你我的指针,访问我的心声 

11.奇怪的参数 

12.奇怪的字符 

13.小式宏刀 

14.GNU/Linux命令(选做) 


0.我的计算器坏了?!

 2的10次方是1024,1000是10的3次方,lg1000=3,1000是四位数所以对于2的10000取lg,lg2^{10000}≈3010,所以lg2^{10000}是十进制的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("")));
}

if括号内有左右两个括号是两个判断语句,第一个括号判断5<2是假的为0,第二个括号中是5>2是真的是1,if所判断的条件是0<1为假,进行else语句这个printf语句在上一篇2023年的第2题有详细解释,在这不进行过多说明。

 2.你好你好你好呀!

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

p0是数组首地址,p1是指针所指地址,p0!=p1返回值是0,strcmp函数(返回值是两个字符串ASCII之差,如果相同返回0)比较两个字符串,p2的下一个字符未知,是随机值,第一行printf的打印结果是p0==p1: 0, strcmp(p0,p2): -72,第二行和第三行考察对于sizeof和strlen的认识,在上一篇23年题解的第三题有详细解释,另外对于sizeof(*p2)在64位操作系统中指针字节长度都是8,所以打印结果是8,在这只放出二三行打印结果。

sizeof(p0): 12, sizeof(p1): 8, sizeof(*p2): 1 
strlen(p0): 11, strlen(p1): 11

3.换一个变量名不行吗?

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

 在块作用域之外定义的变量是全局变量,生命周期是文件作用域。

在块作用域之内定义的变量是局部变量,生命周期是块作用域,离开所在的块作用域就会被销毁。

在这里有三个printf分三次打印,第一次为test函数里面的第一个printf,在这个语句之前的int a=a+1;在此块作用域中重定义并且未初始化就进行使用是不规范的行为,对于不同的编译器打印结果不同,;出了这个作用域a就会被销毁,第二个printf是int a=1;a+=1;之后的值所以打印a = 2,这个数值在出了函数之后就会被销毁,第三个main函数中的printf是全局变量的a是3所以打印a = 3

 4.内存对不齐

#include<stdio.h>
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)); 
    //sizeof (UNION) = 24
    printf("sizeof (STRUCT) = %zu\n", sizeof(STRUCT));
    //sizeof (STRUCT) = 40
    return 0;
}

这道题涉及到内存对齐和结构体与联合体,对于结构体 

  1. 第一个成员在结构体变量偏移量为0的地址处
  2. 其他成员变量要对齐到对齐数的整数倍的地址处
  3. 对齐数=编译器默认的一个对齐数与该成员大小中的较小值。
  4. 结构体总大小为最大对齐数的整数倍 

 对于联合体,各成员共用一块内存空间,并且同时只有一个成员可以得到这块内存的使用权,各变量共用一个内存的首地址。

  1. 一个union变量的总长度至少能容纳最大的成员变量
  2. 满足所有成员变量类型大小的整数倍

 对于联合体UNION至少容纳最大i[5],是4*5=20字节,与对齐数有关,我的运行结果是sizeof (UNION) = 24,是8位对齐,若是4位对齐则是sizeof (UNION) = 20,应为对齐数的整数倍。对于STRUCT,第一个int占4,第二个UNION占24,第三个double占8和是36不满足8的倍数,占用下一个4,最终结果是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);
}

 本题考察原码反码补码以及几种位运算,在上一篇23年题解第四题中有详细解释,这里直接给出计算过程

#include<stdio.h>
int main(void) {
    unsigned char a = 4 | 7;
    //00000100 | 00000111 = 00000111(7)
    a <<= 3;
    //00000111 << 3 = 00111000(56)
    unsigned char b = 5 & 7;
    //00000101 & 00000111 = 00000101(5)
    b >>= 3;
    //00000101 >> 3 = 00000000(0)
    unsigned char c = 6 ^ 7;
    //00000110 ^ 00000111 = 00000001(1)
    c = ~c;
    //无符号字符型范围是0~256
    //~是取反码 00000001的反码是11111110(254)
    unsigned short d = (a ^ c) << 3;
    //00111000 ^ 11111110 = 11000110
    //11000110 << 3 = 00110000(48)
    signed char e = -63;
    //有符号型第一位是符号位0正1负
    //e == 10111111
    e <<= 2;
    //先转换为补码再运算,正数补码是本身,负数补码是反码+1
    //e补码为11000001
    //11000001 << 2 = 00000100(4,对应16进制0x4)
    printf("a: %d, b: %d, c: %d, d: %d\n", a, b, c, (char)d);
    //a: 56, b: 0, c: 254, d: 48
    printf("e: %#x\n", e);//转换16进制
    //e: 0x4
    return 0;
}

6.英译汉  

1.char *const p
2.char const *p
3.const char *p

 对于这道题可以看const与*谁在前谁在后const在前即为内容不可改变,*在前即为地址不可改变,

  1. 是一个字符型指针,所指的地址不可改变。
  2. 和3.是一个字符型指针,所指向的内容不可改变但是可以改变*p指向的地址。

7.汉译英 

  1.  int *p[10]
  2. int (*p)[10]
  3. int (*p[3])(int a)

8.混乱中建立秩序 

选择排序循环主体
for(i=0;i<len-1;i++)
    {
        t=i;
        for(j=i+1;j<len;j++)
        {
            if(a[j]<a[t])
            {
                t=j;
            }
        }
        if(t!=i)
        {
            int y=a[i];
            a[i]=a[t];
            a[t]=y;
        }
    }
冒泡排序循环主体
for(i=0;i<len-1;i++)
    {
        for(j=0;j<n-1-i;j++)
        {
            if(a[j]>a[j+1])
            {
                int y=a[j];
                a[j]=a[j+1];
                a[j+1]=y;
            }
        }
    }

9.手脑并用 

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

 代码如下打印结果为str = wELCOME TO xIYOU lINUX gROUP 2022

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
char* convertAndMerge(char words[2][20])
{
    int len1=strlen(words[0]);//分别计算长度
    int len2=strlen(words[1]);
    //申请内存
    char *marge = (char*)malloc((len1+len2+1)*sizeof(char));
    //拼接两个字符串为一个字符串
    strcpy(marge,words[0]);
    strcat(marge,words[1]);
    //转换大小写
    int i;
    for(i=0;i<len1+len2;i++)
    {
        if(marge[i]>='a' && marge[i]<="z") marge[i]-=32;
        else if(marge[i]>='A' && marge[i]<="Z") marge[i]+=32;
    }
    return marge;
}
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);
}

10.给你我的指针,访问我的心声 

#include<stdio.h>
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]);
        }
        printf("\n");
    }
    return 0;
}
输出结果是
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

对于这段代码 temp<arr[5]会使对于二维数组的每一位都赋值,第一次从0-24对25个数据赋值,第二次对25-44对2-5行赋值,第三次从45-59对3-5行进行赋值,以此类推,后面的赋值会覆盖住前一次的赋值最终得到打印的结果。

11.奇怪的参数 

#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;
        }
    }
    return 0;
}
  1.  argc表示传递给程序命令行参数的数量,至少是1,第一个参数始终是程序的名称。
  2. argv是一个指向字符串数组的指针,每个字符串表示一个命令行参数。

 对于int型变量正向超出范围再一次会从最小值开始,所以argc会有小于0的时候,不会出现死循环,打印的argv[0]为程序路径

12.奇怪的字符 

#include<stdio.h>
#include<string.h>
int main(int argc, char **argv) {
    int data1[2][3] = {{0x636c6557, 0x20656d6f, 0x58206f74},
                       {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);
    //Welcome to Xiyou Linux Group 2022
    return 0;
}

 本题考查对于大小端的认识和进制的转换,目前大部分电脑都是小端储存,即数据从后往前放,这道题与上一篇2023年的12题的解析存在很多相同知识点,对于*a是由data1中的第一个数据的57(16进制)转换为10进制是87对应字母W,然后依次是65,6c,转化之后经过拷贝和拼接,就构成了最终的打印结果。

13.小式宏刀 

#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);
    //x = 2, y = 1, tmp = 1
    //进行了交换,temp是a的值1
    if (x > y) SWAP(x, y, tmp);//现在x=2, y=1条件为真
    //再次交换,temp是后来a的值2
    printf("x = %d, y = %d, tmp = %d\n", x, y, tmp);
    //x = 1, y = 2, tmp = 2
    SWAPWHEN(x, y, tmp, SQUARE(1 + 2 + z++ + ++w) == 100);
    //SQUARE()相当于1 + 2 + z++ + ++w * 1 + 2 + z++ + ++w
    //先进行自加然后乘法然后加减然后判断结果是29条件为假不执行交换的第一句
    //a=b=2;b=tmp=2;所以下面x和y都是2
    printf("x = %d, y = %d\n", x, y);
    //x = 2, y = 2
    printf("z = %d, w = %d, tmp = %d\n", z, w, tmp);
    //z与w分别有两个自加都为5
    //z = 5, w = 5, tmp = 2
    printf("%d",SQUARE(1 + 2 + z++ + ++w));
    return 0;
}

 宏是直接的文本替换,并不会主动加括号是一个要点,解析都在代码里了。

14.GNU/Linux命令(选做) 

  •  ls :列出当下目录的子目录或文件
  • rm:remove移除该文件
  • whoami :用于显示自身用户名称
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值