西邮 Linux 兴趣小组 2019 纳新试题

        1.下面代码段将打印出多少个‘=’?运用相关知识解释该输出。

int main(int argc, char *argv[]) {
 for (unsigned int i = 3; i >= 0; i--)
 putchar('=');
}

无数个‘=’,

        这是个简单的for循环,它的条件是i>=0,i初始值为3,循环迭代条件是i--,看似没问题,实际上,i的数据类型是unsigned int,没有负值,永远大于0.所以会打印出无数个‘=’。

2.下列三种交换整数的方式是如何实现交换的?

/* (1) */ int c = a; a = b ; b = c;
/* (2) */ a = a - b; b = b + a; a = b - a;
/* (3) */ a ^= b ; b ^= a ; a ^= b;

第一个是通过中间变量,暂时储存一个数的值,来达到交换数值的目的的。

第二个是通过算法,通过计算将a和b的值转化成一个算数式子储存,以便交换。

第三种是通过异或的原理,a^b^a的值为b,a^b^b的值是a.

3.有如下代码段所示的函数 f,当我们执行该函数时,会产生什么样的输出结果?在同一程序中 多次执行该函数,输出结果是否一致?

void f() {
    static int a = 0;
    int b = 0;
    printf("%d, %d\n", ++a, ++b);
}

++a是先加,再计算,a++是先计算在加。

对于多次执行该程序,结果不同,a的值一直变大,b一直是1.原理我上篇博客的第四题说过,就不再在此赘续了。

4.下面程序段的输出是什么?请解释该现象并说出与之相关尽可能多的知识。

int main(void) {
    printf("%d\n", printf("Xiyou Linux Group2%d", printf("")));
}

结果:Xiyou Linux Group2019

这个是printf的返回值的原因,printf的返回值是它所包含的字符的个数。(再多想不到了)

5.执行下面的代码段,会输出什么?请试着解释其原因,并叙述相关知识。

int main(int argc, char *argv[]) {
    char ch = 255;
    int d = a + 1;
    printf("%d %d", ch, d);
}

我觉得a好像少加了个‘’,应该是

int d = 'a' + 1;

输出结果:-1 98

这道题考的是ascii码,ascii一般是127位,255是拓展出来的。

对于255:以int来看,它的原码为1111 1111,再以char来看,char类型一个字节,正好占满 ,计算出补码是 000 0001 ,所以输出-1.

对于d:a的ascii码为97,“+1”后就是98.

6.执行以下代码段,将产生什么样的输出?请对输出加以解释,并手动计算代码中 t 的值。

int main(int argc, char *argv[]) {
    char x = -2, y = 3;
    char t = (++x) | (y++);
    printf("x = %d, y = %d, t = %d\n", x, y, t);
    t = (++x) || (y++);
    printf("x = %d, y = %d, t = %d\n", x, y, t);
}

结果为:x = -1, y = 4, t = -1
               x = 0, y = 5, t = 1

        位运算符”|“,它的作用:是在二进制下对两个数的同一位进行运算,1|1=1 , 1|0=1 , 0|0=0(直接上),所以++x与y++都要运算(记得补码),++x是先加再位运算,y++是位运算完后再加,所以第一次运算完后t为-1,

        11111111 11111111 11111111 11111110  

        00000000 00000000 00000000 00000011

结果:11111111 11111111 11111111 11111111

转换成原码:10000000 00000000 00000000 00000001//-1

        逻辑运算符||,作用:两个中至少有一个为真,就返回真,否则假。

++x结果为0,假,所以继续判断y++,y结果为4,为真,所以结果为真,返回1。,即t=1。

7.下面代码段的输出结果是什么?输出该结果的原因是?

#define X a+b
int main(int argc, char *argv[]) {
 int a = 1, b = 1;
 printf("%d\n", X*X);
}

        结果为3,宏是简单的替换,即输出结果是printf(“%d\n”,1+1*1+1)。(写宏记得加括号)

8.请解释下面代码段中每一句的效果。

int val = 2018;
int *pi = 2019;
pi = &val;
*pi = 0;

第一句为给int类型变量val赋值,

第二句是给int类型指针变量pi赋值(这里是给int*类型赋值int类型,所以pi储存的的地址为2019,这是个危险的地方,因为,不知道2019指向哪里),

第三句是将val的地址赋给pi。

第四句是将pi所指向的地址的值修改为0,即将val修改为0

9.执行下列程序段,并输入“Xiyou Linux”(不含引号),那么程序的输出结果是什么?请解释 其原因。

