西邮Linux兴趣小组2022纳新试题
0.
答案:对应十进制的3011位
大家都知道八进制的一位对应这二进制的三位,十六进制对应二进制的四位,可是十进制与二进制之间并没有直接联系,这时候大家是否觉得这个形式有点熟悉 没错!高中时候的数学题!两边同时取对数!
例如:
$$
2^{10}=1024 两边同时取对数后 \\10*lg2=lg1024\approx3.01\\因为3.01>3,所以要在结果后取整加1,所以结果就是4啦!
$$
那么上题就变成了这样:
$$
2^{10000}取对数后变为10000*lg2\approx3010.02\\同样的,我们取整再加1就是3011啦!
$$
1.<u>**尝试解释程序的输出</u>**
输出:Xiyou Linux Group -2022
主要考察printf函数返回值
是不是很神奇!首先,3+2=5<2为假即为0,3+2=5>2为真即为1,if的条件不成立,跳过第一条printf语句执行else后的语句。
在这里就不得不提到printf函数了,对的,你没看错,在c语言里并没有直接的输入输出语句,它们是靠printf和scanf
函数来完成的。既然是函数,那有没有返回值呢?
有!
以printf函数为例(因为本题讨论的是printf函数),若函数错误那printf函数会返回负值,若正确则会返回字符总数!
并且上题可以看成函数的嵌套,准确来说上题的printf是以栈的方式来存储的,遵循先入后出的原则,所以我们先看到最里面的printf函数,里面什么都没有,返回的字符长度为0,嵌在打印内容的后面,然后第二个printf函数返回了22个字符,注意,空格也是一个字符!所以最后会打印出"Xiyou Linux Group -2022"!
2.
程序输出依次为0 0 12 8 1 11 11
1."=="比较等号两边是否相等,相等返回1,不相等返回0,题中不论是p0还是p1都代表着地址,而数组的地址在栈区,指针里的地址在文字常量区,并不相等返回0. |
---|
2.strcmp函数比较字符串是否相等(将每一个字符转换为对应的ASCII码来比较),相等返回0,否则返回两者的ASCLL码的差值.题中p0和p2代表的字符相同,故为0. |
3.sizeof是运算符,计算所含空间字节数(注意不要忘记'\0'),char类型占1个字节,故sizeof(p0)为12. |
4.sizeof(p1),因为p1是指针,这里求的其实是指针所占字节数,与字符常量无关,在64位编译器上指针占8个字节,故为8. |
5.学过数组都知道,p2==p2[0],而*p2指的是取出p2那个地址上所放的值,故*p2=='H',故sizeof(p2)=1. |
6.strlen函数用于计算字符长度,遇'\0'停止,且不包含'\0',故最后两个答案均为11. |
$$
$$
3.
$$
$$
输出:2(不同编译器可能不同) 2 3
变量分为局部与全局,局部变量又可称之为内部变量。 由某对象或某个函数所创建的变量通常都是局部变量,只能被内部引用,而无法被其它对象或函数引用。 全局变量既可以是某对象函数创建,也可以是在本程序任何地方创建。
划重点!!局部变量的生命周期和作用域都是在大括号——块内的,块里定义了和外面同名的变量则会掩盖外面的同名变量,并且不能在一个块内定义同名的变量
首先,test上面的a为全局变量,剩下的如test函数里的a以及main函数里的a均为局部变量。第一个输出的a用的是上一行定义的a值,可是a并未初始化,所以编译器会给出一个默认值,所以不同编译器可能给出不同的值;第二个输出的a用的是test下一行定义的a(此时第一个a的生命周期已结束),故为2;main函数里输出的a用的是全局变量a,故为3(全局变量整个程序都能用,但是前两个是因为在自己块内定义了同名变量所以全局变量被覆盖了)。
4.
输出:20 32
主要考察联合体和结构体的内存对齐问题,
详细情况可见结构体和联合体(内存对齐)_丿安桥的博客-CSDN博客_联合体内存对齐
1)首先是内存对齐的三个原则: 结构体变量的首地址,必须是结构体变量中的“最大基本数据类型成员所占字节数”的整数倍。 结构体变量中的每个成员相对于结构体首地址的偏移量,都是该成员基本数据类型所占字节数的整数倍 结构体变量的总大小,为结构体变量中 “最大基本数据类型成员所占字节数”的整数倍 |
---|
2)在结构体中,各成员有各自的内存空间。而在联合体中,各成员共享同一段内存空间, 一个联合变量的长度等于各成员中最长的长度。这里所谓的共享不是指把多个成员同时装入一个联合变量内, 而是指该联合变量可被赋予任一成员值,但每次只能赋一种值, 赋入新值则冲去旧值。 简而言之,就是联合体内所有成员共享同一段内存空间,用到哪个成员时,该空间就只取哪种成员。 联合体的字节数:(1)最大成员的字节数。(2)所以成员的整数倍 |
联合体和结构体的区别: (1)结构体的各个成员会占用不同的内存,互相之间没有影响,而共用体的所有成员占用同一段内存,修改一个成员会影响其余所有成员。 (2)结构体占用的内存大于等于所有成员占用的内存的总和(成员之间可能会存在缝隙),共用体占用的内存等于最长的成员占用的内存。 (3)共用体使用了内存覆盖技术,同一时刻只能保存一个成员的值,如果对新的成员赋值,就会把原来成员的值覆盖掉。 |
上题中,以union为例,long占四个字节,int占四个字节,因为int定义的是一个数组,一共占20个字节,char占一个字节,20是4和1的整数倍,故最终占20个字节。结构体struct中,int占四个字节,里面嵌套了一个union(因为union里最大数据类型占4个字节,所以前面不用补齐)占20个字节,一共24个字节,double占8个字节,24是8的整数倍,前面不用补齐,所以一共就是32啦!32是struct里最大数据类型double的整数倍,所以整体不用补齐,最后答案就是32啦!
(%zu指的是输出unsigned int型整数)
5.
答案:56 40 254 48 0x4
1."|" 或运算符 有1为1,全0为0. |
---|
2."&" 与运算符 有0为0,全1为1. |
3.“^" 异或运算符 相同为0,不同为1. |
4.“<<" 左移运算符 可以理解为去掉最左边的数,在最右边补0,往左移一位 |
5.“>>" 右移运算符 可以理解为去掉最右边的数,在最左边补0,往右移一位 |
6.“~” 非运算符 相当于取反 |
7.“%#X” #表示完整呈现所有数值的位数,x表示16进制 |
回到本题中,将每个数换成对应的二进制数再按上述规则进行运算即可,注意有符号整数与无符号整数的区别,计算详情可参考有符号整型和无符号整型的计算_心如止水_03的博客-CSDN博客_无符号整型占几个字节
6.
主要知识点:const总是修饰离他后面最近的变量名或数据类型
const:对变量声明只读特性,保护变量值以防止被修改
1)const修饰p,表明地址不能改变
2)const修饰*p,表明p指向的值不能改变
3)与2)相同,const修饰char *p,表明p指向的内容不能改变
7.
1)int *p[10]
[^[]的优先级高于,所以p先与[]结合,表明他是一个数组,然后与结合,表明数组元素是指针]:
2)int (*p)[10]
[理由同上]
3)int (*p[3])(int)
[被括号括起来的int是函数的参数,表明被指向的函数有一个int参数,最前面的int表明返回类型是int]
8.
冒泡排序:
#include<stdio.h>
#include<stdlib.h> //里面包含了malloc函数,动态分配数组空间
int main(void)
{
int n,i,j,t;
scanf("%d",&n);
int *a=(int*)malloc(sizeof(int)*n);//动态分配数组空间
for(i=0;i<n;i++){
scanf("%d",&a[i]);//输入数组各元素
}
//n-1是因为n个元素只需要n-1次排序
for(i=0;i<n-1;i++){
//外循环遍历每个元素,每次都放置好一个元素
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];//从小到大排序
a[j+1]=t;
}
}
}
for(i=0;i<n;i++){
printf("%d ",a[i]);
}
free(a);//malloc后要记得释放空间
return 0;
}
//冒泡排序有两个for循环,平均时间复杂度为O(n^2),比较稳定,最优的空间复杂度是O(0)(此时元素已经排好序),最坏的情况是开始逆序排序,此时空间复杂度为O(n).
简单选择排序:
#include<stdio.h>
#include<stdlib.h>
int main(void)
{
int i,j,t,n;
scanf("%d",&n);
int *a=(int*)malloc(sizeof(int)*n);
for(i=0;i<n;i++){
scanf("%d",&a[i]);
}
//上部分和冒泡排序一样
for(i=0;i<n;i++){
//遍历每个元素
for(j=i+1;j<n;j++){
//每个元素与后一元素比较
if(a[i]>a[j]){
t=a[i];
a[i]=a[j];//从小到大排序
a[j]=t;
}
}
}
for(i=0;i<n;i++){
printf("%d ",a[i]);
}
free(a);//malloc后要释放空间
return 0;
}
//简单选择排序有两个for循环,平均时间复杂度为O(n^2),不稳定(可能会改变相同元素的相对位置),空间复杂度是O(0).
排序算法还包括插入排序,桶排序,快速排序等。
9.
char*converAndMerge(char s[2][20])//传一个二维数组
{
int len1=strlen(s[0]);//计算字符串长度的函数
int len2=strlen(s[1]);
char *ret=(char*)malloc(sizeof(char)*(len1+len2));//malloc动态分配空间
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;//大小写转换
}else if(ret[i]>='a'&&ret[i]<='z'){
ret[i]=ret[i]-32;
}
}
free(ret);//malloc后释放空间
return ret;
}
10.
<u>输出:***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*****
注释写在代码块里:
#include<stdio.h>
int main(int argc,char**argv)
{
int arr[5][5];//二维数组5行5列
int a=0;
for(int i=0;i<5;i++){
int *temp=*(arr+i);
for(;temp<arr[5];temp++){//arr[5]是arr二维数组的第5行,但是arr只有第0行到第4行,所以二维数组所有元素地址都小于arr[5]
*temp=a++;
}
}//第一遍循环时,内层循环给数组0到4行所有元素分别赋值为0-24,其中第0行为0-4;然后第二遍循环时,给1到4行分别赋值为25-44,其中第1行为25-29;第三遍给2到4行分别赋值为45到59,其中第二行为45-49;以此类推
for(i=0;i<5;i++){
for(int j=0;j<5;j++){
printf("%d\t")
}
}
}
11.
1.argc和argv中的arg是参数,其中argc是int类型的整数,用于统计运行程序时送给main函数的命令行参数的个数 |
---|
2.**argv中为输入的字符串内容,它是一个指向字符串的指针 |
3.argc中总是存在一个参数即程序全名,这也是为什么argc的值为1的原因 |
4.不会出现死循环,因为当argc加到一定值后会发生溢出,会变为负数 |
12.
输出:Welcome to Xiyou Linux Group 2022**
主要考察知识点:大小端
-
大端模式:指高位字节放在低地址端,低位字节放在高地址端
-
小端模式:指高位字节放在高地址端,低位字节放在低地址端
-
图片来自图解字节序大小端、比特序大小端_小熊coder的博客-CSDN博客
回到本题,数组data1和data2里都放这16进制的ASCII码,然后将对应的字符输出,如0X636c6557中,16进制的57对应着'W'(没错,是16进制),(计算机从低地址开始读取),以此类推
13.
输出:2 1 1
1 2 2
2 2
5 5 2
这题可有得说了...首先,涉及到宏定义的边际效应(在宏定义时应尽可能的加上括号才会比较准确)
太复杂,在代码块里注释:
#include <stdio.h>
#define SWAP(a, b, t) t = a; a = b; b = t//此宏定义因为没有加大括号,里面的有效语句仅为t=a;
#define SQUARE(a) 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);
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);
}