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

发布于:2022-11-16 ⋅ 阅读:(813) ⋅ 点赞:(0)

 0.我的计算器坏了

思路:高精度模拟乘方的计算

#include<stdio.h>
#include<stdlib.h>
int main()
{
    int i,j,b;
    int a[10000]={1,1};//第一个为初始长度,第二个为初始初始值,a[0]用来记录位数
    for (i = 0; i < 10000; i++)
    {
        int c=0;//标记进位
        for ( j = 1; j<=a[0]; j++)
        {
            a[j]=a[j]*2+c;//加上上一次循环时进上来的位
            c=a[j]/10;//计算此次是否需要进位
            a[j]%=10;//
        }
        if(c){
            a[0]++;//若发生进位则让数组的长度加一
            b=a[0];
            a[b]=c;//数组的最高位为进位的数字一
        }
        
    }
    printf("%d",a[0]);
}

答案:3011 

1.printf还能这么玩? 

考察点:printf的返回值与多重嵌套时的调用顺序。

对应的知识点:printf的返回值为他所打印的字符数,调用的顺序为由内向外调用。

答案:xiyou linux group - 2022

原因:最内层printf没有打印,返回值为零,第二层中printf调用后打印字符串共为22个字符,返回值为22。根据执行顺序,首先输出0在第二层的占位符处,再打印第二层中要打印的句子,最后打印第二层的返回值22。

2.你好!你好!
考察点:1.对于sizeof( )与strlen( )的应用与理解  2.对于指针及数组之间的关系的理解  3.各类变量在不同系统架构下所占内存的大小 

答案:0  1  12  8  1  11 11

原因:

输出1:使用数组所定义的字符串与使用指针所定义的字符串存储位置并不在同一位置。一个位于全局区中的常量区,另一个位于代码文本区。p1与p0指向两个字符串所在的首地址,因为两个字符串存放的地址不同因此p1与p0不相等,返回值为0即为假。

输出2:strcmp函数逐步比较两个字符串中每一个字母的ascii码,如果两个字符串中的字符完全相同则会输出1,否则输出别的数。

输出3:sizeof的返回值为数据的大小,即其所占的字节数。char类型所占的字节数为一个字节,整个字符数组中共有11个字符,但字符数组以/0结尾,因此该字符串一共占用了12个字节。

输出4:p2为一个指针,指针类型在不同的架构下所占字节数不同。64位架构下为8,32位下为4。

输出5:*p1对于指针解引用用后即表示其所指位置上的值,该值为一个char类型的字符,所占字节数为1。

输出6,7:strlen用来计算字符的长度,遇到/0停止,计算长度时不包含/0,因此为11。

3.换个变量名行不行?

考察点:对于全局变量与局部变量的理解与应用

知识点:全局变量定义于函数之外,在整个程序运行的过程中均可访问。直至程序结束时,变量的生命周期才会随之结束。局部变量定义于块{ }的内部,只有在块内可以访问。离开块之后生命周期便会结束。

答案:1 2 3

原因:三个定义在不同位置的a相互独立,是三个不同的变量,只是变量名相同。第一个被打印出来的a为test函数中定义在一个块中的a。它的初始值为0,自增后为一。当离开它所在的块之后,它便随之消亡。第二个被打印的a是定义在test函数中的a。它初始值为1,自增后为2,打印出的值为2。最后被打印的为全局变量a,它的值为3。

4.内存对不齐 

考察点:union与struct中内存的分配方式。

知识点:

1.union内存的分配:所有成员变量共用同一块内存空间。内存的大小需大于等于占用空间最大的成员变量,且要与最宽成员变量保持对齐。

2.struct内存的分配:在保持与最宽成员变量对齐的情况下,将结构体内所有的变量所占用的空间大小相加。

链接(详细讲解版):

答案:20 32

原因:union内int数组所占用的空间最大为20,且最宽成员变量的字节数为4,保持与4对齐,结果需为4的倍数即为20。struct中,最宽成员变量为double所占字节数为8,int与union相接,所占大小为24,恰好为8的倍数与其对齐。所占空间为32。

 5.Bitwise 

考察点:位运算(将十进制数转化为二进制数后按位运算)

对应知识点:

1.&位与 两个都为1,结果才为1

2.I按位或 两个都为0时结果为0

3.^异或 两位相同时为0,不同时为1

4.~按位取反 0变1,1变0

5.<<左位移  >>右位移,后加上数字即为向左或向右移动多少位。(左移即去掉最高位,其余整体向左移动,右移即去掉最低位,并在最高位补0,其余同左移。)

