2020西邮linux兴趣小组纳新题题解

1. 请试着解释其输出。

int main(int argc , char *argv[]) {
  unsigned char a = 255;
  char ch = 128;
  a -= ch;
  printf("a = %d ch = %d\n", a, ch);
}
  • 结果为127 -128
  • 注意无符号类型unsigned char,a=255-128=127;
  • 因为ch是char类型,有符号,表示范围为 -128~127,此时已经超过其范围,因此结果为-128(具体见下图)
    在这里插入图片描述

2. 下面代码的运行输出结果是什么,并说说你的理解。

int main(int argc, char *argv[]) {
  char *str = "Xi You Linux Group 20";
  printf("%d\n", printf(str));
  return 0;
}
  • 涉及到一个知识点:printf的返回值
  • 返回值是指printf输出的字符数量(包括数字,字母,标点符号,空格等)
  • 由此可得输出为Xi You Linux Group 2021

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

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
  • 前两个不解释
  • 第三个:
  unsigned int f = 33554433;//在(0 ~ 4 294 967 295)的范围内
  *(int *)&f >>= 24;//将f进行位运算中的右移24位,结果为2
  *(int *)&f = *(int *)&f + '?';//2+63(?的阿斯克码)=65(A的阿斯克码)
  • *(int*)&f=f (相当于取 f 的地址让其强行转换为指针并指向它自己)

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,&a[0],&a[0][0]地址都相同,但是&a表示整个数组的地址,&a[0]表示数组第一行的地址,&a[0][0]表示第一行第一列的地址(也就是首元素的地址)

  • &a+1表示整个数组的地址加上2* 2*int(一个数组)类型大小的地址(相当于&b

  • &a[0]+1表示第一行地址加上一个2*int(一行)类型大小的地址(相当于&a[1]

  • &a[0][0]+1表示首元素地址加上一个int类型的大小的地址(相当于&a[0][1]

多卷一些?戳!


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的指针从而输出array数组中的值
  • 问题:array在函数作用完后会自动释放内存而带不回返回值,因此p会找不到此数组的地址,使p成为野指针
  • 解决
#include<stdio.h>
#include<stdlib.h>
int* get_array() 
{
	n=1121;
    int*array=(int*)malloc(sizeof(int)*n);
    int*t=array;
    for (int i=0; i<sizeof(int)*n/sizeof(int); i++,array++)
        *array = i;
    return t;
}
int main(int argc, char *argv[]) 
{
	n=1121;
    int *p=get_array();
    for(int i=0;i<n;i++,p++)
        printf("%d ",*p);
    
    return 0;
}

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;
}
  • 先解释 %zu ,它和%d的区别在于:%d输出int型,%zu输出size_t型,而size_t在库中定义为unsigned int,即:一个是整型,一个是无符号整型
  • 再看结果16 8 25 24 (编译器在64位下运行)
  • 前两个不解释
  • 第三个和第四个大同小异,这里只解释最后一个:在x中\t \106(三位八进制) \b分别占一个字节,相当于char类型,因此结果为15(X~p)+1+1+1(F)+1+5=24

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;
} 
  • 解析如下
int add(int *x, int y) 
{
    return *x = (*x^y) + ((*x&y)<<1);//每进函数一次a+1,b+1
}
int a;//全局变量初始化为0
int main(int argc, char *argv[]) 
{
    int b = 2020;
    if(add(&b, 1) || add(&a, 1))//进入
    {
        printf("XiyouLinuxGroup%d\n", b);//b=2021
        printf("Waiting for y%du!\n", a);//a=0
       //a=0说明add(&a,1)并没有被执行,在逻辑或时若满足第一个表达式,会发生短路现象
       //这样会提高计算机的运算效率
    }
    if(add(&b, 1) && a++)//逻辑和时add(&b,1)和a++都被执行
    //不会进入if语句,因为a++表达式是先运算再自增,在进行逻辑和的时候a还是0
    {
        printf("XiyouLinuxGroup%d\n", b);
        printf("Waiting for y%du!\n", a);
    }
    
    return 0;
}
  • 结果如下
    在这里插入图片描述

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);
}
  • 输出的结果为输入的数字
  • 输入一个整数在被强制转换为指针类型c 所指向的地址(就是&a,也是c),
    而因为原本c就是a的地址(c=&a),相当于(int * )c指向a的地址并且赋值c,就是a=c

10. 请问一个C语言程序从源代码到可执行文件中间会进行哪些过程,你能简单描述一下每个环节都做了什么事情吗?

在这里插入图片描述


11. 请解释一下这行代码做了什么?

puts((char*)(int const[]){
0X6F796958,0X6E694C75,0X72477875,
0X3270756F,0X313230,0X00000A
});
  • 这里涉及到一个知识点:大端法,小端法
  • 在了解这个之前,先了解一个专业词:字节序。字节序,顾名思义就是字节的排列顺序,而计算机中既可以从高位到低位进行排列,也能从低位到高位进行排列
  • 现在再来看大端法、小端法:假设有数据0x12345678,左边为高字节,右边为低字节。将高字节的数据放在低地址,便是大端法;反之,为小端法

  • 下图,上面一排为字节的存放地址,从左到右,地址由低到高;下面一排为字节,分别存放在不同的地址中
  • 大端法
    在这里插入图片描述
  • 小端法
    在这里插入图片描述

  • 一般家庭计算机所使用的为小端法,因此根据以上知识并查阅阿斯克码表可得,该程序的输出为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;
}
  • 运用了选择排序的思想
  • 这里需要注意的是:fgets()函数
  • fgets() 函数中的 size 如果小于字符串的长度,那么字符串将会被截取;如果 size 大于字符串的长度则多余的部分系统会自动用 ‘\0’ 填充。

13. 用循环和递归求Fibonacci数列

你觉得这两种方式那种更好?说说你的看法。如果让你求Fibonacci数列的第100项,你觉得还可以用常规的方法求解吗?请试着求出前100项的值(tip大数运算)。

全题终。。。。。。

点个赞再走呗ヾ(•ω•`)o

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值