
❄专栏传送门:《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.1 题目1)
[1.2 题目2](#1.2 题目2)
[1.3 题目3](#1.3 题目3)
[1.4 题目4](#1.4 题目4)
[1.5 题目5](#1.5 题目5)
[2.1 记负均正](#2.1 记负均正)
[2.2 旋转数组的最小数字](#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
**题干:**请问下列表达式哪些会被编译器禁止()【多选】
cpp
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 是只读的)。
举个例子:
cpp
*f = 100; // 非法!编译器会报错,因为 *f 是常量。
**作用(限制)范围:**限制的是指针解引用后的值(*f),与指针本身的存储无关。
2、第二个 const(右侧的*const)
禁止的操作:不能修改指针 f 本身的值 (即 f 不能指向其他地址)。
举个例子:
cpp
f = &b; // 非法!编译器会报错,因为 f 是常量指针。
f = NULL; // 非法!
**作用(限制)范围:**限制的是指针变量 f 存储的地址(指针自身的值)。
总结
声明形式 | 禁止的操作 | 允许的操作 |
---|---|---|
int const *const f |
1. 修改 *f (值) 2. 修改 f (指针) |
1. 读取 *f 2. 读取 f (地址) |
**补充:**两个const共同确保了指针和指向的数据都不可变。
1.3 题目3
**题干:**以下程序的输出结果为( )
cpp
#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
**题干:**下面代码段的输出是( )
cpp
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型就不用管它们了)------

代码演示:
cpp
#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)。
当然博主还有一个更加简单的解法,这个解法大家理解起来就简单了------
代码演示:
cpp
//C语言自己写的版本------全局变量array
#include <stdio.h>
int main()
{
int n = 0;
scanf("%d\n", &n);
int array;
int num1 = 0;
int num2 = 0;
double sum = 0.0;
for (int i = 0; i < n; i++)
{
scanf("%d ", &array);
if (array < 0)
{
num1 = num1 + 1;
}
else if (array > 0)
{
num2 = num2 + 1;
sum += array;
}
}
double average = num2 > 0 ? sum / num2 : 0.0;
printf("%d %.11lf", num1, average);
return 0;
}
也可以这样,都是一样的道理------
代码演示:
cpp
//C语言------局部变量arr数组
#include <stdio.h>
int main()
{
int n = 0;
scanf("%d\n", &n);
int num1 = 0;
int num2 = 0;
double sum = 0.0;
for (int i = 0; i < n; i++)
{
int arr;
scanf("%d ", &arr);
if (arr > 0)
{
num1 = num1 + 1;
sum += arr;
}
else if (arr < 0)
{
num2 = num2 + 1;
}
}
double average = num1 > 0 ? sum / num1 : 0.0;
printf("%d %.11lf", num2, average);
return 0;
}
我们学习了C++之后也可以尝试用C++来实现一下,看看自己前段时间C++学得怎么样------

cpp
//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型就不用管它们了)------

代码演示:
cpp
#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])
{
// 最小值在左半部分或就是mid
right = mid;
}
else
{
// 当nums[mid] == nums[right]时,无法判断,缩小右边界
right--;
}
}
return nums[left];
}
这道题是C语言中一道比较经典的题目。
当然博主还有一个更加简单的解法,这个解法大家理解起来就简单了。
我们如果学习了C++也可以尝试用C++实现一下------

cpp
//C++实现
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param nums int整型vector
* @return int整型
*/
int minNumberInRotateArray(vector<int>& nums) {
// write code here
if (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]) {
// 最小值在左半部分或就是mid
right = mid;
} else {
// 当nums[mid] == nums[right]时,无法判断,缩小右边界
right--;
}
}
return nums[left];
}
};
时间复杂度:O(logn);
空间复杂度:O(1)。
目前要写出来C++的写法是比较考验前面C++的学习情况的,当然大家可以尝试去写一写,优先掌握C语言的写法,博主还没有介绍C++的算法题,之后会涉及的,敬请期待!
结尾
往期回顾:
结语:感谢大家的阅读,记得给博主"一键四连",感谢友友们的支持和鼓励!