答案:56  40  254  48  0X4(详细计算过程便不进行赘述)

6.英译汉

 

考察点:指针与const

知识点:const对变量声明只读特性,保护变量值不被修改。

答案:const在*号后定指针,即指针指向的地址不能被改变。const在 *号前定变量,即指针所指地址上的所存放的变量不能被改变。

7.汉译英

 

答案:int *p[10]  int(*p)[10]  int (*p[3])(int) 

1.[ ]的优先级高于*的优先级,p先于[ ]结合表明其为一个数组,后再与 *结合说明数组中存放的变量为指针类型的变量

2.( )将*p括起来使 *先与p结合代表指针,后为一个含有十个变量的数组

3.括号括起来的int表示参数类型是int型,而最前方的int则为返回值的类型。

8.混乱中建立秩序之排序算法

考察点:对于基础排序算法的理解与实现。

1.桶排序(该思想还可用于找出出现频率最高的数与出现次数与其他数不同的数。)

#include<stdio.h>

int main()

{

​    int a[100],b[100]={0},i,j,t=0,n;//a为待排序的数组,b为存放数字的“桶“,并初始化始桶中放的数值为0个

​    scanf("%d",&n);

​    for(i=0;i<n;i++){

​        scanf("%d",&a[i]);

​    }

​    for(i=0;i<n;i++){

​        j=a[i];

​        b[j]=1;//将数字放入桶中打上标记

​        if(j>t){

​            t=j;//记录标号最大的桶。

​        }

​    }

​    for(j=0;j<=t;j++){//从标号为0的桶一一检查若碰到装有数字的桶(被打上1标记)输出他的编号。

​        if(b[j]==1){

​            printf("%d ",j);

​        }

​    }

}

好处:思想简单易懂

坏处:数组占用空间大造成一定的空间上的浪费,且对于可排序的数的大小具有一定局限性。

2.冒泡排序

整体思路:每轮排序通过左右交换的方式将最大的值交换到数组末尾后并形成有序数列。

#include<stdio.h>
int main(void)
{
    int a[100]n,i,j,t;
    scanf("%d",&n);
    for(i=0;i<n;i++){
    scanf("%d",&a[i]);
    }//输入待排序的值
    for(i=0;i<n-1;i++){
        //记录排序所需的轮数,每次将一个元素排至末尾则最多需要n-1轮
       for(j=0;j<n-1-i;j++){
       //n-1-i以后的为已排好序的升序数列无需理会
           //内循环比较相邻元素
           if(a[j]>a[j+1]){
           t=a[j];
           a[j]=a[j+1];//比较左右两数大小,若左边大于右边则交换。
           }
       }
    }
    for(i=0;i<n;i++){
       printf("%d ",a[i]);
    }
    return 0;
}

好处:程序稳定且思想简单易懂,空间复杂度低

缺点:时间复杂度高效率低

3.选择排序

整体思想:每轮遍历无序区间选择出其中的最小值将其放至数组前端形成升序数列

#include<stdio.h>
int main(void)
{
    int a[100] ,i,j,t,n;
    scanf("%d",&n);
    for(i=0;i<n;i++){
        scanf("%d",&a[i]);
    }

​	int min=0;

​	for(i=0;i<n-1;i++){
​        //共挑选n-1轮
​        for(j=i+1;j<n;j++){
​             min = a[min] < a[j] ? min: j;//选择出本轮中最小的数
​        }

​		t=a[i];
 	   a[i]=a[min];
​		a[min]=t;//与无序区间的第一个元素交换

​    }
​    for(i=0;i<n;i++){
​        printf("%d ",a[i]);
​    }
​    return 0;
}

好处:交换次数少

缺点:运行效率低下且不稳定

4.直接插入排序

整体思想:遍历无序区间比找到有序区间最后一个一个数更小的数向前插入到一个小于该数的数之后。

#include<stdio.h>
int main()
{
    int a[100] ,i,j,t,n;
    scanf("%d",&n);
    for(i=0;i<n;i++){
        scanf("%d",&a[i]);
    }//输入
    for(i=1;i<n-1;i++){//计算完成排序所需的最大轮数
        if(a[i]<a[i-1]){//若无序数列的第一个值小于有序数列的最后一个值,则遍历有序数列直至找到大于该值的数
            t=a[i];
            for(j=i-1;j>=0&&a[j];j--){
                a[j+1]=a[j];//将有序数列的值依次向后挪一个位置留下待插入的空位
            }
            a[j+1]=t;//将该值插入到空位中
        }
    }
    for(i=0;i<n;i++){
    printf("%d ",a[i]);
    }//输出
    return 0;
}

