当前位置: 首页 > news >正文

【C语言进阶】题目练习

目录

1.箭形图案

思路: 

代码:

2. 公务员面试

分析:

代码 :

3. 判断结构体大小(1)

答案:

分析:

4.判断结构体大小(2)

答案:

分析:

5.宏定义+计算位段大小的选择题

分析: 

答案:

6.位段与指针

分析:

答案:

7. 结构体大小判别

分析: 

答案:

8.联合体的大小

分析:

答案:

9.大小端字节序

分析:

答案:

10.枚举选择题

答案:

11. 编程题:找出只出现一次的数字

分析1:

代码1:

思路2:

代码2:

12.atoi的实现

13.文件读写的选择题(1)

14.看代码说功能

15. 文件读写的选择题(2)

16.预处理的选择题

17.预处理的分析题

18.feof函数的选择题

19.宏替换的选择题(1)

20.宏替换的选择题(2)

21.写一个宏将一个整数的二进制位的奇数和偶数进行交换

思路:


1.箭形图案

KiKi学习了循环,BoBo老师给他出了一系列打印图案的练习,该任务是打印用“*”组成的箭形图案。

输入描述:

本题多组输入,每行一个整数(2~20)。

输出描述:

针对每行输入,输出用“*”组成的箭形。

输入

2

输出

    ***
******

思路: 

        可以把图形分为上下两部分,如果输入n上面就是n行,下面就是n+1行;

上半部分:n行

空格:第一行有四个空格,第二行有两个空格,我们可以把2个空格当做一组,第一行打印两组,第二行打印一组;每一行需要递减,所以内部循环减去外面的行数。

*:和行数有关,第一行是一个,第二行是两个。

下半部分:n+1行

空格:两个空格为一组,第一行是0组空格,第二行是1组空格,第三行是2组空格,就是行数-1。

*:第一行是3个*,第二行是2个*,第3行是1个*,每次从n+1开始,需要再减去行数。

代码:

#include<stdio.h>int main() 
{int n = 0;while(scanf("%d",&n)){
// 上半部分for (int i = 0; i < n; i++){for (int j = 0; j < n - i; j++){printf("  "); // 先打印空格,两个为一组}for (int k = 0; k <= i; k++) // 第一行一个*,第二行两个*,跟行号有关{printf("*");}printf("\n");}// 下半部分for (int i = 0; i < n + 1; i++){// 空格for (int j = 0; j < i; j++){printf("  ");}for (int k = 0; k < n + 1 - i; k++){printf("*");}printf("\n");}}return 0;
}

2. 公务员面试

描述

公务员面试现场打分。有7位考官,从键盘输入若干组成绩,每组7个分数(百分制),去掉一个最高分和一个最低分,输出每组的平均成绩。

(注:本题有多组输入)

输入描述:

一行,输入7个整数(0~100),代表7个成绩,用空格分隔。

输出描述:

一行,输出去掉最高分和最低分的平均成绩,小数点后保留2位,每行输出后换行。

示例1

输入:

99 45 78 67 72 88 60

输出:

73.00

分析:

        本身的逻辑不难,难的是如何oj,我们之前是每次读取一个数字,我们这道题可以一次读取一个数字,也能读取一个数字。

        若读取一个数字,我们需要一个变量n来记录读取数字的个数,每次读取n需要++;

        定义最大最小值并设立处置,每次读取一个数字就需要判断是否是最大或者最小值,以此保证最小最大值保持更新,一旦n ==7,说明数字够了,就开始计算平均值,需要将这些变量进行重新初始化以待下一次实例的调用。

代码 :

#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>int main() {int score = 0;int max = 0;int min = 100; int n = 0;int ret = 0;while (scanf("%d", &score) == 1) {n++;if(score > max){max = score;}if (score < min ) {min = score;}ret += score;if (n == 7) {printf("%.2lf\n",(ret - min - max)/5.0);n = 0;ret = 0;max = 0;min = 100;}}return 0;
}

3. 判断结构体大小(1)

