2021-2023西邮linux兴趣小组纳新题

2023

0.鼠鼠我啊,要被祸害了

有 1000 瓶水,其中有一瓶有毒,l小白鼠只要尝一点带毒的水,24 小时后就会准时死亡。
至少要多少只小白鼠才能在 24 小时内鉴别出哪瓶水有毒?

将1000瓶水的标签转化会二进制,也就是0000000000到1111101000。然后将第一位为1的水混合在一起喂给小鼠,如果小鼠死亡则毒水二进制的一位为1,以此类推10次便可以得到毒水二进制编号,转化为10进制即可。

1.先预测一下~

按照函数要求输入自己的姓名试试~

char *welcome() {
 // 请你返回自己的姓名
}
int main(void) {
 char *a = welcome();
 printf("Hi, 我相信 %s 可以面试成功!\n", a);
 return 0; }

如果是在函数中填写//char a[20]=“yunjian”; return a; 最后会输出 我相信(null)可以面试成功!
我的名字去哪里了呢?由于a为字符串数组,存储在栈中,在函数结束后,栈的内存释放,导致a的地址指向了(null)成为空指针。
所以可以有两种做法,一是在 char前加入 static 关键词 ,使成为静态变量延长其生命周期。
二是 ,申请动态规格,,char* a=(char*)malloc(sizeof(char)*7);(只是因为yunjian为7个字符长度)
strcpy(a,“yunjian”); 或者 a=“yunjian”;

当然也可以绕过不使用变量,char* a=“yunjian”;
或者直接返回字符串 return “yunjian”;

2.欢迎来到 Linux 兴趣小组

有趣的输出,为什么会这样子呢~

int main(void) {
 char *ptr0 = "Welcome to Xiyou Linux!";
 char ptr1[] = "Welcome to Xiyou Linux!";
 if (*ptr0 == *ptr1) {
 printf("%d\n", printf("Hello, Linux Group - 2%d", printf("")));
 }
 int diff = ptr0 - ptr1;
 printf("Pointer Difference: %d\n", diff);
}

输出:

Hello, Linux Group - 2023
Pointer Difference: -2077387488 //(这会是个随机值)

1,printf()函数是从右往左读的,2,printf()函数的返回值为打印的字符串长度(包括空格)所以会打印出Hello, Linux Group - 2023
3,*ptr0为字符串常量,存放在静态区域,而ptr1[]是字符串变量,存放在栈中,地址当然不一样了,所以地址有差值。

3.一切都翻倍了吗

① 请尝试解释一下程序的输出。
② 请谈谈对 sizeof()和 strlen()的理解吧。
③ 什么是 sprintf(),它的参数以及返回值又是什么呢?

int main(void) {
 char arr[] = {'L', 'i', 'n', 'u', 'x', '\0', '!'}, str[20];
 short num = 520;
 int num2 = 1314;
 printf("%zu\t%zu\t%zu\n", sizeof(*&arr), sizeof(arr + 0),//第一个将arr取地址在引用,没有变化,arr数组占7个长度,而arr+0,把arr当作数组的首地址,为指针类型,为8字节。
 sizeof(num = num2 + 4));//num为short类型,2字节(不转化类型)
 printf("%d\n", sprintf(str, "0x%x", num) == num);//str="0x208";
 printf("%zu\t%zu\n", strlen(&str[0] + 1), strlen(arr + 0));//第一个是取str[0]的长度开始加一地址,其跳跃度为1(char),因此从'x'开始计算,为4;
}//而strlen(arr+0) 从'L'开始 ,值为5;

输出:

7 8 2
0
4 5

②sizeof()(为运算符)为字节数(计算时连带’\0’),strlen()(为string.h的函数) 计算char*字符串的长度(读到’\0’结束)
③sprintf() 为string.h的函数,参数为 sprintf( char *,const char *,(传入值可为int double char 等等));
作用将第二给参数打印进第一个参数中(char *)(不打印进终端);
返回值与printf()的返回值类似,为打印的长度

4.奇怪的输出

程序的输出结果是什么?解释一下为什么出现该结果吧~

