1. 大小和长度竟然不是一个意思

sizeof()strlen()有什么异同之处?

他们对于不同参数的结果有什么不同?请试举例子说明。

int main(void) {char s[] = "I love Linux\0\0\0";int a = sizeof(s);int b = strlen(s);printf("%d %d\n", a, b);
}
  • 程序输出为16 12
  • sizeof会统计字符串结尾的\0;而strlen不会,它只统计\0之前的字符串个数,遇到\0停止
  • 因此sizeof的结果比strlen的多能看见的三个\0,以及在字符串末尾自动加上的再一个\0,即一共多四个\0。So,16和12相差4

举个栗子ヾ(•ω•`)o

int main(){char arr1[]="abc";char arr2[]={'a','b','c'};printf("%d\n"sizeof(arr1));printf("%d\n"sizeof(arr2));printf("%d\n"strlen(arr1));printf("%d\n"strlen(arr2));
}
  • 根据以上的说明,可知该程序的输出为4 3 3 26(随机值)(由于arr2没有结尾的\0,所以计算完‘c’后,继续往后计算,直到遇见随机的\0)
  • 嗯哼,没看够?点这里

注意:

  • sizeof是运算符,计算对应类型所占的空间数,不是函数;而strlen是在#include<string.h>头文件下的一个计算字符串长度的函数,且只能(char*)字符串作为参数

2. 箱子的大小和装入物品的顺序有关

test1test2都含有:1个short、1个int、1个double,那么sizeof(t1)sizeof(t2)是否相等呢?这是为什么呢?

struct test1 {int a;short b;double c;
};
struct test2 {short b;int a;double c;
};
int main(void) {struct test1 t1;struct test2 t2;printf("sizeof (t1) : %d\n", sizeof(t1));printf("sizeof(t2): %d\n", sizeof(t2));
}
  • 相等,均为16
  • 了解一下结构体的内部成员存放和结构体的大小:
    1.结构体内部的成员不是连续紧挨着存放的
    2.结构体可以分成N份,每份的大小是最大成员类型的长度
    3.结构体的大小为N * 最大成员类型的长度
再看这题:
  • 举该题t1的例子,由于double是占了8个字节,为结构体成员中的最大长度,因此每份大小为8
  • 第一份中,int占了4个字节,还剩8-4=4个字节,∵4>2(shout)接下来的short可以继续放在第一份中,此时第一份里只剩下8-4-2=2个字节,∵2<8(double)double无法再放入第一份,得重开新的第二份;
  • 第二份刚好放下double;
  • 在这个结构体中一共用了两份,所以结构体大小为8(每份大小)× 2(份数)=16

3. 哦,又是函数

想必在高数老师的教导下大家十分熟悉函数这个概念。那么你了解计算机程序设计中的函数吗?请编写一个func函数,用来输出二维数组arr中每个元素的值。

/*在这里补全func函数的定义*/
int main(void) {int arr[10][13];for (int i = 0; i < 10; i++) {for (int j = 0; j < 13; j++) {arr[i][j] = rand();}}func(arr);
}
  • 上代码
void fun( int a[][13] ){int i ,j;for( i = 0 ; i < 10 ; i++ ){for( j = 0 ; j < 13 ; j++ ){printf( "%d" , a[i][j] );}}
}
  • over

4.就不能换个变量名吗?

  • 请结合下面的程序,简要谈谈传值传址的区别。
  • 简要谈谈你对C语言中变量的生命周期的认识。
int ver = 123;
void func1(int ver) {ver++;printf("ver = %d\n", ver);
}
void func2(int *pr) {*pr = 1234;printf("*pr = %d\n", *pr);pr = 5678;printf("ver = %d\n", ver);
}
int main() {int a = 0;int ver = 1025;for (int a = 3; a < 4; a++) {static int a = 5;printf("a = %d\n", a);a = ver;func1(ver);int ver = 7;printf("ver = %d\n", ver);func2(&ver);}printf("a = %d\tver = %d\n", a, ver);
}
  • 看结果:

  • 传值:把A的数值传到B,改变B,A不会跟着变,B存的是跟A一样的值

  • 传址:把A的地址传到B,改变B,A同时跟着变,B存的是A的地址

  • 生命周期:将一对大括号称为“块”
    1.本地变量定义在块内,且不会被默认初始化(因此第一个的输出结果为随机值)
    2.程序运行到“块”之前,其中的变量不存在;离开“块”,其中的变量消失了
    3.“块”外面定义的变量其一下到处有效
    4.“块”里面定义了和外面同名的变量,则会掩盖外面的

  • 据以上信息,便可得其结果


5. 套娃真好玩!

请说明下面的程序是如何完成求和的?

unsigned sum(unsigned n) { return n ? sum(n - 1) + n : 0; }
int main(void) { printf("%u\n", sum(100)); }
  • 结果为5050=100+99+…+1

  • 本题了解条件运算符的执行方法就能解决


6. 算不对的算术

void func(void) {short a = -2;unsigned int b = 1;b += a;int c = -1;unsigned short d = c * 256;c <<= 4;int e = 2;e = ~e | 6;d = (d & 0xff) + 0x2022;printf("a=0x%hx\tb=0x%x\td=0x%hx\te=0x%x\n", a, b, d, e);printf("c=Ox%hhx\t\n", (signed char)c);
}

又双叒叕是位运算


注:图片来自位运算全面总结,关于位运算看这篇就够了

  • %hx 代表以16进制输出short类型的整数,因此a,b显而易见,不解释
  • 关于d,d为无符号的short,c*256=-256,所以此时d=216+(-256);接着d和0xff进行与运算,结果为0,再加上0x2022,所以d最终=0x2022
  • 关于e,先进行 ~(取反),取反结果和6进行或运算,结果为0xffffffff
  • 关于c,将c左移4位后,并强制类型转换成signed char,得0xfff0

7. 指针和数组的恩怨情仇

int main(void) {int a[3][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};int(*b)[3] = a;++b;b[1][1] = 10;int *ptr = (int *)(&a + 1);printf("%d %d %d \n", a[2][1], **(a + 1), *(ptr - 1));
}
  • 结果:10 4 9
int main(void) {int a[3][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};int(*b)[3] = a;//b和*结合,构成一个名为b指针,int修饰数组的内容(数组的每个元素),因此b指针指向该数组的首地址,//而这个数组有3个单元,每个单元都是int类型,且该数组没有名字>>指向含有3个int数组的指针//将a赋值给他,使b指针指向a数组第一个单元{1,2,3}中的首元素1++b;//指针b指向a数组的第二个单元{4,5,6}中的首元素4b[1][1] = 10;//经过++b后,b[0][0]为4,所以这里的b[1][1]为8,并将其赋值为10(即a[2][1]=10)int *ptr = (int *)(&a + 1);//(&a+1)是指针ptr指向a数组的下一个数组(在a数组最后一个元素的后面)printf("%d %d %d \n", a[2][1], **(a + 1), *(ptr - 1));
}
  • a[2][1]据分析可得为10
  • **(a + 1)可理解为 * (*(a+1)+0)=a[1][0]=4
  • *(ptr - 1))指整个数组的下一个数组减去一个元素地址,得到上一个数组a的最后一个元素9

  • a+1和&a+1的区别

8. 移形换位之术

下面有abc三个变量和4个相似的函数。

  • 你能说出使用这三个变量的值或地址作为参数分别调用这5个函数,在语法上是否正确吗?
  • 请找出下面的代码中的错误。
  • const intint const是否有区别?如果有区别,请谈谈他们的区别。
  • const int *int const *是否有区别?如果有区别,请谈谈他们的区别。
int a = 1;
int const b = 2;
const int c = 3;
void funco(int n) {n += 1;n = a;
}
void func1(int *n) {*n += 1;n = &a;
}
void func2(const int *n) {*n += 1;n = &a;
}
void func3(int *const n) {*n += 1;n = &a;
}
void func4(const int *const n) {*n += 1;n = &a;
}

void func2(const int *n) {//const修饰指针*n,表示*n指向的值不能被改变*n += 1;//因此这里是错误的n = &a;
}
void func3(int *const n) {//const修饰地址,表示指针的地址不能被改变*n += 1;n = &a;//因此这里是错误的
}
void func4(const int *const n) {//const修饰指针和地址,两者均不能改变*n += 1;//因此这里是错误的n = &a;//因此这里是错误的
}
  • const int和 int const都表示int类型的变量不能被修改
  • const int *aint const *a:(*和a连在一起)表示指针a指向一个const int,即 *a的值为const,不能被修改
  • 而对于int *const a:(* 和a分开来了)表示地址固定的指针a不能被修改地址,但能修改*a的值
  • 更多见:here here

9. 听说翻转字母大小写不影响英文的阅读?

请编写convert函数用来将作为参数的字符串中的大写字母转换为小写字母,将小写字母转换为大写字母。返回转换完成得到的新字符串。

char *convert(const char *s);
int main(void) {char *str = "XiyouLinux Group 2022";char *temp = convert(str);puts(temp);
}
  • 上代码
char *convert(const char *s)
{int len=strlen(s);char *a=(char*)malloc(len);strcpy(a,s);char *q=a;for(;*a!='\0';a++){if(*a>='a'&&*a <= 'z') *a -= 32;else if(*a >= 'A'&&*a <= 'Z') *a += 32;}return q;
}

10. 交换礼物的方式

  • 请判断下面的三种Swap的正误,分别分析他们的优缺点。
  • 你知道这里的do {...} while(0)的作用吗?
  • 你还有其他的方式实现Swap功能吗?
#define Swap1(a, b, t) do {                 t = a;             a = b;             b = t;             } while (0)
#define Swap2(a, b) do {              int t = a;      a = b;          b = t;          } while (0)
void Swap3(int a, int b) {int t = a;a = b;b = t;
}
  • swap1、2正确,swap3错误
  • swap1:直接从原函数中传递参数,方便快捷
  • swap2:在参数中创建交换变量t,作用时间短,且占用内存空间小
  • swap3:只传递了a,b变量的值而并没有传递地址,所以仅在函数内部改变了a,b的值而函数作用完后就释放掉函数中变量的内存,a,b的值还是没有改变
  • do {…} while(0)的作用:实现局部作用域(为了在宏定义中使用多个语句块而不会受大括号和分号的影响)
  • 用指针啦

11. 据说有个东西叫参数

你知道argcargv的含义吗?请解释下面的程序。你能在不使用argc的前提下,完成对argv的遍历吗?

int main(int argc, char *argv[]) {printf("argc = %d\n", argc);for (int i = 0; i < argc; i++)printf("%s\n", argv[i]);
}
  • argc:外部输入的参数个数
  • argv:参数的字符串数组,用来存放指向字符串参数的指针数组
  • (argc=1时,表示只有一个程序名称,存储在argv[0]中;argv[0]指向程序运行的全部路径名;argv[1]指向程序在DOS命令中执行程序名的第一个字符串,后面以此类推)
  • 见代码
int main(int argc, char *argv[]) {printf("argc = %d\n", argc);for ( int i = 0; argv[i]!='\0'; i++)printf("%s\n", argv[i]);
}

一样的结果:


12. 人去楼空

这段代码有是否存在错误?谈一谈静态变量与其他变量的异同。

int *func1(void) {static int n = 0;n = 1;return &n;
}
int *func2(void) {int *p = (int *)malloc(sizeof(int));*p = 3;return p;
}
int *func3(void) {int n = 4;return &n;
}
int main(void) {*func1() = 4;*func2() = 5;*func3() = 6;
}
  • 解答见下
int *func3(void) {int n = 4;return &n;//不可返回局部变量的地址(&n),作用完就被释放了
}
  • static int 与 int 的区别:static int 不管在函数内还是函数外,都作为一个全局变量可以保存它被修改以后的值。而 int没有这一功能,只有作为全局变量时能保存修改。
  • c语言中static关键字用法详解

13. 奇怪的输出

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

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

  • 一般家庭计算机所使用的为小端法,因此根据以上知识并查阅阿斯克码表可得,该程序的输出为Welcome to xiyou Linux group 2021

14. 请谈谈对从「C语言文件到可执行文件」的过程的理解

  • 图片来自谈谈C语言从源文件变为可执行文件之间发生的过程详解(C程序的编译链接运行)

全题终。。。。。。

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

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

2021西邮linux兴趣小组纳新题题解相关推荐

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

    1. 请试着解释其输出. int main(int argc , char *argv[]) {unsigned char a = 255;char ch = 128;a -= ch;printf(& ...

  2. 2021西邮linux兴趣小组纳新题解

    目录 1. 请试着解释其输出 2. 下面代码的运行输出结果是什么,并说说你的理解. 3. 这段代码的输出结果是什么?为什么会出现这样的结果? 4. 下面程序会出现什么结果?为什么会出现这样的结果? 5 ...

  3. 2021年 西邮Linux兴趣小组 纳新免试题揭秘

    文章目录 引言 第一关 第二关 第三关 第四关 第五关 总结 引言 小组2020年的免试题的四位出题人是:小组18级成员李兆龙,20级成员赵子玮,刘树杭,任子涧. 同时19级成员周阔,戚凯萌,胡哲宁, ...

  4. 西邮Linux兴趣小组纳新笔试试题

    下面是西邮Linux小组今年纳新的笔试试题 1. 下面这个程序的输出结果是什么? int main() { int a = (1, 2); printf("a = %d\n", a ...

  5. 西邮linux兴趣小组网络,西邮Linux兴趣小组纳新笔试试题

    下面是西邮Linux小组今年纳新的笔试试题,原文在这里. 1. 下面这个程序的输出结果是什么? int main() { int a = (1, 2); printf("a = %d\n&q ...

  6. 西邮linux面试题,西邮Linux兴趣小组纳新免试题! come on!

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 密文: 0011011101111010101111001010111100100111000111000000000000000011100110111 ...

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

    目录 0. 我的计算器坏了?! 1. printf还能这么玩? 2. 你好你好你好呀! 3.换个变量名不行吗? 4. 内存对不齐 5. Bitwise 6. 英译汉 7. 汉译英 8. 混乱中建立秩序 ...

  8. 西邮linux兴趣小组网络,西邮Linux兴趣小组2012纳新笔试题

    这是我们西邮Linux兴趣小组2012的纳新笔试题,对于大一的学生,出得有难度哦,个人感觉比腾讯实习生的笔试题出的有水平. 西邮Linux兴趣小组纳新试题 姓名:                    ...

  9. 西邮Linux兴趣小组2021纳新面试题题解

    注: 本题目仅作西邮Linux兴趣小组2021纳新面试题的有限参考. 为节省版面本试题的程序源码中省略了#include指令. 本试题中的程序源码仅用于考察C语言基础,不应当作为C语言代码风格的范例. ...

最新文章

  1. ISP、主机之间的通信方式、电路交换和分组交换、时延
  2. 主线程等待线程池所有任务完成
  3. myeclipse中添加Oracle数据库
  4. c语言错误解析-变量声明
  5. 2017.6.5 YY的GCD 失败总结
  6. 面向对象设计模式纵横谈:Prototype 原型模式(笔记记录)
  7. 引用 DetachedCriteria
  8. 简单谈谈视频网站分析
  9. git revert与git reset
  10. 0903 - Firebase Analytics PK Google Analytics
  11. 生物医学基础--人体阻抗模型
  12. GSM模块通过服务器或GSM内部获取网络时间 网络授时
  13. ABT Node:为去中心应用开发带来的范式迁移
  14. Pinia学习笔记之--核心概念Actions
  15. ACM与IEEE双Fellow、华人女计算机科学家周以真:可信 AI,未来可期
  16. Mac 苹果系统没有WIFI选项自检出现-1005D
  17. python interpreter配置_PyCharm使用之配置SSH Interpreter
  18. 1. 树莓派的基础配置
  19. 线性回归使用的基本条件
  20. 小程序毕业设计 基于微信电影院购票小程序毕业设计开题报告功能参考

热门文章

  1. 精确性和准确性是两码事儿
  2. APP通过http获取OneNet数据与命令下发【应用层】
  3. 2022年上期计算机英语复习
  4. DM368开发 -- 华为3G/4G模块移植
  5. linux centos7 网络限速
  6. 基于cortex-A7
  7. OpenStack octavia LB负载均衡基础
  8. 细节决定成败之C++成员变量、构造函数初始化顺序
  9. 作为一名Python程序员,论听歌的正确姿势?
  10. Centos7 更换yum软件源