2022
0. 我的计算器坏了?!
2^10=1024
对应于十进制的4位,那么2^10000
对应于十进制的多少位呢?
对应于十进制的k位等价于除以10k次小于1,中的最小值
两遍取对数进行运算
约等于0.30102999566398119521373
n=10000,代入得k为3010+1=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("")));
}
printf()返回打印字符的个数
输出:Xiyou LInux Group - 2022
2. 你好你好你好呀!
- 程序的输出有点奇怪,请尝试解释一下程序的输出吧。
- 请谈谈对
sizeof()
及strlen()
的理解吧。
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指针指向字符串,p2[11]给的空间不够(字符串末尾有\0)
p0和p1是指针,比较地址,明显不一样。p0==p1返回0
p2储存的字符串没有结尾,所以strcmp(p0,p1)无法返回0
sizeof测字符串大小时读取首地址。而*p2只是字符串的第一个元素,大小为1
strlen()函数返回字符串的长度(不包括\0)
3. 换个变量名不行吗?
请结合本题,分别谈谈你对C语言中「全局变量」和「局部变量」的「生命周期」理解。
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);
}
作用域描述程序中可访问标识符的区域,生命周期常常用存储期描述。
写在所有函数的外面具有文件作用域,具有文件作用域的变量也被称为全局变量。文件作用域变量具有静态存储期。从程序被载入到程序结束期间都存在。
定义在块中的变量具有块作用域,这些变量往往被称为局部变量,具有自动存储期。当程序进入定义这些变量的块时,为这些变量分配内存;当退出这个块时,释放刚才为变量释放的内存。
4. 内存对不齐
union
与struct
各有什么特点呢,你了解他们的内存分配模式吗。
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));
printf("sizeof (STRUCT) = %zu \n", sizeof(STRUCT));
}
union各成员共享一块内存空间
struct各成员各有内存空间。但可能会内存对不齐,浪费内存。
结构体的内存对齐 - (jianshu.com)
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);
}
位运算:先把10进制转化为2进制,然后再算(负数表示为补码,等于原码的取反加一)
| 位或 有一个1就是1
&位与 必须2个都是1才是1
^异或 相同为0,不同为1
~按位取反 0变1,1变0
<<左移 右移>>
注意char之类的本身就有范围,可能会有截断。
参考输出:
a:56,b:0,c:254,d:48
e:0x4
6. 英译汉
请说说下面数据类型的含义,谈谈
const
的作用。
char *const p
。char const *p
。const char *p
。
1 > const在 * 右边修饰指针。
指向char类型的指针,不能更改指向的值
2、3 > const在 * 左边修饰char。
指向char类型的指针,不能修改指向的地方
const可以防止数据被意外篡改
7. 汉译英
请用变量
p
给出下面的定义:
- 含有10个指向
int
的指针的数组。- 指向含有10个
int
数组的指针。- 含有3个「指向函数的指针」的数组,被指向的函数有1个
int
参数并返回int
。
1 > int a[10]
2 > int (p)[10]
3 > int *a[3] (int)
8. 混乱中建立秩序
你对排序算法了解多少呢?
请谈谈你所了解的排序算法的思想、稳定性、时间复杂度、空间复杂度。提示:动动你的小手敲出来更好哦~
冒泡排序
像冒泡一样,元素一个个上来(被排序)。
稳定性:稳定
时间:O(n2) 空间:O(1)只用了一个临时变量
选择排序
每次选个最值
稳定性:稳定(正序遍历)/不稳定(倒序遍历)
时间:O(n2) 空间O(1)同样也只用了一个临时变量
归并排序
先分解再综合
稳定性:稳定
时间:O() 每一层n,总共层
空间:O(n)等于原来要排序的大小
9. 手脑并用
请实现ConvertAndMerge函数:
拼接输入的两个字符串,并翻转拼接后得到的新字符串中所有字母的大小写。提示:你需要为新字符串分配空间。
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);
}
参考代码:
#include
#include "stdlib.h"
#include
#include
char* ConvertAndMerge(char str[][20]);
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);
return 0;
}
char* ConvertAndMerge(char str[][20])
{
char *start,*s;
start=s=(char*)malloc(strlen(str[0])+strlen(str[1])+1);
char *p1=str[0];
char *p2=str[1];
while (*p1 != '\0')
{
if (isupper(*p1))
*s++=tolower(*p1++);
else
*s++=toupper(*p1++);
}
while (*p2 != '\0')
{
if (isupper(*p2))
*s++=tolower(*p2++);
else
*s++=toupper(*p2++);
}
return start;
}
10. 给你我的指针,访问我的心声
程序的输出有点奇怪,请尝试解释一下程序的输出吧。
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]);
}
}
}
arr=&arr[0],*(arr+i)的意思是移动 i 行。
C保证中超出数组一个元素的指针指向的位置依然有效,arr[5]是第5行第1个元素的位置(从第0行开始数)。
第一次—— temp指向第0行,因为二维数组是以一维数组的方式排列的,temp从[0][0]到[5][0]总共重复了25次。所以输出后的二维数组被改成了这样:
0 1 2 3 4
5 6 7 8 9
10 11 12 13 14
15 16 17 18 19
20 21 22 23 24 25
第二次—— temp指向第1行,a在第一次循环的历练之中已经变成了26,,现在再次循环,从[1][0]到[5][0]总共20次。第二次会对第一次的数据进行覆盖。所以结果如下:
0 1 2 3 4
26 27 28 29 30
31 32 33 34 35
36 37 38 39 40
41 42 43 44 45
在这之后的几次改动效果同上
改动之后二维数组的元素被依次打印了出来。
最后输出→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
11. 奇怪的参数
你了解argc和argv吗?
直接运行程序argc的值为什么是1?
程序会出现死循环吗?
#include
int main(int argc, char **argv)
{
printf("argc = %d\n", argc);
while (1)
{
argc++;
if (argc < 0)
{
printf("%s\n", (char *)argv[0]);
break;
}
}
}
argc是参数的个数,argv是参数列表。直接运行,传入的参数是程序名。只有一个参数,所以argc的值是1。
程序不会出现死循环,因为int类型的值有范围,超出范围就会发生溢出。溢出的结果是未定义的,但是很有可能是一个“最负的值”,于是满足(argc<0)的结果,程序终止。
12. 奇怪的字符
程序的输出有点奇怪,请尝试解释一下程序的输出吧。
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);
}
本题涉及到大端模式和小端模式
小端模式低位字节排放在内存的低地址端,而大端模式则刚好相反。计算机内部大部分采用小端模式。
strcpy把a复制到buf,strcat再将b与buf拼接。
char类型一次读取一个字节,二个16进制位=8个2进制位,即1个字节。
0x636c6557 左端是高位字节,右端是低位字节(你可以拿10进制类比),
内存的读写永远从低地址开始读/写,所以它被2个2个地从后向前读。
最后输出→Welcome to Xiyou Linux Group 2022
13. 小试宏刀
- 请谈谈你对
#define
的理解。- 请尝试着解释程序的输出。
#include
#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);
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);
printf("x = %d, y = %d,tmp=%d\n", x, y, tmp);
printf("z = %d, w = %d ,tmp = %d\n", z, w, tmp);
}
把宏替换成对应的字符串
一板一眼地照着一点一点抽丝剥茧,很容易发现SWAPWHEN破绽百出
if(1 + 2 + z++ + ++w*1 + 2 + z++ + w++ == 100)
t=a;a=b;b=t;
if条件显然不对,t=a无法执行。但是后面两条没有被if给控制,可以正常执行。
14. GNU/Linux命令 (选做)
你知道以下命令的含义和用法吗:
ls
rm
whoami
请问你还了解哪些GNU/Linux的命令呢。
ls:查看当前目录下文件内容
rm:用于删除一个文件或目录(若删除目录需要配合 -r )
whoami:查看当前目录名
其他:
timedatectl:查看当前时区设置
mkdir:新建一个文件夹
pwd:打印当前目录
2021(1)
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);
}
sizeof()返回占空间的大小(包括\0),strlen()返回字符串长度(不包括\0)
2. 箱子的大小和装入物品的顺序有关
test1
和test2
都含有: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 16
详情见上 [2022/4内存对不齐]
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 func(int arr[][13],int n,int m)
{
int i,j;
for(i=0;i
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);
}
传值:把实参的值copy给形参,相当于生成一个影分身,“分身受伤对本体没有影响”。但是要用一块新的空间,比较浪费。
传址:把地址传给别人,会被顺着地址找上门来,所以实参可能会被改变。
生命周期:[2022/3. 换个变量名不行吗?]
运行结果→
a = 5
ver = 1026
ver = 7
*pr = 1234
ver = 123
a = 0 ver = 1025
5. 套娃真好玩!
请说明下面的程序是如何完成求和的?
unsigned sum(unsigned n) {
return n ? sum(n - 1) + n : 0;}
int main(void) {
printf("%u\n", sum(100));
}
这是一个递归
直到n==0为止,调用sum(n-1)
n
n n-1
n n-1 n-2
n n-1 n-2 n-3
n n-1 …………0
n n-1 n-2 n-3
n n-1 n-2
n n-1
n
这里输入的参数为100,结果为0+1+2+……100=5050
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=0x%hhx\t\n", (signed char)c);
}
运算规则见 [2022/5 Bitwise]
简单的运算,没什么好说的。
%h short ; %hh char
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));
}
b指向&a[0]
++b指向&a[1]
**(a+1)第1行第0个元素
*(ptr-1)第2行第2个元素(ptr一次移动一个表)
结果→ 10 4 9
8. 移形换位之术
下面有
a
、b
、c
三个变量和4个相似的函数。
- 你能说出使用这三个变量的值或地址作为参数分别调用这5个函数,在语法上是否正确吗?
- 请找出下面的代码中的错误。
const int
和int 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;
}
答案都是没区别 见[2022/6 英译汉]
func2×
const说明指针指向的值不能改,它却依然改
func3×
const说明指针指的位置不能变,却依然变
其他都对√
9. 听说翻转字母大小写不影响英文的阅读?
请编写
convert
函数用来将作为参数的字符串中的大写字母转换为小写字母,将小写字母转换为大写字母。返回转换完成得到的新字符串。
char *convert(const char *s);
int main(void) {
char *str = "XiyouLinux Group 2022";
char *temp = convert(str);
puts(temp);
}
见[2022/9. 手脑并用]
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;
}
3不行,1和2可以
3复制了分身,对本体没有产生任何影响。
swap1 多传一个参,但不创建新变量
swap2 方便
do{}while(0)保证只交换一次
还可以借助位运算进行交换:
a^=b;b^=a;a^=b;
解释:
一个数异或它自己等于0;
0异或任何数等于那个数本身;
a=a ^ b
b=b ^ a ^ b=b ^ b ^ a=0^a=a
a=a ^ a ^ b=0 ^ b=a
11. 据说有个东西叫参数
你知道
argc
和argv
的含义吗?请解释下面的程序。你能在不使用argc
的前提下,完成对argv
的遍历吗?
含义见[2022/11. 奇怪的参数]
参考代码:
int main(int argc, char *argv[]) {
printf("argc = %d\n", argc);
for (int i = 0; i < argc; 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;
}
func1 func2正确 ;
func3错误,在块中分配给n的内存函数执行完后就被还回去了。
静态变量,静态的意思不是说它的值不变,而是说它在内存中原地不动。这些变量和自动变量一样都具有块作用域,即只能在块中通过标识符访问。但是如本题中func1中的static声明的变量一样,它所占的空间不会因为程序离开了它所在的函数就被自动返还。
其他相关知识 见[2022/3. 换个变量名不行吗?]
13. 奇怪的输出
int main(void) {
int data[] = {0x636c6557, 0x20656d6f, 0x78206f74,
0x756f7969, 0x6e694c20, 0x67207875,
0x70756f72, 0x32303220, 0x00000a31};
puts((const char*)data);
}
见[2022/12. 奇怪的字符]
14. 请谈谈对从「C语言文件到可执行文件」的过程的理解
C通过编译和链接两个步骤来完成这一过程
编译器把源代码转成中间代码(汇编),链接器把中间代码和其他代码合并,生成可执行文件。
{这里的其他文件包括:
预编译的库代码
系统的标准启动代码(启动代码充当着程序和操作系统之间的接口)}
这种分而治之的方法有助于对程序进行模块化,让你可以独立编写一个新模块,然后再用编译器将其与已编译的模块链接起来。在有些系统中,必须分别运行编译程序和链接程序,而在另一些系统中,编译器会自动启动链接器,用户只需给出编译命令即可。
15. (选做) 堆和栈
你了解程序中的栈和堆吗?它们在使用上有什么区别呢?请简要说明。
内存分类:
栈区(stack) 由编译器自动分配释放
堆区(heap) 由程序员自己指定大小,自己释放
全局区(静态区)(static) 程序结束后由系统释放
文字常量区: 程序结束后由系统释放
申请内存后,
当栈的剩余空间>申请空间时,系统就会为程序提供内存,否则将提示栈溢出。
堆会遍历记录空间内存地址的链表,搜索一个空间比所申请空间大的堆节点,将该节点的空间分配给程序。
16. (选做) 多文件
一个程序在不使用任何头文件的情况下,如何使用另一个文件中的函数。
被引用的函数的返回值类型前面添加extern关键字,表明该函数可以被其他的源文件调用
然后在去引用那个函数程序中添加要用到的函数原型
17. (选做) GNU/Linux
与文件
- 你知道如何在
GNU/Linux
下如何使用命令行创建文件与文
件夹吗?- 你知道
GNU/Linux
下的命令ls 的每一列的含义吗?- 你知道
GNU/Linux
下文件的访问时间、修改时间、创建时间如何查看吗?并简单说说他们的区别。
创建文件夹:mkdir 目录名,一次只能创建一层,如果使用-p(递归)选项可以一次创建多层
创建文件:touch
ls -I
1.文件属性
2.文件个数
3.该文件或目录的拥有者
4.所属的组
5.文件大小
6.创建日期
7.文件名
时间相关:https://blog.csdn.net/zyz511919766/article/details/14452027
2021(2)
1. 请试着解释其输出。
int main(int argc , char *argv[]) {
unsigned char a = 255;
char ch = 128;
a -= ch;
printf("a = %d ch = %d\n", a, ch);
}
char的范围是 -128~127;ch越界,真正的值为 -128。
为什么-128的补码是1000 0000? - (jianshu.com)
a-ch=255-128=127
2. 下面代码的运行输出结果是什么,并说说你的理解。
int main(int argc, char *argv[]) {
char *str = "Xi You Linux Group 20";
printf("%d\n", printf(str));
return 0;
}
见[2022/1. printf还能这么玩?]
输出→Xi You Linux Group 2021
3. 这段代码的输出结果是什么?为什么会出现这样的结果?
int i = 2;
void func() {
if(i != 0) {
static int m = 0;
int n = 0;
n++;
m++;
printf("m = %d, n = %d\n", m, n);
i--;
func();
} else {
return;
}
}
int main(int argc, char *argv[]) {
func();
return 0;
}
输出→
m = 1, n = 1
m = 2, n = 1
变量的生命周期
见[2022/3. 换个变量名不行吗?] [2021/12. 人去楼空]
4. 下面程序会出现什么结果?为什么会出现这样的结果?
int main(int argc, char * argv[]) {
char ch = 'A';
int i = 65;
unsigned int f = 33554433;
*(int *)&f >>= 24;
*(int *)&f = *(int *)&f + '?';
printf("ch = %c i = %c f = %c\n", ch, i, *(int *)&f);
return 0;
}
输出→ch = A i = A f = A
*(int *)&f意为采用读int的方法读f,然后再给出用这种方式读出来的f(相当于强制转换为int类型)
?的ASCII码等于63
其他就是简单的位运算。
5. 下面代码的运行输出结果是什么,并说说你的理解。
int main(int argc, char *argv[]) {
int a[2][2];
printf("&a = %p\t&a[0] = %p\t&a[0][0] = %p\n", &a, &a[0], &a[0][0]);
printf("&a+1 = %p\t&a[0]+1 = %p\t&a[0][0]+1= %p\n", &a+1, &a[0]+1, &a[0][0]+1);
return 0;
}
数组名等于它的地址,数组的地址是它第一个元素的地址,二维数组的元素可以看做一维数组。
输出→
&a = 000000000061FE10 &a[0] = 000000000061FE10 &a[0][0] = 000000000061FE10
&a+1 = 000000000061FE20 &a[0]+1 = 000000000061FE18 &a[0][0]+1= 000000000061FE14
6. 下列程序的功能是什么?有什么问题,你能找出问题并解决它吗?
int* get_array() {
int array[1121];
for (int i = 0; i < sizeof(array) / sizeof(int); i++) {
array[i] = i;
}
return array;
}
int main(int argc, char *argv[]) {
int *p = get_array();
}
array的内存被还回去了,指针指了个寂寞,所以这个程序没有用。
可以使用malloc手动分配空间,参考代码:
int* get_array()
{
int*array=NULL,*save=NULL;
save=array=(int*)malloc(sizeof(int)*1121);
for (int i = 0; i < 1121; i++,array++)
*array = i;
return save;
}
7. 下面代码的运行输出结果是什么,并说说你的理解。
int main(int argc, char *argv[]) {
char str[] = "XiyouLinuxGroup";
char *p = str;
char x[] = "XiyouLinuxGroup\t\106F\bamily";
printf("%zu %zu %zu %zu\n", sizeof(str), sizeof(p), sizeof(x), strlen(x));
return 0;
}
\t(tab) \106(F) \b(退格)分别占一个字节,相当于char类型
其他见 [2022/2. 你好你好你好呀!]
输出:16 8 25 24
8. 如下程序,根据打印结果,你有什么思考?
int add(int *x, int y) {
return *x = (*x^y) + ((*x&y)<<1);
}
int a;
int main(int argc, char *argv[]) {
int b = 2020;
if(add(&b, 1) || add(&a, 1)) {
printf("XiyouLinuxGroup%d\n", b);
printf("Waiting for y%du!\n", a);
}
if(add(&b, 1) && a++) {
printf("XiyouLinuxGroup%d\n", b);
printf("Waiting for y%du!\n", a);
}
return 0;
}
没什么思考,只是感觉花里胡哨的
位运算(&、|、^、~、>>、 | 菜鸟教程 (runoob.com)
9. 在下段程序中,我们可以通过第一步打印出a
的地址,假如在你的机器上面打印结果是0x7ffd737c6db4
;我们在第二步用scanf
函数将这个地址值输入变量c
中;第三步,随机输入一个数字,请问最终输出了什么结果,你知道其中的原理吗?
void func() {
int a = 2020;
unsigned long c;
printf("%p\n", &a);
printf("我们想要修改的地址:");
scanf("%lx", &c);
printf("请随便输入一个数字:");
scanf("%d", (int *)c);
printf("a = %d\n", a);
}
scanf("%lx",&c)把a的地址给c
(int *)c使c强制转化为一个指向整型的指针
于是a被这个指针赋值为那个输入的值
10. 请问一个C语言程序从源代码到可执行文件中间会进行哪些过程,你能简单描述一下每个环节都做了什么事情吗?
同【2021/14. 请谈谈对从「C语言文件到可执行文件」的过程的理解】
11. 请解释一下这行代码做了什么?
puts((char*)(int const[]){
0X6F796958,0X6E694C75,0X72477875,
0X3270756F,0X313230,0X00000A
});
打印 XiyouLinuxGroup2021
见[2022/12. 奇怪的字符]
12. 请随机输入一串字符串,你能解释一下输出结果吗?
int main(int argc, char *argv[]) {
char str[1121];
int key;
char t;
fgets(str, 1121, stdin);
for(int i = 0; i < strlen(str) - 1; i++) {
key = i;
for(int j = i + 1; j < strlen(str); j++) {
if(str[key] > str[j]) {
key = j;
}
}
t = str[key];
str[key] = str[i];
str[i] = t;
}
puts(str);
return 0;
}
对输入的字符进行一个排序
利用的是选择排序,在(str-i-1)个数中,遍历找到最小值后跟第i个字符个字符进行交换。
char *fgets(char *str, int n, FILE *stream):从指定的流里读取一行字符串,然后把它存储在str指向的字符串之中。当读取 (n-1) 个字符时,或者读取到换行符时,或者到达文件末尾时,它会停止,具体视情况而定。
13. 用循环和递归求Fibonacci
数列,你觉得这两种方式那种更好?说说你的看法。如果让你求Fibonacci
数列的第100项,你觉得还可以用常规的方法求解吗?请试着求出前100项的值(tip大数运算)。
递归虽然简洁,但斐波那契数列需要用到双递归,用到的空间会飞速增长。
循环代码比较臃肿,看着丑。
总体来说,我认为循环比较好。
大数运算其实就是用代码模拟竖式计算
大斐波那契数_陶鸿杰的博客-CSDN博客
14. Linux 实操题
请通过命令创建一个目录,在该目录中创建几个后缀为
.Linux
的文件,然后通过命令查询这几个文件的基本属性信息(如文件大小,文件创建时间等),之后使用命令查看该目录下文件名含有“.Linux
”的文件的数量(不包括子目录下的文件),把得到的数字写入到一个文件中,最后删除此目录。
mkdir fold
cd fold
touch a.Linux
touch b.Linux
ls -I
echo "2" > a.Linux
cd ..
rm -r fold