1. 请试着解释其输出。
int main(int argc , char *argv[]) {
unsigned char a = 255;
char ch = 128;
a -= ch;
printf("a = %d ch = %d\n", a, ch);
}
- 结果为
127 -128
- 注意无符号类型unsigned char,a=255-128=127;
- 因为ch是char类型,有符号,表示范围为 -128~127,此时已经超过其范围,因此结果为-128(具体见下图)
2. 下面代码的运行输出结果是什么,并说说你的理解。
int main(int argc, char *argv[]) {
char *str = "Xi You Linux Group 20";
printf("%d\n", printf(str));
return 0;
}
- 涉及到一个知识点:printf的返回值
- 返回值是指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;
}
- 结果如下
- static int 与 int 的区别:
static int
不管在函数内还是函数外,都作为一个全局变量可以保存它被修改以后的值。而int
则没有这一功能,只有作为全局变量时能保存修改。 - c语言中static关键字用法详解
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
- 前两个不解释
- 第三个:
unsigned int f = 33554433;//在(0 ~ 4 294 967 295)的范围内
*(int *)&f >>= 24;//将f进行位运算中的右移24位,结果为2
*(int *)&f = *(int *)&f + '?';//2+63(?的阿斯克码)=65(A的阿斯克码)
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,&a[0],&a[0][0]地址都相同
,但是&a表示整个数组的地址,&a[0]表示数组第一行的地址,&a[0][0]表示第一行第一列的地址(也就是首元素的地址) -
&a+1
表示整个数组的地址加上2* 2*int(一个数组)类型大小的地址(相当于&b) -
&a[0]+1
表示第一行地址加上一个2*int(一行)类型大小的地址(相当于&a[1]) -
&a[0][0]+1
表示首元素地址加上一个int类型的大小的地址(相当于&a[0][1])
多卷一些?戳!
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的指针从而输出array数组中的值问题
:array在函数作用完后会自动释放内存而带不回返回值,因此p会找不到此数组的地址,使p成为野指针解决
#include<stdio.h>
#include<stdlib.h>
int* get_array()
{
n=1121;
int*array=(int*)malloc(sizeof(int)*n);
int*t=array;
for (int i=0; i<sizeof(int)*n/sizeof(int); i++,array++)
*array = i;
return t;
}
int main(int argc, char *argv[])
{
n=1121;
int *p=get_array();
for(int i=0;i<n;i++,p++)
printf("%d ",*p);
return 0;
}
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;
}
- 先解释 %zu ,它和%d的区别在于:%d输出int型,%zu输出size_t型,而size_t在库中定义为unsigned int,即:一个是整型,一个是无符号整型
- 再看结果
16 8 25 24
(编译器在64位下运行) - 前两个不解释
- 第三个和第四个大同小异,这里只解释最后一个:在x中\t \106(三位八进制) \b分别占一个字节,相当于char类型,因此结果为15(X~p)+1+1+1(F)+1+5=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;
}
- 解析如下
int add(int *x, int y)
{
return *x = (*x^y) + ((*x&y)<<1);//每进函数一次a+1,b+1
}
int a;//全局变量初始化为0
int main(int argc, char *argv[])
{
int b = 2020;
if(add(&b, 1) || add(&a, 1))//进入
{
printf("XiyouLinuxGroup%d\n", b);//b=2021
printf("Waiting for y%du!\n", a);//a=0
//a=0说明add(&a,1)并没有被执行,在逻辑或时若满足第一个表达式,会发生短路现象
//这样会提高计算机的运算效率
}
if(add(&b, 1) && a++)//逻辑和时add(&b,1)和a++都被执行
//不会进入if语句,因为a++表达式是先运算再自增,在进行逻辑和的时候a还是0
{
printf("XiyouLinuxGroup%d\n", b);
printf("Waiting for y%du!\n", a);
}
return 0;
}
- 结果如下
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);
}
输出的结果为输入的数字
- 输入一个整数在被强制转换为指针类型c 所指向的地址(就是&a,也是c),
而因为原本c就是a的地址(c=&a),相当于(int * )c指向a的地址并且赋值c,就是a=c
10. 请问一个C语言程序从源代码到可执行文件中间会进行哪些过程,你能简单描述一下每个环节都做了什么事情吗?
11. 请解释一下这行代码做了什么?
puts((char*)(int const[]){
0X6F796958,0X6E694C75,0X72477875,
0X3270756F,0X313230,0X00000A
});
- 这里涉及到一个知识点:大端法,小端法
- 在了解这个之前,先了解一个专业词:字节序。字节序,顾名思义就是字节的排列顺序,而计算机中既可以从高位到低位进行排列,也能从低位到高位进行排列
- 现在再来看大端法、小端法:假设有数据0x12345678,左边为高字节,右边为低字节。将高字节的数据放在低地址,便是大端法;反之,为小端法
- 下图,上面一排为字节的存放地址,从左到右,地址由低到高;下面一排为字节,分别存放在不同的地址中
大端法
小端法
- 一般家庭计算机所使用的为小端法,因此根据以上知识并查阅阿斯克码表可得,该程序的输出为
XiyouLinuxGroup2021
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;
}
- 运用了选择排序的思想
- 这里需要注意的是:fgets()函数
- fgets() 函数中的 size 如果小于字符串的长度,那么字符串将会被截取;如果 size 大于字符串的长度则多余的部分系统会自动用 ‘\0’ 填充。
13. 用循环和递归求Fibonacci
数列
你觉得这两种方式那种更好?说说你的看法。如果让你求
Fibonacci
数列的第100项,你觉得还可以用常规的方法求解吗?请试着求出前100项的值(tip大数运算)。
- 递归代码简洁
- 循环时间短
- 斐波那契数列的两种方法(递归和循环)
全题终。。。。。。
点个赞再走呗ヾ(•ω•`)o