目录
0.我的计算器坏了?!
2的10次方是1024,1000是10的3次方,lg1000=3,1000是四位数所以对于2的10000取lg,lg2≈3010,所以lg2是十进制的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;
}
这道题涉及到内存对齐和结构体与联合体,对于结构体
- 第一个成员在结构体变量偏移量为0的地址处
- 其他成员变量要对齐到对齐数的整数倍的地址处
- 对齐数=编译器默认的一个对齐数与该成员大小中的较小值。
- 结构体总大小为最大对齐数的整数倍
对于联合体,各成员共用一块内存空间,并且同时只有一个成员可以得到这块内存的使用权,各变量共用一个内存的首地址。
- 一个union变量的总长度至少能容纳最大的成员变量
- 满足所有成员变量类型大小的整数倍
对于联合体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在前即为内容不可改变,*在前即为地址不可改变,
- 是一个字符型指针,所指的地址不可改变。
- 和3.是一个字符型指针,所指向的内容不可改变但是可以改变*p指向的地址。
7.汉译英
- int *p[10]
- int (*p)[10]
- 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;
}
- argc表示传递给程序命令行参数的数量,至少是1,第一个参数始终是程序的名称。
- 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 :用于显示自身用户名称