int main(int argc, char *argv[]) {
 char *p = (char *)malloc(sizeof(char) * 20),
 *q = p;
 scanf("%s %s", p, q);
 printf("%s %s\n", p, q);
}

输出结果:Linux Linux

这里先对p分配了动态内存,然后将p储存的地址给了q,所以q,p指向一个地址,scanf先输入p的值,然后输入q的值,因为地址一样,所以q的值会更改p的值,所以p和q都输出最后一个输入的值,即q的值

10.执行下面的程序段,每次执行的输出结果一致吗,整理并解释输出结果。

int main(int argc, char *argv[]) {
 int a[4] = { 2, 0, 1, 9 };
 printf("%p, %p\n", a, &a);
 printf("%p, %p\n", a + 1, &a + 1);
}

        不一致,因为地址是变化的,程序每运行一次,就会重新分配一次地址,你上次用的地址不一定是这次的地址。

        但数组的地址虽然变化,但却是连续的。

        a就是数组的首地址,即a[0]的地址,a+1就是a的地址加a的类型的字节数,即a[1].

        &a相当于二维数组的首地址,所以&a+1就是a[0]的地址+二维数组中的一个一维数组的字节数,比如这里就是(+4*4)。

11.斐波那契数列是这样的一串数列:1,1,2,3,5,8,13,......。在这串数列中,第一项、第二项 为 1,其他项为前两项之和,该数列的第 x 项可以表示为下面的函数。请根据描述,写出一个程 序,使之输入 x 后,能够输出斐波那契数列的第 x 项(其中 x<30)。当你完成之后,你可以尝试 使用递归解决这个问题。

 (怎么去水印啊)

int fb(int num){
    if(num==1||num==2){
        return 1;
    }
    if(num>2){
        return fb(num-1)+fb(num-2);
    }
}

int main(){
    int num=0;
    scanf("%d",&num);
    num=fb(num);
    printf("%d",num);

    return 0;
}

按公式套就行了。 

12.下面代码段是某一种排序算法的简单实现,你知道它是什么吗?请讲解其原理,并尝试改进 它。你还知道哪些排序算法?试着详细描述这些算法。   

int main(int argc, char *argv[]) {
    int nums[6] = { 6, 3, 2, 4, 5, 1 };
    for (int i = 0; i < 6; i++) {
        for (int j = i; j < 6; j++) {
            if (nums[i] > nums[j]) {
                int c = nums[i];
                nums[i] = nums[j];
                nums[j] = c;
            }
        }
    }
}

        这是冒泡排序的算法。 

        冒泡排序,就是像冒泡一样,最小的数会慢慢到最后面或最前面。它重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。 

排序算法:冒泡排序,选择排序,插入排序(还有希尔排序,堆排序,快速排序,并归排序,桶排序等,这些就不说了,不然感觉这篇博客能上万字(其实是我懒))

        选择排序:就是在数组中选择最大或最小的数,放到最前面或最后面,再选择第二大或第二小的,依次排序。

int main(int argc, char *argv[]) {
    int nums[6] = { 6, 3, 2, 4, 5, 1 };
    for(int i=0;i<6-1;i++){
        int max=i;
        for(int j=i+1;j<6;j++){
            if(nums[j]>nums[max]){
                max=j;
            }
        }
        if(max!=i){
            nums[max]^=nums[i];
            nums[i]^=nums[max];
            nums[max]^=nums[i];
        }
    }
}

插入排序:构造一个有序数列,将后面的数字逐个插入。

int main(){
    int nums[6] = { 6, 3, 2, 4, 5, 1 };
    for(int i=1;i<6;i++){
        for(int j=i-1;j>=0&&nums[j]<nums[j+1];j--){
            nums[j]^=nums[j+1];
            nums[j+1]^=nums[j];
            nums[j]^=nums[j+1];
        }
    }
}

13.请简单叙述两种字节序(大端、小端)的概念,你的机器是什么字节序?试着写一个 C 语言程 序来验证,如果你没有思路,你可以尝试着使用联合体或者指针。

        大端:低地址存储高字节,高地址存储低字节。

        小端:高地址存储高地址,低地址存储低字节。

        小端有利于类型的强制转换,比int->char,直接截取低地址处的。

详解可以看:大小端详解_HanSion.Z-CSDN博客_大小端

测试:

int main(){
    int num = 0x12345678;
    char cs = *(char*)&num;

    if ( cs == 0x12 )    
        printf("大端");
    else{
        printf("小端");
    }
}

上篇博客写过的,直接搬过来了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值