单选
1. 单选
以下for循环的执行次数是()
for(int x = 0, y = 0; (y = 123) && (x < 4); x++);
A. 是无限循环
B. 循环次数不定
C. 4次
D. 3次
解析
for(初始化部分;条件判断部分:调整部分)
{
循环语句部分;
}
初始化部分:用于循环变量的初始化
条件判断部分:用于判断循环什么时候结束
调整部分:用于循环变量的调整
循环语句部分
- 初始化部分,将x初始化为0,y初始化为0,并且初始化部分只会进行一次
- 条件判断部分,用逻辑与连接起来的表达式,左右都为真,整体才为真,其他情况都为假。
- 左边为赋值语句,给变量y赋值为123,结果为123,非0,为真
- 整个表达式的结果与右边有关,x<4时整个表达式的结果为真
- 调整部分:x++,每次循环结束以后,x+1
- x初始化为0,x<4时会进入循环,每次循环结束x+1
- 所以当x=0,1,2,3时会进入循环,x=4时会结束循环
- 所以for循环的执行次数是4次
- 选C
2. 单选
以下程序的运行结果是()
#include <stdio.h>
int main(void)
{
printf("%s , %5.3s\n", "computer", "computer");
return 0;
}
A. computer , puter
B. computer , com
C. computer , computer
D. computer , compu.ter
解析
- 不同的格式化去打印相同的字符串
- %s去打印字符串,遇到\0会停止打印
- 常量字符串在最后的位置会有一个\0
- 所以第一个computer会完整的打印出来
- %m.ns:m表示小数点前的数字,n表示小数点后的数字
- m:表示输出字符串的宽度
- n:表示左起截取目标字符串n个字符,并且是右对齐,补空格
- 当字符串长度>n>m时,m的作用就失效了,只受n控制,左起截取目标字符串n个字符进行输出即可
- 当n>字符串长度时,作用和%s是一样的,遇到字符串最后一个\0,就会停止打印
- %5.3s:输出的字符串的宽度为5,然后左起截取目标字符串3个字符(com),左边差两个不够,补空格,( com)
- 最后的结果:computer, com
- 选B
3.单选
下列main()函数执行后的结果为()
int func()
{
int i, j, k = 0;
for(i = 0, j = -1; j = 0; i++, j++)
{
k++;
}
return k;
}
int main()
{
cout << (func());
return 0;
}
A. -1
B. 0
C. 1
D. 2
解析
- func函数定义了一个k变量初始化为0,最后将k的值返回出来,在main函数中输出出来
- k变量每次在for循环中k++
- 这个题的本质在问for循环能够执行多少次
- 变量i初始化为0,j初始化为-1
- 条件判断部分,是一个赋值语句,j赋值为零,这个条件的结果为0,是假的,所以不会进入for循环,k的变量的值是不会增加的,是将0这个值返回出去,进行输出
- 所以正确结果就是0
- 选B
4.单选
下面程序输出是什么?
#include <stdio.h>
int main()
{
int a=1,b=2,c=3,d=0;
if(a == 1 && b++==2)
if(b!=2||c--!=3)
printf("%d,%d,%d\n" ,a,b,c);
else
printf("%d,%d,%d\n" ,a,b,c);
else
printf("%d,%d,%d\n" ,a,b,c);
return 0;
}
A. 1,2,3
B. 1,3,2
C. 3,2,1
D. 1,3,3
解析
- else语句:有就近匹配if语句原则
- 所以第一个else和第二个if匹配,第一个if和最后一个else配套
- 逻辑与表达式,两边的表达式都为真的时候,整个表达式才为真,否则都为假
- 变量a等于1,和1比较,相等,表达式结果为真,
- b++ == 2,因为是后置++,先拿b的值和2比较,也就是b等于2和2比较,相等,表达式结果为真,比较完以后,b++,b为3
- 所以整体的表达式为真,进入第二个if语句
- 逻辑或表达式,至少某一边的表达式为真的话,整个表达式为真
- 左边b != 2,上一步b已经为3了,所以这里为真
- 逻辑或有短路原则,左边的表达式为真的话,右边的表达式就不会执行
- 所以直接进行printf语句,输出abc三个变量的值
- a为1,b为3,c因为没有执行逻辑或右边的表达式,所以不会–,为3
- 最后的结果是1,3,3
- 选D
5.单选
若有定义语句:
int a=10 ;
double b=3.14 ;
则表达式'A'+a+b
值的类型是()
A. char
B. int
C. double
D. float
解析
- 定义了一个int类型的整型变量a,初始化为10,一个double类型的变量b,初始化为3.14
- 问表达式字符A+变量a+变量b的类型是什么
- 不同类型的表达式进行计算的时候,有自动提升的过程,表示范围小的数据类型会自动提升为表示范围大的数据类型
- 字符A,char数据类型,占1个字节,范围-128~127
- 变量a,int数据类型,占4个字节,范围-21亿~21亿
- 变量b,double数据类型,占8个字节,范围2.3x10-308~1.7x10308
- 所以计算的时候,char和int数据类型会自动提升为double数据类型,整个表达式的数据类型就是double数据类型
- 选C
6.单选
在
int p[][4] = {{1}, {3, 2}, {4, 5, 6}, {0}};
中,p[1][2]
的值是()
A. 1
B. 0
C. 6
D. 2
解析
- 定义了一个二维数组,并且进行了初始化,在二维数组的声明中,可以看到,省略了行数,列是4列
- 行可以通过初始化部分去获得,每个大括号表示一行,4个大括号表示4行,所以这个二维数组是4行4列的
- 这里每一行都没有进行完全初始化,在没有初始化的部分会默认为0
- 把二位数组整个写出来
1000
3200
4560
0000 - 这里通过下标访问数组元素,二维数组中行和列都是从0开始,所以
p[1][2]
的值为0 - 选B
7.单选
选择表达式 11|10 的结果(本题数值均为十进制)()
A. 11
B. 10
C. 8
D. 2
解析
- 计算11按位或上10的结果
- 先将十进制数字转为二进制数字
- 11:0000 1011
- 10:0000 1010
- 按位或:对应的比特位至少有一个1,对应的结果就为1,
- 11|10:0000 1011
- 转换为十进制:11
- 所以正确结果是11
- 选A
8.单选
int fun (int a)
{
a^=(1<<5)-1;
return a;
}
fun(21)运行结果是()
A. 10
B. 5
C. 3
D. 8
解析
- 先分析fun函数,根据int a传参,通过异或给参数赋值,再将结果返回出来
- ^=:异或赋值,将a异或b的结果赋值给a
- a^=b; -> a = a^b;
- <<:左移运算符
- 1<<5:0000 0001将它左移5位:0010 0000,转化为十进制:32
- a^=(1<<5)-1 -> a = a^(1<<5)-1 -> a = a^31
- a = 21^31
- 21:0001 0101
- 31:0001 1111
- a = 21^31
- 按位异或:对应的比特位如果一个为0一个为1,则最后的结果为1,其他情况都为0
- 21^31:000 1010
- 转换为十进制:10
- 选A
9.单选
若有定义语句:int year=1009,*p=&year;
以下不能使变量 year 中的值增至 1010 的语句是()
A. *p+=1;
B. (*p)++;
C. ++(*p)
D. *p++
解析
- 定义了year变量,赋初值1009
- 将year变量的地址作为指针变量p的初始值
- A:
*
运算符的优先级是要高于+=
运算符的,所以先对指针变量p进行解引用,获取到指针所指向的地址的值,也就是year变量1009。再+=1,也就是将year1009+1赋给year变量,所以可以。 - B、C:B选项和C选项的区别是前置和后置++,因为都带了括号,都是先对p变量进行解引用,获取到对应地址的值,也就是year1009,再进行++,所以可以满足条件
- D:不可以。因为后置++的优先级高于
*
号,所以要先对p指针进行++,因为是后置++,所以在真正++之前先对p变量进行解引用,获取到year变量的值,再对指针p进行++,所以没有对year值进行++,所以不会
- A:
- 选D
10.单选
下面关于"指针"的描述不正确的是()
A. 当使用free释放掉一个指针内容后,指针变量的值被置为NULL
B. 32位系统下任何类型指针的长度都是4个字节
C. 指针的数据类型声明的是指针实际指向内容的数据类型
D. 野指针是指向未分配或者已经释放的内存地址
解析
A:当用free释放掉一个指针以后,只是销毁了指针指向的空间,并没有将指针置空,此时指针指向一个已经被销毁的空间,这时就是野指针
造成野指针的原因
在定义指针的时候未进行初始化
在free掉指针后没有置空
越界访问,超越作用域去使用指针
- 选A
编程题
1.编程题
组队竞赛__牛客网 (nowcoder.com)
知识点
排序 贪心
题目
- 牛牛举办了一次编程比赛,参加比赛的有
3*n
个选手,每个选手都有一个水平值a_i.现在要将这些选手进行组队,一共组成n个队伍,即每个队伍3人.牛牛发现队伍的水平值等于该队伍队员中第二高水平值。 - 例如:
一个队伍三个队员的水平值分别是3,3,3.那么队伍的水平值是3
一个队伍三个队员的水平值分别是3,2,3.那么队伍的水平值是3
一个队伍三个队员的水平值分别是1,5,2.那么队伍的水平值是2
为了让比赛更有看点,牛牛想安排队伍使所有队伍的水平值总和最大。
如样例所示:
如果牛牛把6个队员划分到两个队伍
如果方案为:
team1:{1,2,5}, team2:{5,5,8}, 这时候水平值总和为7.
而如果方案为:
team1:{2,5,8}, team2:{1,5,5}, 这时候水平值总和为10.
没有比总和为10更大的方案,所以输出10.
解析
怎样分组使水平值总和更大
- 思路
- 首先对这一组数据进行排序:125558
- 然后分别取第一个和后两个作为一组(1,5,8)(2,5,5,),这样水平值总和为10
- 这样子取,第一组一定会拿到一个最高值和一个仅次于最高值的值,这样一定会包含一个比最大值更小的一个元素
- 例251437698
- 排序:123456789
- 分组:(1,8,9)(2,6,7)(3,4,5)
- 8+6+4=18,最优解
- 那么,如何知道864在哪个地方
- 推导公式:假设一个数组arr.len - 2*(i+1)
- 对第一个例子来说,len = 6,当len = 6时,分为2组
- 取一个for循环
for(int i = 0; i < n;)
- 当i=0时,
6-2*1=4
,正好是第五个数字的下标 - 当i=1时,
6-2*2=2
,正好是第三个数字的下标
- 取一个for循环
- 对第二个例子来说,len = 9,当len = 9时,分为3组
- 取一个for循环
for(int i = 0; i < n;)
- 当i=0时,
9-2*1=7
,正好是第八个数字的下标 - 当i=1时,
9-2*2=5
,正好是第六个数字的下标 - 当i=2时,
9-2*3=3
,正好是第四个数字的下标
最后理一下顺序
- 取一个for循环
- 首先处理输入,把数据输入进来
- 然后对数组排序
- 最后根据公式取值
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main()
{
//输入
long long sum = 0;// 用于存储最终结果的变量 sum
int n;
cin >> n;// 输入一个整数 n,表示每组数据的大小
vector<int> a;// 创建一个整型向量 a,用于存储输入的 3n 个数
a.resize(3*n);// 调整向量 a 的大小为 3n,以存放输入的数据
// 循环读取输入的 3n 个数
for(int i = 0; i < 3*n; i++)
{
cin >> a[i];
}
// 将向量 a 中的元素从小到大排序
std::sort(a.begin(),a.end());
// 从排序后的向量 a 中选取每组中第二大的数,共选取 n 个数,并将它们累加到 sum 中
for(int i = 0; i < n; i++)
{
sum = sum + a[a.size() - 2*(i+1)];
}
// 输出最终的累加结果 sum
cout << sum << endl;
return 0;
}
这段代码的功能是从输入中读取一个整数 n
,表示每组数据的大小。然后,读取 3n
个整数,并存储到大小为 3n
的整数向量 a
中。接着,对向量 a
中的元素进行排序。最后,从排序后的向量 a
中选取每组中第二大的数,共选取 n
个数,并将它们累加到变量 sum
中,最终输出 sum
的值。
- 由于牛客是循环输入,也可以用另一种
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main()
{
int n;
while(cin >> n)
{
long long sum = 0;
vector<int> a;
a.resize(3*n);
for(int i = 0; i < 3*n; i++)
{
cin >> a[i];
}
std::sort(a.begin(),a.end());
for(int i = 0; i < n; i++)
{
sum = sum + a[a.size() - 2*(i+1)];
}
cout << sum << endl;
}
return 0;
}
2.编程题
删除公共字符_牛客题霸_牛客网 (nowcoder.com)
知识点
字符串 模拟
题目
- 输入两个字符串,从第一字符串中删除第二个字符串中所有的字符。例如,输入”They are students.”和”aeiou”,则删除之后的第一个字符串变成”Thy r stdnts.”
- 每个测试输入包含2个字符串
- 输出删除后的字符串
输入:
They are students.
aeiou
输出:
Thy r stdnts.
解析
输入的是字符,字符对ASCII表总共有256个
可以给一个数组,利用哈希的思想
第一个字符串abcdef
第二个字符串be
结果acdf
- 遍历第二个字符串str2上的每一个字符,把每一个对应的字符放到hash[]
b的ASCII值是98,在数组98下标的位置上放b出现的次数,b第一次放进来,初始我为0,++显示1
e放在相应的下标上,初始为0,++显示1
int hash[256]={0};
hash[str2[i]]++;
- 遍历第一个字符串str1,找到等于0的,需要保留的字符
拿每一个字符,a对应的hash数组的97下标的值为0,表示a是想要的结果,保留;轮到b,b不为0,不是想要的结果,依次往后循环 - 最后输出acdf
注意
输入的字符串中间有空格隔开
cin >> str1;
cin >> str2;
不能这样写,cin遇到空格就结束了
#include <iostream>
#include <string>
using namespace std;
int main()
{
//输入两个字符串
string str1, str2;
getline(cin, str1);
getline(cin, str2);
//创建哈希数组,用于记录字符串str2中每个字符的出现次数
int hash[256] = {0};
for(int i = 0; i < str2.size(); i++)
{
hash[str2[i]]++;
}
//创建结果字符串 ret,用于存储不在字符串str2中出现的字符
string ret = "";
for(int i = 0; i < str1.size(); i++)
{
if(hash[str1[i]] == 0)
{
ret += str1[i]; //每次将不在str2中出现的字符加入ret
}
}
//输出结果字符串 ret
cout << ret << endl;
return 0;
}
这段代码的功能是找出两个输入字符串 str1
和 str2
中,只在 str1
中出现而在 str2
中未出现的字符,并将其输出。代码通过创建一个大小为 256 的哈希数组 hash
来记录 str2
中每个字符的出现次数,然后遍历 str1
,将不在 str2
中出现的字符添加到结果字符串 ret
中,最后输出 ret