C语言编程题练习 📔(从初识到入门再到进阶)
小飞机 🛬
输入学生信息 👨🎓
计算表达式的值
计算y的值
利用函数递归(按顺序打印数字每一位)
什么是递归
程序调用自身的编程技巧称为递归( recursion )。递归做为一种算法在程序设计语言中广泛应用。一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。
递归的主要思考方式在于:把大事化小
递归的两个必要条件
- 存在限制条件,当满足这个限制条件的时候,递归便不再继续
- 每次递归调用之后越来越接近这个条件
从大到小输出数字
打印3的倍数
最大公约数
打印闰年
打印素数
素数只能被1和它本身整除,例如判断13(i)是不是素数,就是产生2到12(2到i-1)的数字
九九乘法表 ✖️
二分查找
小乐乐走台阶
斐波那契数
斐波那契数列(Fibonacci sequence),又称“黄金分割”数列,比如这样一个数列:1,1,2,3,5,8,13,21,34,55,89... ...数列从第3项开始,每一项都等于前两项之和。在C语言中,我们可以用多种方式来实现斐波那契数列。本文针对以下三种方式来体现每种方法的效率:1.递归,2.非递归 3.数组。
- 递归。该递归属于多分支递归,会造成栈溢出
- 非递归。非递归较递归效率更高,避免了重复计算的时间和空间。
- 数组
字母大小写转换
描述
KiKi想完成字母大小写转换,有一个字符,判断它是否为大 写字母,如果是,将它转换成小写字母;反之则转换为大写字母。
输入描述:
多组输入,每一行输入一个字母。
输出描述:
针对每组输入,输出单独占 一行,输出字母的对应形式。
示例1
变种水仙花
描述
变种水仙花数 - Lily Number:把任意的数字,从中间拆分成两个数字,比如1461 可以拆分成(1和461),(14和61),(146和1),如果所有拆分后的乘积之和等于自身,则是一个Lily Number。
例如:
655 = 6 * 55 + 65 * 5
1461 = 1 * 461 + 14 * 61 + 146*1
求出 5位数中的所有 Lily Number。
序列中删除指定数字
最高分与最低分之差
方法一
冒泡排序将数组中的数重新排序一遍,然后最大的减去最小的得到最高分和最低分的差值
利用冒泡排序算法解决十个乱序数字排成升序数字
方法二
传统方法,先设数组中的第一个数为最大值,然后遍历一遍数组中的数跟第一个数比较,如果都小于,则第一个数最大,如果比第一个数大,此时大的值为最大的。相同方法求出最小值
方法三
建立在方法三的基础之上的,我们看到方法二中的代码求最大值和最小值分别用了两次遍历,加长了代码的长度和重复性,所以在这里我们可以简化一下,在求最大值的时候同时也在求最小值,这样就只需要遍历一遍就可以同时得到最大值和最小值了
方法四
方法四又是建立在方法三之上的,在方法三的基础上我们发现我们是在所有数全部输入之后才进行遍历找出最大值,此时我们思考一下是不是可以在输入的时候就可以便输入便求出最大值呢,首先在题目中我们规定了最大不能超过100,最小不能低于0,所以在这里我们可以现设最小值就是100,然后在输入中,如果小于100的话,那么此时那个值就是最小值,如果后面还有更小的,又可以将它赋值给最小值,同理设最大值为0,可以同时在输入的时候求出最大值。
写一个函数返回参数二进制1的个数
求两个数二进制中不同位的个数 ‼️
打印整数二进制的奇数位和偶数位
X形图案
三角形判断 📐
获得月份天数
逆序打印字符串
计算求和
打印水仙花数
菱形打印
喝汽水问题
冒泡排序 🗯️
qsort函数排序 🔜
1. qsort()函数简介
qsort()函数是C语言库函数中的一种排序函数,排序方法为快速排序(quick sort) 。
其特点是可以排序任意类型的数组元素。
1.1 函数原型
需引用头文件:<stdlib.h>或<search.h>
1.2 函数参数
qsort()函数需要四个参数
- void* base: 需排序数组首元素
- size_t num: 数组元素个数
- size_t size: 一个数组元素大小(byte)
- int (comparator) (const void elem1 , const void* elem2): 是一个函数指针,其指向的是一个比较函数的地址,该函数有两个void* 的参数,其返回类型为int 。
void* 类型指针:可以接收任意类型的地址,但不能进行解引用操作和不能对其进行加减整数的操作。
2.比较函数简介
2.1比较函数参数
比较函数为自定义函数:其两个参数为void*类型指针的elem1和elem2 ,返回参数为整形int
参数类型为void原因:不清楚需比较元素的类型是什么,所以通过void*类型指针的特点(可以接收任意类型的地址)来接收。const修饰其两个比较参数不可被更改
返回值有三种情况:
< 0 : elem1 小于 elem2
= 0 : elem1 等于 elem2
0 : elem1 大于 elem2
2.2 比较函数使用
如需使用比较函数而void*类型指针不能解引用操作和加减整数操作我们只需对两个元素进行强制类型转换为我们想比较元素的类型指针,再进行解引用获取两个元素的值,最后进行两个元素的差值返回。
整型数组
字符数组
浮点型数组
字符串
按首字母排序
按字符串长度排序
按正常排序
结构体
对学生姓名排序
对学生成绩排序
3. qsort()函数使用
3.1 整形数组排序
3.2 字符数组排序
3.3 浮点型数组排序(double类型为例)
3. 4 字符串数组排序
按字符串首字母排序
按正常排序
3.5 结构体
【C语言】指针经典笔试八题 🉑
前言
指针往往是变幻莫测,灵活多变,只有深入理解其本质才能有深刻的体会。
下面通过八道经典笔试题,来一起深入理解指针的神奇之处。
笔试题1
程序运行的结果是什么呢?
答案
为什么会这样呢?
详细解释如下:
(a + 1) - 解释:
*(ptr - 1) - 解释·:
此时的ptr指针就是一个整形指针,对其减一就是向前跳动一个整形的地址指向了蓝色箭头的位置,*(ptr - 1)是以整形指针的视角去读取所指空间的内容,也就是从蓝色箭头的指针处向后访问一个整形(4个字节)的长度,所以读到的就是5。
笔试题2
*程序运行的结果是什么呢?*
*备注:*
//p是结构体指针
//假设p 的值为0x100000。 如下表表达式的值分别为多少?
//已知,结构体Test类型的变量大小是20个字节
答案:
为什么会这样呢?
详细解释如下:
计算机内存十一字节划分的,一个字节都有一个对应的地址,地址是由16进制来表示的。
printf("%p ", p + 0x1); - 解释:
p = (struct Test*)0x100000;
是将0x100000 强制类型转换成(struct Test*)这个结构体的地址。
而我们知道指针的类型决定了指针加减整数的时候跳过的字节数;
如:int*类型的指针 + 1 跳过4个字节,
char* 类型的指针 + 1跳过1个字节,
所以结构体类型的指针 + 1 就跳过一个结构体。
因为这个结构体的大小为20个字节,+1之后指针就向后跳20个字节,20的16进制是14
所以结果就为00100014。
printf("%p ", (unsigned long)p + 0x1); - 解释:
(unsigned long)p 是将这个结构体的地址强制类型转换成无符号整形
整形数字 + 1就是+1,所以结果是00100001。
printf("%p ", (unsigned int*)p + 0x1); - 解释:
(unsigned int*)p 是将p强制类型转换成整形指针,整形指针+1就是跳过四个字节,
所以结果是00100004。
补充
大小端存储:
全称:大端字节序存储 小端字节序存储
大端字节序存储:
当一个数据的低字节的数据存放在高地址处,高字节的内容放在了低地址处
这样的存储方式就是大端字节序的存储。
小端字节序存储:
当一个数据的低字节的数据存放在低地址处,高字节的内容放在了高地址处
这样的存储方式就是小端字节序的存储。
写一个小程序来判断当前机器的字节序是大端还是小端:
临时变量存放在栈区,栈区使用地址的习惯是从高地址到低地址。
32位平台下,1的存储。
二进制:00000000000000000000000000000001
十六进制:00 00 00 01
char* p = (char*)&a; - 将整形指针强制类型转换成字符指针。
*p;访问第一个字节(低字节向高字节读取), 所以 *p 就拿到了低字节的存储数据。小端存储示意图:
大端存储示意图:
笔试题3
*程序运行的结果是什么呢?*
答案:
为什么会这样呢?
详细解释如下:
注意:本题的输出方式为十六进制输出。
ptr1[-1] - 解释:
与笔试1类似,不再赘述。
*ptr2 - 解释:
a是数组首元素的地址,是十六进制的,强制类型转换成整形(int)之后再 + 1
再强转成整形指针,也就是在上几部操作后,a的地址数值加了1,地址加1
就是向后偏移了一个字节。在VS的环境下:存储方式为小端存储
ptr从 01 指向了后一个字节 00。
(int*)((int)a + 1) 再将其强转成整形指针,再向后访问四个字节并以十六进制的方式输出,
所以结果是:2 00 00 00。
以什么形式存储,就以什么形式输出,以小端存储方式存入,就以小端的方式输出。
笔试题4
*程序运行的结果是什么呢?*
答案:
为什么会这样呢?
详细解释如下:
这道题很简单,逗号表达式是从左到右一次执行,并以最后一个值作为整个表达式的值。
所以,数组内部布局为:
0 12 3
4 5所以p[0]就为第一个元素1。
笔试题5
*程序运行的结果是什么呢?*
答案:
详细解释如下:
p是一个数组指针,p能够指向的数组是4个元素,
a 为二维数组的数组名,二维数组的数组名表示二维数组第一行的地址。
同时二维数组可以理解为一位数组组成的数组。
p = a;
那么p + 1是向后跳了四个整形(int)16个字节。
详解图:
a[4][2]的地址比p[4][2]的地址高4,所以结果为-4;
计算机存数据是以补码的形式存储:
-4的存储
100000000 00000000 00000000 00000100 - 原码
111111111 11111111 11111111 11111011 - 反码
111111111 11111111 11111111 11111100 - 补码
以%p的形式输出,就是以16进制的形式输出,结果为:FF FF FF FC。
笔试题6
程序运行的结果是什么呢?
答案:
详细解释如下:
与前面几题有所雷同,再次不再过多赘述。
只强调一点:&aa得到的是整个二维数组的地址,对其+ 1是跳过整个二维数组。
笔试题7
程序运行的结果是什么呢?
答案:
详细解释如下:
注意:
形如 char* p = "abcdefg";这样的p为字符指针,存放的是字符串首元素的地址。同时它是 只 读 的 ,是不能被修改的。如果 *p = ‘w’;这样操作的话,编译器报警告。
(访问权限冲突)
a[]就是一个指针数组,里面存放的都是字符指针。
a是数组名是数组首元素的指针,char** pa;说明pa是个指针,这个指针指向的类型是个字符指针。
pa++;就是相当于pa + 1,首元素向后跳动一个字符指针,便是"at"这个字符串的首地址。
笔试题8
答案:
详细解释如下:
一开始布局:
c中放的是字符串首地址。
cp中放的是c中元素得地址。
cpp放的是cp首元素地址。
**++cpp - 解释:
补充:操作符的优先级:++ 高于 * 高于 + 高于 -
先对cpp自增一次,此时cpp指向了(c + 2)的位置,一次解引用操作就拿到了cp数组中的(c + 2),再次解引用操作就拿到了c数组中第3个元素,第三个是个元素是字符指针,这个字符指针存放的是POINT这个字符串的首地址,%s拿到了POINT首地址向后打印,所以结果为POINT。
*-- * ++cpp + 3 - 解释:
cpp现在原只向的(c + 2)位置上自增1,此时指向了(c + 1)的位置上,解引用一次便拿到了(c + 1),因为 -- 的优先级比+高,先执行 -- ,(c + 1)自减变成了c,再解引用一次,就拿到c[]数组的第一个元素,第一个元素存的是ENTER的首地址,再对首地址 + 3,跳过三个字符,指向了E。%s拿到了E的地址向后打印,结果就是ER。
*cpp[-2] + 3 - 解释:
cpp[-2] + 3 <==> ((cpp - 2)) + 3,cpp在指向原来的(c + 1)位置,而(cpp - 2)向前跳动两个char**的元素指向了(c + 3)的位置,但是cpp本身的值没变,这时对(cpp - 2)解引用一次就拿到了(c + 3),再对(c + 3)解引用*一次就拿到了c[]数组中的最后一个元素,c[]数组中的最后一个元素存的是FIRST字符串的首地址,对其+3就是跳过三个字符,指向了S。%s拿到了S的地址向后打印,结果就是ST。
cpp[-1][-1] + 1 - 解释:
cpp[-1][-1] + 1 <==> ((cpp - 1) - 1) + 1,cpp在指向原来的(c + 1)位置,(cpp - 1)向前跳动一个char**的元素指向了(c + 2)的位置,但是cpp本身的值没变,这时对(cpp - 1)解引用*一次就
拿到了(c + 2),再对(c + 2) - 1得到了(c + 1),再对(c + 1)解引用*一次就拿到了c[]数组中的第二个元素,c[]数组中的第二个元素存的是NEW这个字符串的首地址,对其 +1就是跳过c语言基础编程题一个字符,指向了E。%s拿到了E的地址向后打印,结果就是EW。
总结: ✏️
指针往往比较灵活且多变,空想很难有想出答案,最好的方法就是:画图。
结合题目的要求找到对应关系,当把所有的关系理清时,会有一种拨开迷雾见青山的快感。
小乐乐该数字
思路:
带空格直角三角形的图案
思路:
网购
确定比赛名次 🎲
谁是凶手 🔪
打印杨辉三角
思路:
字符串左旋 ⏪
思路:
思路2:
杨氏矩阵
思路:
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/bian-cheng-ji-chu/32.html