int main(void) {
 char a = 64 & 127;//100000 &111111==100000==64
 char b = 64 ^ 127;//100000 &111111==011111==63
 char c = -64 >> 6;//-100000 >> 6=-000001==-1
 char ch = a + b - c;//64+63-(-1)==128;
 printf("a = %d b = %d c = %d\n", a, b, c)//64 63 -1
 printf("ch = %d\n", ch);//126
}

位运算,如注释

5.乍一看就不想看的函数

“人们常说互联网凛冬已至,要提高自己的竞争力,可我怎么卷都卷不过别人,只好用一些奇技淫
巧让我的代码变得高深莫测。”
这个 func()函数的功能是什么?是如何实现的?

int func(int a, int b) {
 if (!a) return b;
 return func((a & b) << 1, a ^ b);
}
int main(void) {
 int a = 4, b = 9, c = -7;
 printf("%d\n", func(a, func(b, c)));
}

功能:实现两数相加
实现:由于位运算a+b=(a^b)+((a&b)<<1);(亦或运算相当于相加不进位,而与运算再右移相当于进位)
使这个等式递归,到进位(a&b)<<1==0时,便不进位了,a&b=a+b;

6.自定义过滤

请实现 filter()函数:过滤满足条件的数组元素。
提示:使用函数指针作为函数参数并且你需要为新数组分配空间。

typedef int (*Predicate)(int);
int *filter(int *array, int length, Predicate predicate,
 int *resultLength); /*补全函数*/

int isPositive(int num)
 { return num > 0; }