好处:稳定性强

缺点:数量级大的情况下循环次数过多

 9.手脑并用

考察点:1.对于头文件string下四个函数的应用与对于ascii码的应用  2.对于自定义函数的考察  3.代码实现能力。

(详细的实现思路在代码中注明)

char*converAndMerge(char s[2][20])//传入二维数组
{
    int len1=strlen(s[0]);//计算字符串长度的函数
    int len2=strlen(s[1]);
    char *ret=(char*)malloc(sizeof(char)*(len1+len2));//动态分配空间
    int i;
    strcpy(ret,s[0]);//字符串复制函数,将s[0]复制到ret中
    strcat(ret,s[1]);//字符串拼接函数,将s[1]拼接到ret后面
    ret[len1+len2]='\0';//在末尾加上终止符
    for(i=0;i<len1+len2;i++){
        if(ret[i]>='A'&&ret[i]<='Z'){
            ret[i]=ret[i]+32;//利用ascii码大小写转换
        }else if(ret[i]>='a'&&ret[i]<='z'){
            ret[i]=ret[i]-32;
        }
    }
    free(ret);//malloc后释放空间
    return ret;
}

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

考察点:指针与多维数组之间的关系及其应用

知识点:一级指针自增或自减所代表的仅在数组第一维上进行所指向位置的偏移例如*(p+1)同p[1][0]同理二级指针则是在第二维内进行指向位置的偏移例如*(*(p+1)+1)同p[1][1]

答案:

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   

(矩阵的形式只是为了方便观看与理解,二维数组在底层上依旧为一个连续的存储单元)   

第一行:最开始时i为零,temp的起始位置为arr[0] [0],a为0,a自增赋给数组的值为0~4。此后a一直自增直至temp遍历完整个二维数组。数组的元素总量为25,a在此轮循环结束时为24。

第二行:此时i自增一次,temp的起始位置为arr[1] [0],a在第一轮基础上继续自增,赋给数组的值为25~29.此后a一直自增直至temp遍历完整个二维数组。此时由于从arr[1] [0]开始,因此之后的元素只有20个,a在此轮循环结束时的值为44。

其余几行依次类推。

 11.奇怪的参数

 

考察点:1.对于mian 函数中参数的了解与使用。2.对于整型溢出的认识与理解。

知识点:1.argc与argv均是main函数中的参数,argc为int型整数用于统计程序运行时发送给,用于统计运行程序时发送给main函数的命令行参数的个数,而其中argv为一个数组元素argv[0]即为程序的文件名。

2.受到二进制位的限制,当数字大于该整型所能表示的最大值时会发生数据的溢出。(因此不会死循环)

答案:为何值为1? argc中始终存在一个参数即为程序的文件名,因此为1。

 12.奇怪的字符

考察点:1.大小端的认识  2.ascii码的十六进制表示

知识点:大端:高位字节放于低地址,低位字节放于高地址。小端反之,高高低低。

输出:Welcom to Xiyou Linux Group 2022

13.小试宏刀

 

考察点:对于宏的理解与应用

知识点:

1.宏为预处理指令仅用于文本的替换并不属于c语言的一部分  

2.如果一个宏中有其他宏的名字,也会被替换掉  

3.如果宏的值超过一行则须在末尾加上\以作为连字符

4.带参数的宏需给每个值加上括号((x)*(x)),否则存在一定的风险

#include <stdio.h>
#define SWAP(a, b, t) t = a; a = b; b = t//此宏定义没有加大括号,里面的有效语句仅为t=a;后两部分虽发生替换但不属于SWAP
#define SQUARE(a) a *a//a没有用括号括起来,可能会发生错误如代码中第15行
#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);  
    if (x > y) SWAP(x, y, tmp); //又发生一次交换
    printf("x = %d, y = %d, tmp = %d\n", x, y, tmp);  
    SWAPWHEN(x, y, tmp, SQUARE(1 + 2 + z++ + ++w) == 100);  //1+2+3+4*1+2+4+5!=100(前面提到的没有括号的原因),因为宏定义是逐步展开,第一个z++后z变为了4,++w后w变为4,然后第二次展开z++,此时z==5,z++==4
    //因为if语句不成立,所以宏中的有效语句t=a不会被执行,但是a=b和b=t会被执行,因为它不属于SWAP里的语句
    printf("x = %d, y = %d,tmp=%d\n", x, y, tmp);  
    printf("z = %d, w = %d ,tmp = %d\n", z, w, tmp);
}

 结尾特别感谢一定.提供的纳新题的题图^_^

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到