判断以下两个结构体的大小:

#include<stdio.h>struct A 
{int a;short b;int c;char d;
};struct B 
{int a;short b;char c;int d;
};int main() 
{struct A a = { 0 };struct B b = { 0 };printf("%d\n",sizeof(a)); // 16printf("%d\n",sizeof(b)); // 12return 0;
}

答案:

16,12

分析:

A:a占4个字节偏移量0-3;b占2个字节,对齐数是2,偏移量是4-5;c占4个字节,偏移量是4,6不是4的倍数,所以偏移量是8-11;最后一个d是占1个字节,所以偏移量是12;总共占用13个字节,13不是最大对齐数(4)的倍数,那么最近的倍数是16;

B: a占4个字节偏移量0-3;b占2个字节,对齐数是2,偏移量是4-5;c占1个字节,偏移量是6;d占4个字节,最小对齐数是4,7不是4的倍数,所以偏移量是8,占用8-11;总共占用12个字节,12是最大对齐数的倍数,所以答案是12;

4.判断结构体大小(2)

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#pragma pack(4) // 4字节对齐
struct S1
{short a; // 0-2char d; // 3long b; // 4-7 long c;// 8-11 
};struct S2
{long b;// 0-3short c;// 4-5char d;// 6long a;// 8-11 
};
struct S3
{short c;// 0-1long b;// 4-7char d;// 8long a;// 12-15
};
int main() 
{printf("%d\n", sizeof(struct S1));printf("%d\n", sizeof(struct S2));printf("%d\n", sizeof(struct S3));}

答案:

12 12 16

分析:

见注释,这里需要注意的是32位系统重long占4个字节。

5.宏定义+计算位段大小的选择题

分析: 

①首先需要判断位段占用的bit位数,首先第一个成员变量开辟一个字节的空间,8bit,第一个成员+第二个成员用了6bit,剩余2bit,此时第三个成员变量需要1个字节,需要单独开辟,第四个成员变量虽然只需要1bit,但仍然要开辟1字节,总共3字节。

②注意宏定义:3* 2 + 3 = 9

答案:

D

6.位段与指针

分析:

        首先定义一个char类型的数组,有四个元素;定义一个位段指针指向这个数组;将数组全部初始化为0,;

        位段的第一个成员是占用1个字节,剩下三个成员占用一个字节,所以这个位段整体占用两个字节。

        需要给成员赋值,第一个成员赋值为2,8bit足以存下;

第二个成员只有1bit需要存3,所以只能取低1位bit位;

第三个成员只有2bit需要存4,所以只能取低2位bit位;

第四个成员只有3bit需要存5,刚好可以存下。

此时内存分布如下图所示:

此时按照16进制打印两位来输出每一个字节那么就是:

答案:

0000  0010 -》 02

0010 1001 -》  29

0000 0000 -》  00

0000 0000 -》  00 

7. 结构体大小判别

分析: 

总大小是10B,最大对齐数是4,所以必须是4的倍数12B。

答案:

12字节 

8.联合体的大小

union Un
{short s[7];int n;
};

分析:

        联合体的奥义是成员公用内存,所以s占用14个字节,n占用4个字节,此时14个字节够用了,最后需要考虑最大对齐数是4,所以最终应该是4的倍数,16字节。

答案:

16

9.大小端字节序

注:32位cpu平台

分析:

 首先联合体是2B,这里分别访问数组的第一个元素和第二个元素,这里其实就是给两个字节填充数据;这里需要打印k变量,由于是两个字节,这里就存在字节序大小端的问题,在vs编译器中是采用小端存储,即低字节存在低地址高字节存在高地址(倒着存)那么输出就是0x3839(还原数据,先打印高地址再打印低地址)

 

答案:

3839 

10.枚举选择题

答案:

枚举从0开始,依次递增1,中途可以修改,再依次递增1;

11. 编程题:找出只出现一次的数字

一个数组中有两个数字出现一次其余数字出现了两次,找到这两个只出现了一次的数字。

力扣原题

分析1:

暴力求解,每个元素都要对n个元素进行比较,如果标记到两个元素相等cnt++,如果cnt是1,那么说明只和自己相等,那就是单独的数字了。

代码1:

#include<stdio.h>void find_dog(int arr[], int sz)
{for (int i = 0; i < sz; i++){int cnt = 0;for (int j = 0; j < sz; j++){if (arr[i] == arr[j]){cnt++;}}// cnt = 1的时候需要记录下来if (cnt == 1) {printf("%d是单独的数字!\n",arr[i]);}}
}int main()
{int arr[10] = { 1,2,3,4,5,1,2,3,4,6 };int sz = sizeof(arr) / sizeof(arr[0]);find_dog(arr, sz);return 0;
}

思路2:

        可以利用异或的特性,两个数字异或如果相同结果就是0,相异结果就是1,所以将这所有的数字全部异或,最后的结果一定不为0,我们假定最后异或出来的结果的最后一位是1,那么相当于最后一位是相异的,那么我们可以按照最后一位是0或者1将所有数字分成两组,这两组分别进行异或,就能得到最终相异的数字。

①所有数字异或得到不为0的结果。

②从结果中找到二进制的某一位是1。

③旨在按照此位进行分组,组内进行异或,最后的结果就是其中一个单独的数字。

核心思想:按照根据异或的原理将两个单独的数字分别分为两组,组内进行异或(其余数字都是成对,异或就是0),最终每组只剩下那个单独的数字。

代码2:

/*** Note: The returned array must be malloced, assume caller calls free().*/
int* singleNumber(int* nums, int numsSize, int* returnSize) 
{int sum = 0;int* ret = malloc(2 * sizeof(int));int pos = 0;int dog1 = 0;int dog2 = 0;for(int i = 0;i < numsSize;i++){// 1.全部异或得到一个数字sum ^= nums[i];}// 2. 根据这个数字的第n位为1进行分组// 3.计算第n位为1for(int i = 0;i < 32;i ++){if(((sum >> i)&1) == 1){pos = i;break;} }//4. 按照第pos位进行分组,组内进行异或for(int i = 0;i < numsSize;i++){if((nums[i] >> pos)&1 == 1){dog1 ^= nums[i];}else{dog2 ^= nums[i];}}ret[0] = dog1;ret[1] = dog2;*returnSize = 2;return ret;
}

12.atoi的实现

        即字符串转换成整数,例如“123456” -》 123456、“-123456” -》 -123456,遇到非数字的时候停止转化,“-123abc456” -》 -123;

        需要考虑以下几点:

①空指针。assert判断。

②空字符串。字符串只有\0,如果返回0,那就会和“0”产生歧义。

③空格。使用isspace判断是否是空格,是空格那么str++跳过空格。

④+-号。定义一个正负号的变量,如果遇到+变量置为1,遇到-变量置为-1,最后返回只需要结果*flag即可。

⑤非数字字符。若字符串为123ABC,应该输出123

正常处理:需要将每一位的数字转换成整型,存入变量,接下来变量只需要*10 + 新这一位的数字即可。

⑥越界问题:当字符串内的数字非常大,此时就可能发生越界,此时我们需要判断是正数越界还是负数越界

做到这里,我们可以将简易版的代码写出:

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<assert.h>
#include<ctype.h>
#include <limits.h>
// 判断这个字符串是否合法
enum STATUS
{VALID,INVALID
}status = INVALID;int my_atoi(const char* str)
{// 正负标记int flag = 1;long long ret = 0;assert(str);// 空字符串,返回非法0if (*str == '\0'){return 0;}// 判断空白字符,跳过while (isspace(*str)){str++;}// 遇到+-号if (*str == '+'){flag = 1;str++;}else if (*str == '-'){flag = -1;str++;}// 正常处理数字字符串while (*str != '\0'){if (isdigit(*str)) {ret = ret * 10 + flag * (*str - '0');// *str是字符,需要-字符'0'转换成对应的数字// 判断是否越界if (ret > INT_MAX || ret < INT_MIN) {status = INVALID;return 0;}}else{// 不是数字字符status = INVALID;return str;}str++;}// 没有提前返回说明是正常处理完毕if(*str == '\0'){status = VALID;}return ret;
}int main()
{char arr[100] = "123456";int ret = my_atoi(arr);if (status == INVALID){printf("数字不合法!:%d\n", ret);}else if (status == VALID){printf("数字为:%d\n", ret);}return 0;
}

测试:

含非数字字符:

 

负数: 

溢出:

 

13.文件读写的选择题(1)

B:getchar适用于标准输入流。

14.看代码说功能

统计文件的字符个数 

15. 文件读写的选择题(2)

 

D:sprintf是把格式化的数据写入字符串中。

16.预处理的选择题

 C:链接阶段会查找符号表,看这个函数是否存在。

17.预处理的分析题

判断变量的类型

#define INT_PTR int*
typedef int* int_ptrINT_PTR a,b;
int_ptr c,d;

替换完毕后是:int *a,b,那么a是int*类型,b是int类型;

下面不一样,把int*当做一个整体的类型,c,d都是int*类型。

18.feof函数的选择题

A:错误,解析详见B选项。

19.宏替换的选择题(1)

答案:70

直接替换计算: 2*(4 + Y(5+1)),Y(5+1)是31。

20.宏替换的选择题(2)

答案:B 

21.写一个宏将一个整数的二进制位的奇数和偶数进行交换

思路:

        假如红色位置是偶数位,绿色位置是奇数位;将奇数位的数字全部拿出来,向右移动一位;同理将偶数位的数字都拿出来,向左移动一位,最后相加即可。 

        怎么拿?以偶数位举例,与一个偶数位都是1,奇数位都是0的32位数字即可。

 

#define SWAP_BIT(n) (((n&0x55555555)<<1) + ((n&0xaaaaaaaa)>>1))int main() 
{int n = 10;printf("%d\n", SWAP_BIT(n));return 0;
}

 这里用10进行测试,1010 -> 0101(5)

http://www.dtcms.com/a/305124.html

相关文章:

  • docker部署zingerbee/netop 轻量级网络流量监控工具
  • 河南萌新联赛2025第(二)场:河南农业大学(补题)
  • 高端医疗超声AFE模拟前端应用
  • 机器学习之线性回归——小白教学
  • 关于为什么写分配法搭配写回法?非写分配法搭配全写法?
  • python基础:request请求查询参数的基本使用、携带请求参数的两种方法、 json串和python中数据类型转化、 post模拟登录
  • 全方位Python学习方法论:从入门到精通的系统指南
  • GB/T 4706.1-2024 家用和类似用途电器的安全 第1部分:通用要求 与2005版差异(21)
  • 【Spring】日志级别的分类和使用
  • 计算机视觉-局部图像描述子
  • 代理IP轮换机制:突破反爬虫的关键策略
  • AI驱动的知识管理新时代:释放组织潜力的关键武器
  • win10 环境删除文件提示文件被使用无法删除怎么办?
  • MPLS 专线网络
  • 字符集学习
  • 实现多路标注截图
  • GESP2025年6月认证C++七级( 第三部分编程题(1)线图)
  • Spring Boot中的this::语法糖详解
  • Spring与数学的完美碰撞
  • 偏二甲肼气体浓度报警控制系统
  • 自适应双门限的能量检测算法
  • Python算法实战:从排序到B+树全解析
  • TDengine:用AI改变数据消费范式
  • linux命令ps的实际应用
  • 学习Python中Selenium模块的基本用法(3:下载浏览器驱动续)
  • 微服务快速入门
  • BehaviorTree.Ros2 编译教程
  • JavaWeb 入门:JavaScript 基础与实战详解(Java 开发者视角)
  • 飞算科技:以原创之力,开启Java开发新纪元与行业数智变革
  • 技术QA | GNSS模拟器如何赋能自动驾驶?聚焦HIL、多实例与精准轨迹仿真的技术优势