int main(void) {
 int array[] = {-3, -2, -1, 0, 1, 2, 3, 4, 5, 6};
 int length = sizeof(array) / sizeof(array[0]);
 int resultLength;
 int *filteredNumbers = filter(array, length, isPositive,
 &resultLength);
 for (int i = 0; i < resultLength; i++) {
 printf("%d ", filteredNumbers[i]);
 }
 printf("\n");
 free(filteredNumbers);
 return 0; }`

//补全函数

typedef int (*Predicate)(int);//predicate 指针指向一个返回值为int (int)的函数
int *filter(int *array, int length, Predicate predicate, int *resultLength)
{ int *filteredNumbers=(int *)malloc(sizeof(int)*length);
int j;
for(int i=0 ,j=0;i<length ; i++){

    if(predicate(array[i])){
   filteredNumbers[j]= array[i] ;
   j++;
   }
*resultLength=j;
}

return  filteredNumbers ;    
}

7.静…态…

① 如何理解关键字 static?
② static 与变量结合后有什么作用?
③ static 与函数结合后有什么作用?
④ static 与指针结合后有什么作用?
⑤ static 如何影响内存分配?

① 关键词,静态
② 与局部变量的结合,改变变量的生命周期(不改变作用域),与全局变量结合改变其作用域(使其属性从外部链接变为内部链接)。
③ 与全局变量差不多,使其属性从外部链接变为内部链接,使其它文件无法使用该函数。
④ 指针的指向的地方是不变的(如果不重新赋值),其指向的东西可以变。(当变量)
⑤ 将局部变量直接放入静态区(和全局变量放一起了)(最开始放在栈区的)

8.救命!指针!

数组指针是什么?指针数组是什么?函数指针呢?用自己的话说出来更好哦,下面数据类
型的含义都是什么呢?

int (*p)[10];//一个数组指针。指针指向一个10个int 元素的数组
const int* p[10];//一个指针数组,数组里有10个类型为指向const int的指针元素
int (*f1(int))(int*, int);//函数指针,指向一个返回值类型为(返回值类型为int,形参为(int*,int )的函数)的函数。

9.咋不循环了

程序直接运行,输出的内容是什么意思?

int main(int argc, char* argv[]) {
 printf("[%d]\n", argc);
 while (argc) {
 ++argc;
 }
 int i = -1, j = argc, k = 1;
 i++ && j++ || k++;
 printf("i = %d, j = %d, k = %d\n", i, j, k);
 return EXIT_SUCCESS; }

argc(初始为一)为int 类型, 一直循环至2^31之后超出界限变为0之后,循环结束。
argc为命令行的文件的数量 ,argv[]为文件名称,argv[0]为本文件的路径

10.到底是不是 TWO

#define CAL(a) a * a * a
#define MAGIC_CAL(a, b) CAL(a) + CAL(b)
int main(void) {
 int nums = 1;
 if(16 / CAL(2) == 2)//if(16/2*2*2 ==2)   16/2*2*2等于32;(考点:宏定义单纯的文本替换,不会进行运算)
  {
 printf("I'm TWO(ノ>ω<)ノ\n");
 } else {
 int nums = MAGIC_CAL(++nums, 2);//为定义行为
 //赋值从右往左,nums=++nums*++nums*++nums+8;

 //(由于乘法两数相乘,同时进行,所以如果nums==1,则答案会是3*3*4+8==32)
 //算是局部函数,将nums全局变量覆盖掉了(这个是最后输出为1的原因)
 
 }
 printf("%d\n", nums);//1
}

11.克隆困境

试着运行一下程序,为什么会出现这样的结果?
直接将 s2 赋值给 s1 会出现哪些问题,应该如何解决?请写出相应代码。

struct Student {
 char *name;
 int age;
};
void initializeStudent(struct Student *student, const char *name,
 int age) {
 student->name = (char *)malloc(strlen(name) + 1);
 strcpy(student->name, name);
 student->age = age; }
int main(void) {
 struct Student s1, s2;
 initializeStudent(&s1, "Tom", 18);
 initializeStudent(&s2, "Jerry", 28);
 s1 = s2;
 printf("s1 的姓名: %s 年龄: %d\n", s1.name, s1.age);
 printf("s2 的姓名: %s 年龄: %d\n", s2.name, s2.age);
 free(s1.name);
 free(s2.name);
 return 0; }

s1=s2会出现free(); double free detected in tcache 2
free()检测到双空闲空间,在执行程序的过程中对同一个空间释放了两遍
为什么呢?由于s1=s2的操作是结构体浅拷贝,两个结构体公用一个内存空间
解决方法,用strcpy函数将第二个字符串放进第s1的地址。使其的空间独立。

12.你好,我是内存

作为一名合格的 C-Coder,一定对内存很敏感吧~来尝试理解这个程序吧!

struct structure {
 int foo;//0-3
 union {
 int integer;
 char string[11];
 void *pointer;
 } node;//8-23
 short bar;//24~25
 long long baz;//32~39
 int array[7];//40-71
};
int main(void) {
 int arr[] = {0x590ff23c, 0x2fbc5a4d, 0x636c6557, 0x20656d6f,
 0x58206f74, 0x20545055, 0x6577202c, 0x6d6f636c,
 0x6f742065, 0x79695820, 0x4c20756f, 0x78756e69,
 0x6f724720, 0x5b207075, 0x33323032, 0x7825005d,
 0x636c6557, 0x64fd6d1d};//18*4=72
 printf("%s\n", ((struct structure *)arr)->node.string);//将arr数组的首地址
}

大小端:低地址存储到内存高地址处为小端,而存储到高地址处为大端。
而一般的电子设备都为小段存储,因此像int 类型的%s,字符读出,那就是用asllc码为字符,直到遇\0截至。

内存对齐:(上题有说)导致联合体度内存为8开始,之后强制内存转换,使从0x636c6557开始,
又因为小端存储,从57 ->W,65->e …如此,读到’\0’为止

Welcome to XUPT , welcome to Xiyou Linux Group [2023]

内存对齐

13.GNU/Linux (选做)

注:嘿!你或许对 Linux 命令不是很熟悉,甚至你没听说过 Linux。但别担心,这是选做题,了解
Linux 是加分项,但不了解也不扣分哦!
你知道 cd 命令的用法与 / . ~ 这些符号的含义吗?
请问你还懂得哪些与 GNU/Linux 相关的知识呢~

cd / 回到根目录
cd ~ ( cd ) 进入用户主目录
cd ! 将上个命令参数做为cd参数
cd … 返回上层
cd . 无作用,保持当前层文件
cd - 在最近两次工作目录之间切换
cd …/… 返回2次上层

2022

0. 我的计算器坏了?!

2^10 = 1024对应于十进制的4位,那么2^10000对应于十进制的多少位呢?

取2^1000的10的对数,使其向上取整

1. printf还能这么玩?

尝试着解释程序的输出。

int main(void) {
    if ((3 + 2 < 2) > (3 + 2 > 2))//(5<2)>(5>2)==0>1==0 所以进入else
        printf("Welcome to Xiyou Linux Group\n");
    else
        printf("%d\n", printf("Xiyou Linux Group - 2%d", printf("")));
}

printf()函数从右向左数,且其返回值为字符串长度(包括空格)
所以先打印printf(“”);其返回为0,再打印printf("Xiyou Linux Group - 20);其返回值为22,再打印printf(“22\n”):
最后结果为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: 0, strcmp(p0, p2): -1
sizeof(p0): 12, sizeof(p1): 8, sizeof(*p2): 1
strlen(p0): 11, strlen(p1): 11

1,ptr0为字符串常量,存放在静态区域,而ptr1[]是字符串变量,存放在栈中,地址当然不一样了,所以p0==p1的值为0。
2,strcmp为比较函数, int strcmp (const char
str1 ,const char* str2 ); 比较两个字符串的大小,按ASCLL码比较 ,str1==str2 返回 0;
str1<str2,返回负数,str1>str2,则返回正数。
3,sizeof()及strlen()在2023的第2题。

3. 换个变量名不行吗?

请结合本题,分别谈谈你对C语言中「全局变量」和「局部变量」的「生命周期」理解。

int a = 3;//全局变量 记a1;
void test() {
    int a = 1;//局部变量,记a2,其掩盖全局变量a1
    a += 1;//a2==2;
    {
        int a = a + 1;//a3,掩盖a2,a1
        printf("a = %d\n", a);//此时a未定义,a为随机值
    }
    printf("a = %d\n", a);//a2,输出2
}
int main(void) {
    test();
    printf("a= %d\n", a);//a1=3,此时a2,a3已经释放
}

输出:

a = 1(随机值)
a = 2
a= 3

全局变量与局部变量 看这里~

4. 内存对不齐

union与struct各有什么特点呢,你了解他们的内存分配模式吗。

typedef union {
    long l;
    int i[5];//5*4
    char c;
} UNION;
typedef struct {
    int like;//0-3
    UNION coin;//4-23
    double collect;//24-32
} STRUCT;
int main(void) {
    printf("sizeof (UNION) = %zu\n", sizeof(UNION)); 
    printf("sizeof (STRUCT) = %zu\n", sizeof(STRUCT));
}

输出:

sizeof (UNION) = 20
sizeof (STRUCT) = 32

union 联合体的内存为最大的数据 为int i[5],使用时诺将赋值一个元素,上一个元素将覆盖,而 struct 结构体的内存为 各排列内存之和。
内存对齐为最大(数据类型)的字节数,其的内存分配为最大字节的倍数;(其的可能地址不是放在一起的,中间有空间隔)
(因此若需最小内存,将内存相近的数放相近,使空空间减少)

5.Bitwise

请使用纸笔推导出程序的输出结果。
请谈谈你对位运算的理解。

int main(void) {
    unsigned char a = 4 | 7;//0000 0100 |0000 0111 =0000 0111
    a <<= 3; // a=a*8;(0011 1000)
    unsigned char b = 5 & 7;//0000 0101 &  0000 0111 = 0000 0101
    b >>= 3; //b=0000 0000
    unsigned char c = 6 ^ 7;//0000 0110 ^0000 0111 =0000 0001 
    c = ~c;//取反 1111 1110 (255-1)
    unsigned short d = (a ^ c) << 3; //(0011 1000 ^ 1111 1110)<<3==(1100 0110)<<3==0011 0000
    signed char e = -63;//1011 1111
    e <<= 2;
    printf("a: %d, b: %d, c: %d, d: %d\n", a, b, c, (char)d);
    printf("e: %#x\n", e);//16进制输出
}

输出:

a: 56, b: 0, c: 254, d: 48
e: 0x4

6. 英译汉

请说说下面数据类型的含义,谈谈co nst的作用。

char *const p。//常数变量指针,其内存地址不改变
char const *p。//与3一样指向的字符变量为常量,不改变了
const char *p。//

7. 汉译英

请用变量p给出下面的定义:

含有10个指向int的指针的数组。//int *a[10]
指向含有10个int数组的指针。//int(*a[10])
含有3个「指向函数的指针」的数组,被指向的函数有1个int参数并返回int。//int(*p[3]) (int );

8. 混乱中建立秩序

你对排序算法了解多少呢?
请谈谈你所了解的排序算法的思想、稳定性、时间复杂度、空间复杂度。
提示:动动你的小手敲出来更好哦~
1.冒泡排序

void Sort (int a[],int len)//冒泡排序
{
    for(int i=0;i<len;i++){
        for(int j=0;j<len-i-1;j++){
            if(a[j]>a[j+1]){//比较,交换
                int temp;
                temp=arr[j+1];
                a[j+1]=a[j];
                a[j]=temp;
            }
        }}}

时间复杂度 O(n^2) (最好情况)
空间复杂度 O(1)

2插入排序

void insertsort (int arr[],int len)//插入排序
{
    int i, j, key;
    for(i = 1 ;i < len ; i++){
        key = arr[i];//记录一个数
        j = i-1;
       while((j >= 0) && (arr[j] > key)){//从后向前遍历,倘若符合条件,将该数向后移动
            arr[j+1] = arr[j];
            j--;
            
        }
        arr[j+1] = key;//将记录的数字重新插入数组
    }
}

时间复杂度:O(n^n)(最好情况 O(n))
空间复杂度:O(1)

3.选择排序

void SelectSort(int arr[],int n){
  int begin=0 , end=n-1;
  while(begin < end)
{
  int maxi=begin;
  int mini=begin;
  for(int i=begin ;i <=end;i++){
    if(arr[i] <arr[mini]){
      mini =i;
    }
    if(arr[i] > arr[maxi]){
      maxi=i;
    }
  }
  swap(&arr[mini],&arr[begin]);
  if(begin ==maxi){
    maxi=mini;
  }
  swap(&arr[maxi],&arr[end]);
  begin++;
  end--;
}}

时间复杂度:O(n^2)(最好情况 O(n ^2))
空间复杂度:O(1)

4.希尔排序

#include<stdio.h>
int main(){
    int arr[10] ={3,4,6,7,4,5,2,5,7,8};
    int step =0;
    int temp =0;
    int j, i;
        int n=10;
        for(step =n/2 ; step >0 ;step/=2){
            for(i=step ; i< n ; i++){
        temp=arr[i];
        for( j= i-step ;j >= 0 && arr[j] > temp ; j-=step ){
                arr[j+step]=arr[j];

        }
        arr[j+step] = temp;
        }
        
        }

for(int i=0 ;i <10 ; i++){
    printf("%d ",arr[i]);
}
return 0;

}

时间复杂度平均:O(n^1.3);
空间复杂度:O(1);

5快速排序

void kuaipai(int a[], int left, int right)//快排函数,后为第一个数和
{
	int i, j, t, temp;
	if (left > right)//left>right时,说明已经排序完成,结束循环
		return;
	temp = a[left]; 
	i = left;
	j = right;//遍历需要,不改变传入的数字,i为左指向,j为右指向
	while (i != j){
	while (a[j] >= temp && i < j) j--;
		while (a[i] <= temp && i < j)	i++;//找到小于基准值的数
		if (i < j)//当左指向与右指向没有相遇时
			swap(&a[i],&a[j]);
	}
	a[left] = arr[i];	
	a[i] = temp;//交换基本位置
 
	kuaipai(a,left, i - 1);//继续向左处理
	kuaipai(a, i + 1, right);
}

时间复杂度:O(nlogn)
空间复杂度:O(1)

6,堆排序,归并等

9. 手脑并用

请实现ConvertAndMerge函数:
拼接输入的两个字符串,并翻转拼接后得到的新字符串中所有字母的大小写。

提示:你需要为新字符串分配空间。

char* convertAndMerge(char *a[2]);
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);
}
char* convertAndMerge(char a[2][20]){
  char *str11=(char *)malloc(sizeof(char)*40);
  // for(int i=0;i<strlen(a[0]);i++){
  //   str[i]=a[0][i];
  // }
  // for(int i=strlen(a[0]);i<strlen(a[1])+strlen(a[0]);i++){
  //   str[i]=a[1][i-strlen(a[0])];
  // }
    strcpy(str11, a[0]);
    strcat(str11, a[1]);

  for(int i=0;i<strlen(a[1])+strlen(a[0]);i++){
    if(str11[i]>='A' &&str11[i]<='Z') str11[i]+='a'-'A';
    else str11[i]+='A'-'a';
  }
  return str11;
}

int main(void) {
    char words[2][20] = {"Welcome to Xiyou ", "Linux Group 2022"};

    printf("%s,%d\n", words[0],strlen(words[0]));
    printf("%s,%d\n", words[1],strlen(words[1]));
    char *str = convertAndMerge(words);
    printf("str = %s\n", str);
    free(str);
}

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++;
  }//将上行的arr[5]改为arr[i+1],如果是arr[5],赋值完会被第二轮循环覆盖掉,但是a已经自增了
  for (int i = 0; i < 5; i++) {
    for (int j = 0; j < 5; j++) {
      printf("%4d", arr[i][j]);
    }
    printf("\n");
  }
}

输出

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 <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;
        }
    }
}

与2023第9题;

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);
}

23年13题 同类型题目

13. 小试宏刀

请谈谈你对#define的理解。
请尝试着解释程序的输出。

#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);//交换a,b
    printf("x = %d, y = %d, tmp = %d\n", x, y, tmp);//tmp等于a->1; 输出 ,2,1,1;
    if (x > y) SWAP(x, y, tmp);//又交换回去
    printf("x = %d, y = %d, tmp = %d\n", x, y, tmp);//1,2,2;
    SWAPWHEN(x, y, tmp, SQUARE(1 + 2 + z++ + ++w) == 100);//if(1+2+z++ +++w*1+2+z++ + ++w(等于1+2+3+4+2+4+5不等于100)) 所以if后不交换;
    printf("x = %d, y = %d\n", x, y, tmp);//只有前两个,所以为2,2
    printf("z = %d, w = %d, tmp = %d\n", z, w, tmp);//5,5
}

输出:

x = 2, y = 1, tmp = 1
x = 1, y = 2, tmp = 2
x = 2, y = 2
z = 5, w = 5, tmp = 2

2021

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

23年 3题

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));
}

sizeof (t1) : 16
sizeof(t2): 16

结构体内存对齐:
1结构体的每个成员并不是连续对齐的,
2,其内存为最大的类型*N。(对齐数一般默认为4)
3,所以最好将内存相近的数据放一起。

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);
}

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);
}

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);//1234
  pr = 5678;
  printf("ver = %d\n", ver);//123 (全局变量)
}
int main() {
  int a = 0;
  int ver = 1025;
  for (int a = 3; a < 4; a++) {
    static int a = 5;
    printf("a = %d\n", a);//5
    a = ver;//1025
    func1(ver);//传的1025,输出1026
    int ver = 7;
    printf("ver = %d\n", ver);//7
    func2(&ver);//
  }
  printf("a = %d\tver = %d\n", a, ver);//1025,for的场结束,ver重新为main函数定义的1025;
}

输出

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)); }

5050

递归,三目运算

6.算不对的算术

void func(void) {
  short a = -2;//1111 1111 1111 1110即0xfffe
  unsigned int b = 1;//0000 0000 0000 0000 0000 0000 0000 0001
  b += a;//由于b 为无符号数,-1跨过,变为2^32;//1111 1111 1111 1111 1111 1111 1111 1111(0xffffffff)(补码)
  int c = -1;//c=1111 1111 1111 1111 1111 1111 1111 1111(补码)
  unsigned short d = c * 256;//-
  c <<= 4;//1111 1111 1111 1111 1111 1111 1111 1111 0000
  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);
}

a=0xfffe b=0xffffffff d=0x2022 e=0xffffffff
c=Oxf0

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

int main(void) {
  int a[3][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
  int(*b)[3] = a;//指针指向一个3个int 类型的数组。
  ++b;//加加跳跃为4*3,因此指向a[1][0];
  b[1][1] = 10;//a[2][1](在前b自增了)
  int *ptr = (int *)(&a + 1);//&a的跳跃为9个int指向a[3][3]后一个地址。
  printf("%d %d %d \n", a[2][1], **(a + 1), *(ptr - 1));//a[2][1]之前b[1][1]赋值为10,**(a+1)w为a[1][0]的地址,*(ptr -1)(由于ptr为int*类型的指针-1时地址减少4个字节,因此为a[3][3]的地址)
}

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;
}//正确但是不改变n在函数外n的值。
void func1(int *n) {
  *n += 1;
  n = &a;
}//
void func2(const int *n) {//n指向的值并不改变
  *n += 1;//所以这里是错的(语法错误)
  n = &a;
}
void func3(int *const n) {//指针指向的地址不可以改变
  *n += 1;
  n = &a;//所以这是错误的阿
}
void func4(const int *const n) {//都改不了
  *n += 1;//
  n = &a;//所以两者都是错误的
}

const int和 int const都表示int类型的常量变量
const int *和int const *前者为指针指向的变量为常量,后者为指针为常量

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){
    char *rst=(char *)malloc(sizeof(char)*strlen(s));
    strcpy(rst,s);

        for(int i=0;i<strlen(s);i++) {
        if(*(rst+i)>='A' && *(rst+i)<= 'Z'){
            *(rst+i)-='A'-'a';
        }else if(*(rst+i)>='a' && *(rst+i)<= 'z') *(rst+i)+='A'-'a';
    }
    return rst;


}

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;
}//没有作用,由于函数传的形参

do{}while(0)是,相当于大括号(一个场),在swap2中避免函数中有于t 同名的变量,避免重复声明以及将t 的生命周期在括号后结束
其他方法:

void swap4(int *a ,int * b){
  *a= *a^*b;
  *b= *a^*b;
  *a= *a^*b;
} 
void swap5(int *a ,int *b){
  *a=*a+*b;
  *b=*a-*b;
  *a=*a-*b;
}
void swap6(int *a,int *b){
  *a<<=8;
  *a+=*b;
  *b=*a>>8;
  *a=*a& 0xff;
}

11. 据说有个东西叫参数

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的前提下,完成对argv的遍历吗?

argc:外部输入的参数个数
argv:参数的字符串数组,用来存放指向字符串参数的指针数组

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;
}//此段错误,由于函数结束变量n的空间释放,&n的地址指向Null,而之后进行赋值操作,发生段错误。(空指针)
int main(void) {
  *func1() = 4;
  *func2() = 5;
  *func3() = 6;
}

Segmentation fault段错误:原因1,访问了不存在的内存,2,访问了系统保护或只读的内存地址3,空指针废弃,4堆栈溢出,5内存越界(数组越界)

13. 奇怪的输出

int main(void) {
  int data[] = {0x636c6557, 0x20656d6f, 0x78206f74,
                0x756f7969, 0x6e694c20, 0x67207875,
                0x70756f72, 0x32303220, 0x00000a31};
  puts((const char*)data);
}

23,13,22,13;

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

源代码——>预处理->编译 ->汇编 ->链接

15.堆和栈(选做)

堆和栈

栈由操作系统自动分配释放 ,用于存放函数的参数值、局部变量等,其操作方式类似于数据结构中的栈。堆由开发人员分配和释放, 若开发人员不释放,程序结束时由 OS 回收,分配方式类似于链表。

16.多文件(选做)

多文件

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问,欢迎随时与博主沟通,博主会及时解答。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值