【C语言16天强化训练】从基础入门到进阶:Day 3
🔥个人主页:艾莉丝努力练剑
❄专栏传送门:《C语言》、《数据结构与算法》、C语言刷题12天IO强训、LeetCode代码强化刷题、洛谷刷题、C/C++基础知识知识强化补充、C/C++干货分享&学习过程记录
🍉学习方向:C/C++方向
⭐️人生格言:为天地立心,为生民立命,为往圣继绝学,为万世开太平
前言:距离我们学完C语言已经过去一段时间了,在学习了初阶的数据结构之后,博主还要更新的内容就是【C语言16天强化训练】,之前博主更新过一个【C语言刷题12天IO强训】的专栏,那个只是从入门到进阶的IO模式真题的训练。【C语言16天强化训练】既有IO型,也有接口型。今天依然是训练五道选择题和两道编程算法题,希望大家能够有所收获!
目录
正文
一、五道选择题
1.1 题目1
1.2 题目2
1.3 题目3
1.4 题目4
1.5 题目5
二、两道算法题
2.1 记负均正
题目理解:
2.2 旋转数组的最小数字
题目理解:
结尾
正文
一、五道选择题
1.1 题目1
题干:已知函数的原型是:int fun(char b[10], int *a); ,假设定义:char c[10];int d; ,那么正确的调用语句是( )
A. fun(c,&d); B. fun(c,d); C. fun(&c,&d); D. fun(&c,d);
解析:正确的调用语句是A. fun(c,&d);。我们先分析一下函数原型int fun(char b[10], int *a);表示函数fun的第一个参数是一个字符数组(或者说字符指针),第二个参数是一个整型指针。
继续分析函数原型:
(1)第一个参数char b[10]:可以直接传递字符数组c数组名(c会退化为指针);
(2)第二个参数int *a):需要传递一个整型变量的地址,因此d应该通过&d传递其地址。
这里我们定义的是char c[10];int d;,所以关键就在于——
1.数组作为参数:char c[10] 作为参数时,实际传递的是char*(d退化为指针);
2.指针参数:int*a 必须传入地址(如&d),不能直接传值(如d)。
补充:
这里唯一正确的调用方式是 A.
fun(c, &d);
,
B选项是错误的,因为它没有传递指针给
int *a
。
1.2 题目2
题干:请问下列表达式哪些会被编译器禁止()【多选】
int a = 248, b = 4;
int const *c = 21;
const int *d = &a;
int *const e = &b;
int const * const f = &a;
A. *c = 32; B. *d = 43 C. e=&a D. f=0x321f
解析:题目问的是“哪些表达式会被编译器禁止”,即哪些操作是非法(违反const规则)的。
我们注意以下几点——
(1)const 在
*
左侧(如const int* 或 int const*):指向的值不可变,指针可变。(2)const 在
*
右侧(如 int *const):指针不可变,指向的值可变。(3)const 在
*
两侧(如int const *const):指针和指向的值均不可变。
所有选项(A、B、C、D)均违反const规则,全部会被编译器禁止。若题目要求“多选”,应全选。
我们再深挖一下选项看看——
问:为什么D选项有两个const,分别都禁止了什么?
1、第一个const(左侧的int const或const int)
禁止的操作:不能通过指针 f 修改它指向的值(即 *f 是只读的)。
举个例子:
*f = 100; // 非法!编译器会报错,因为 *f 是常量。
作用(限制)范围:限制的是指针解引用后的值(*f),与指针本身的存储无关。
2、第二个 const(右侧的*const)
禁止的操作:不能修改指针 f 本身的值(即 f 不能指向其他地址)。
举个例子:
f = &b; // 非法!编译器会报错,因为 f 是常量指针。
f = NULL; // 非法!
作用(限制)范围:限制的是指针变量 f 存储的地址(指针自身的值)。
总结
声明形式 | 禁止的操作 | 允许的操作 |
---|---|---|
int const *const f | 1. 修改 *f (值)2. 修改 f (指针) | 1. 读取 *f 2. 读取 f (地址) |
补充:两个const共同确保了指针和指向的数据都不可变。
1.3 题目3
题干:以下程序的输出结果为( )
#include <stdio.h>
int i;
void prt()
{for (i = 5; i < 8; i++)printf("%c", '*');printf("\t");
}
int main()
{for (i = 5; i <= 8; i++)prt();return 0;
}
A. *** B. *** *** *** *** C. *** *** D. * * *
解析:注意这里i是一个全局变量,i是全局变量,在ptr() 和main() 中共享。
这里 ptr() 中的 for (i = 5; i < 8; i++)会执行 3 次循环(i = 5,6,7),每次打印一个' * ',因此输出 *** 。之后打印一个制表符 \t(tab)。
main()函数中,for (i = 5; i <= 8; i++)会调用 ptr() 4 次(i = 5,6,7,8)。
每次调用ptr()的时候:i 被 ptr() 的 for 循环修改为 8(循环结束后i++使 i 变为8),然后回到main() 的for循环,i++使 i 变为
9
,从而终止循环。因此,只有第一次调用 ptr() 会正常输出*** ,后续调用因为 i 的全局性导致循环条件直接不满足,因而无输出。
实际输出:***
(仅第一次调用有效,其余调用因 i
的值被修改而无输出),答案是A选项。
注意:这里的 * 紧密相连,中间是没有空格的。
1.4 题目4
题干:下面代码段的输出是( )
int main()
{int a=3;printf("%d\n",(a+=a-=a*a));return 0;
}
A. -6 B. 12 C. 0 D. -12
解析:题目是(a+=a-=a*a),计算过程如下:
a * a
→9
。
a -= 9
→3 - 9 = -6
此时
a = -6,我们把-6代入到后面的赋值操作——
a += -6
→-6 + (-6) = -12
。
这样一来,答案就是选项D. -12。
1.5 题目5
题干:下列不能实现死循环的是( )
A. while(1){} B. for(;1;){} C. do{}while(1); D. for(;0;){}
解析:如下所示——
A. while(1){} ——
1 是恒为真条件,因此这是一个典型的死循环,故能实现死循环。
B. for(;1;){} ——
for 循环的中间条件为 1(恒为真),相当于 while(1){} ,故能实现死循环。
C. do{}while(1); ——
do{}while(1); 的条件为 1(恒真),会无限循环,故能实现死循环。
D. for(;0;){} ——
for 循环的中间条件为 0(恒为假),循环体根本不会执行,不能实现死循环。
题目问的是“不能实现死循环”的选项,因此正确答案是D选项。
选择题答案如下:
1.1 A
1.2 ABCD
1.3 A
1.4 D
1.5 D
校对一下,大家都做对了吗?
二、两道算法题
2.1 记负均正
题目链接:HJ97 记负均正
题目描述:
题目理解:
我们需要统计负整数的个数并计算正整数的平均值。
这道题也是IO型的,下面是C语言的模版(IO型就不用管它们了)——
代码演示:
#define _CRT_SECURE_NO_WARNINGS 1
//C语言
#include <stdio.h>int main()
{int n;scanf("%d", &n); // 读取整数个数int negative_count = 0; // 负整数计数器int positive_count = 0; // 正整数计数器int positive_sum = 0; // 正整数总和for (int i = 0; i < n; i++) {int num;scanf("%d", &num); // 读取每个整数if (num < 0) {negative_count++; // 统计负数}else if (num > 0) {positive_count++; // 统计正数positive_sum += num; // 累加正数}// 0不做处理}// 输出负整数个数printf("%d ", negative_count);// 计算并输出正整数的平均值if (positive_count > 0) {double average = (double)positive_sum / positive_count;printf("%.10lf\n", average); // 输出10位小数保证精度}else {printf("0.0\n"); // 没有正整数时输出0.0}return 0;
}
这道题也是C语言中一道比较经典的算法题目。
时间复杂度:O(n);
空间复杂度:O(1)。
我们学习了C++之后也可以尝试用C++来实现一下,看看自己前段时间C++学得怎么样——
//C++实现
#include <iostream>
#include <iomanip> // 用于控制输出精度
using namespace std;int main()
{int n;cin >> n; // 读取整数个数int negative_count = 0; // 负整数计数器int positive_count = 0; // 正整数计数器int positive_sum = 0; // 正整数总和for (int i = 0; i < n; i++) {int num;cin >> num; // 读取每个整数if (num < 0) {negative_count++; // 统计负数}else if (num > 0) {positive_count++; // 统计正数positive_sum += num; // 累加正数}// 0不做处理}// 输出负整数个数cout << negative_count << " ";// 计算并输出正整数的平均值if (positive_count > 0) {double average = static_cast<double>(positive_sum) / positive_count;// 设置输出精度为10位小数cout << fixed << setprecision(10) << average << endl;}else {cout << "0.0" << endl; // 没有正整数时输出0.0}return 0;
}
时间复杂度:O(n),空间复杂度:O(1)。
这个目前要写出来非常考验C++的学习情况,大家可以尝试去写一写,优先掌握C语言的写法,博主还没有介绍C++的算法题,之后会涉及的,敬请期待!
2.2 旋转数组的最小数字
题目链接:JZ11 旋转数组的最小数字
题目描述:
题目理解:
我们需要在旋转后的非降序数组中找到最小数字。由于题目要求时间复杂度为O(logn),我们使用二分查找算法来实现。
这道题是接口型的,下面是C语言的模版(IO型就不用管它们了)——
代码演示:
#define _CRT_SECURE_NO_WARNINGS 1
//C语言
/*** 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可*** @param nums int整型一维数组* @param numsLen int nums数组长度* @return int整型*/
int minNumberInRotateArray(int* nums, int numsLen)
{if (numsLen == 0) return 0; // 处理空数组情况int left = 0;int right = numsLen - 1;while (left < right){int mid = left + (right - left) / 2; // 防止溢出if (nums[mid] > nums[right]){// 最小值在右半部分left = mid + 1;}else if (nums[mid] < nums[right]){// 最小值在左半部分或就是midright = mid;}else{// 当nums[mid] == nums[right]时,无法判断,缩小右边界right--;}}return nums[left];
}
这道题是C语言中一道比较经典的题目。
当然博主还有一个更加简单的解法,这个解法大家理解起来就简单了——
我们如果学习了C++也可以尝试用C++实现一下——
//C++实现
class Solution {public:/*** 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可*** @param nums int整型vector* @return int整型*/int minNumberInRotateArray(vector<int>& nums) {// write code hereif (nums.empty()) return 0; // 处理空数组情况int left = 0;int right = nums.size() - 1;while (left < right) {int mid = left + (right - left) / 2; // 防止溢出if (nums[mid] > nums[right]) {// 最小值在右半部分left = mid + 1;} else if (nums[mid] < nums[right]) {// 最小值在左半部分或就是midright = mid;} else {// 当nums[mid] == nums[right]时,无法判断,缩小右边界right--;}}return nums[left];}
};
时间复杂度:O(logn);
空间复杂度:O(1)。
目前要写出来C++的写法是比较考验前面C++的学习情况的,当然大家可以尝试去写一写,优先掌握C语言的写法,博主还没有介绍C++的算法题,之后会涉及的,敬请期待!
结尾
往期回顾:
【C语言16天强化训练】从基础入门到进阶:Day 2
【C语言16天强化训练】从基础入门到进阶:Day 1
结语:感谢大家的阅读,记得给博主“一键四连”,感谢友友们的支持和鼓励!