一、选择题
1、1. 使用printf函数打印一个double类型的数据,要求:输出为10进制,输出左对齐30个字符,4位精度。以下哪个选项是正确的?
A %-30.4e
B %4.30e
C %-30.4f
D %-4.30f
答案:C
解析:默认是右对齐,左对齐要加-,所以是%-30.4f
2、请找出下面程序中有哪些错误()
int main()
{
int i = 10;
int j = 1;
const int* p1;//(1)
int const* p2 = &i; //(2)
p2 = &j;//(3)
int* const p3 = &i;//(4)
*p3 = 20;//(5)
*p2 = 30;//(6)
p3 = &j;//(7)
return 0;
}
A 1,2,3,4,5,6,7
B 1,3,5,6
C 6,7
D 3,5
答案:C
解析:常量指针:所指空间的值不能发生改变,不能通过指针解引用修改指针所指空间的值,但是指针的指向可以发送改变
指针常量:指针本身是一个常量,指针的指向不能发生改变,但是指针所指空间的值是可以发生改变的,可以通过指针解引用改变指针所值空间的值
区别:const在 * 的左边是常量指针,const在 * 的右边是指针常量
p2是一个常量指针,p3是一个指针常量,所以(6)、(7)是错的
3、下面叙述错误的是()
char acX[] = "abc";
char acY[] = { 'a','b','c' };
char* szX = "abc";
char* szY = "abc";
A acX与acY的内容可以修改
B szX与szY指向同一个地址
C acX占用的内存空间比acY占用的大
D szX的内容修改后,szY的内容也会被更改
答案:D
解析:acX和acY是在栈上开辟的,可以修改。A对
szX和szY指向同一个常量字符串,所以指向同一个地址。B对
acX是字符串初始化,末尾有一个‘\0’,也会占一个空间,占了4可空间,acY是字符数组初始化,没有‘\0’,占了3个空间。C对
szX的内容修改后,也就是说szX的指向发生改变,而常量字符串没有发生改变,而szY的指向并没有发生改变,所以常量字符串也没有发生改变
4、在头文件及上下文均正常的情况下,下列代码的运行结果是()
int a[] = { 1, 2, 3, 4 };
int* b = a;
*b += 2;
*(b + 2) = 2;
b++;
printf("%d,%d\n", *b, *(b + 2));
A 1,3
B 1,2
C 2,4
D 3,2
答案:C
解析:经过* b += 2、* (b + 2) = 2 后,数组里的元素变为 3,2,2,4,经过b++后,b指向第二个元素,所以* b、* (b + 2) 的结果为2、4
5、下列关于C/C++的宏定义,不正确的是()
A 宏定义不检查参数正确性,会有安全隐患
B 宏定义的常量更容易理解,如果可以使用宏定义常量的话,要避免使用const常量
C 宏的嵌套定义过多会影响程序的可读性,而且很容易出错
D 相对于函数调用,宏定义可以提高程序的运行效率
答案:B
解析:由于宏定义没有类型安全检测,并且是在预处理阶段进行宏替换的,所以无法进行调试的,所以要尽量使用const常量
6、有以下定义:
int a[10];
char b[80];
函数声明为:
void sss(char[], int[]);
则正确的函数调用形式是()
A sss(a,b);
B sss(char b[],int a[]);
C sss(b[],a[]);
D sss(b,a);
答案:D
7、用变量a给出下面的定义:一个有10个指针的数组,该指针指向一个函数,该函数有一个整形参数并返回一个整型数()
A int *a[10];
B int (*a)[10];
C int (*a)(int);
D int (*a[10])(int);
答案:D
A是指针数组。B是数组指针。C是函数指针,有一个int参数,返回值类型也是是int。D是函数指针数组,有一个int参数,并返回int
8、以下 C++ 函数的功能是统计给定输入中每个大写字母的出现次数(不需要检查输入合法性,所有字母都为大写),则应在横线处填入的代码为()
void AlphabetCounting(char a[], int n) {
int count[26] = {}, i, kind = 10;
for (i = 0; i < n; ++i)
_________________;
for (i = 0; i < 26; ++i) {
printf("%c=%d", _____, _____);
}
}
A ++count[a[i]-‘Z’]
‘Z’-i
count[‘Z’-i]
B ++count[‘A’-a[i]]
‘A’+i
count[i]
C ++count[i]
i c
ount[i]
D ++count[‘Z’-a[i]]
‘Z’-i
count[i]
答案:D
9、在32位CPU上选择缺省对齐的情况下,有如下结构体定义:
struct A
{
unsigned a : 19;
unsigned b : 11;
unsigned c : 4;
unsigned d : 29;
char index;
};
则sizeof(struct A)的值为()
A 9
B 12
C 16
D 20
答案:C
解析:unsigned类型首先会开辟一个4字节的空间,也就是32比特位,a占19个比特位,b占11个比特位,c占4比特位,d占29比特位,占满32个比特位后,还会开辟一个4字节的空间,所以unsigned类型开辟了12个字节的空间,所以struct A一共开辟了13个空间,内存对齐后,为16字节
10、下面代码会输出()
int main()
{
int a[4] = { 1,2,3,4 };
int* ptr = (int*)(&a + 1);
printf("%d", *(ptr - 1));
}
A 4
B 1
C 2
D 3
答案:A
解析:(int*)(&a + 1)会偏移整个数组的大小,所以指向的位置是最后一个元素的下一个位置,ptr - 1 向后偏移一个位置,所以打印的结果为4
二、编程题
1、排序子序列
入口:题目连接
题目描述:
题目解析:
本题要求解的是排序子序列,排序子序列为非递增或者非递减,注意:非递减就是a[i]<=a[i+1],递减就是a[i]>a[i+1],非递增就是a[i]>=a[i+1],递增就是a[i]<a[i+1]。
解题思路:
- 本题依次比较整个数组
- a[i+1]>a[i] ,则进入非递减序列判断,直到遍历到下一个值不大于等于为止count++,然后进行下一位
置的判断 - a[i+1]<a[i],则进入非递增序列判断,直到遍历到下一个值不小于等于为止count++,然后进行下一位
置的判断 - a[i+1] == a[i]不进行操作,++i进行下一位置遍历,因为相等既可以属于非递增序列,也可以属于非递减
序列。
本题注意点:本题开始比较a[i+1]与a[i]进行比较,为了避免越界,数组定义为n+1个,同时给a[n] = 0;
a[n] = 0带来的影响,我们分为三种情况讨论:
- 若到a[n-1] 的最后一组是非递减序列,当i==n-1,a[i] >a[i+1],因为前面的数都是大于0的,这个输入
条件已经说明了(去看看题目输入条件描述),里面的循环结束,i++,count++,i == n,外面的循环结
束。 - 若到a[n-1] 的最后一组是非递增序列,当i==n-1,a[i] >a[i+1],因为前面的数都是大于0的,这个输入
条件已经说明了(去看看题目输入条件描述),循环再走一次,i++, i == n,里面的循环结束,i++,
count++,i ==n+1,外面的循环结束。 - 第三种情况 1 2 1 2 1最后一个数是单独的情况,后面补个0,序列变成1 2 1 2 1 0,当走完全面的序列
i==n-1时,a[i] > a[i+1],进入判断出一个非递增序列,count++,i++,循环结束。 - 也就是说数组最后一个位置多增加一个0,不会影响第1、2情况的判断,主要是帮助第3情况的正确判
断。
代码展示:
#include <iostream>
#include <vector>
using namespace std;
int main()
{
int n = 0;
cin >> n;
vector<int> a;
a.resize(n + 1);
a[n] = 0;
for (int i = 0; i < n; i++)
{
cin >> a[i];
}
int i = 0;
int count = 0;
while (i < n)
{
if (a[i] < a[i + 1])
{
//注意i不能一直加,要i<n,但是i+1会越界,
//要多开一个空间,还要a[n]=0
while (i < n && a[i] <= a[i + 1])
{
i++;
}
count++;
i++;
}
else if (a[i] == a[i + 1])
{
i++;
}
else
{
while (i < n && a[i] >= a[i + 1])
{
i++;
}
count++;
i++;
}
}
cout << count << endl;
return 0;
}
2、倒置字符串
入口:题目连接
题目描述:
题目解析:
一段字符串中的前后单词交换,以单词为单位逆置。
解题思路1:
先将整个字符串逆置过来,再遍历字符串,找出每个单词,对单词逆置。这里我们使用了stl算法中的
reverse,所以这里使用迭代器遍历string
代码展示:
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int main()
{
string str;
getline(cin, str);
// 翻转整个句子
reverse(str.begin(), str.end());
// 翻转单词
auto start = str.begin();
while (start != str.end())
{
auto end = start;
while (end != str.end() && *end != ' ')
{
end++;
}
reverse(start, end);
if (end != str.end())
{
start = end + 1;
}
else
{
start = end;
}
}
cout << str << endl;
return 0;
}
解题思路2:
第二思路是一个比较讨巧的思路,直接利用cin>>s接收输入,遇到空格就结束了,自然就分割开了每个单
词,其次将每次接收到的单词拼接到之前串的前面就逆置过来了
代码展示:
#include <iostream>
#include <string>
using namespace std;
// cin读取string时自动会被空格分隔开,用另一个字符串存储进行逆序输出
int main()
{
string s1, s2;
cin >> s2;
while (cin >> s1)
s2 = s1 + " " + s2;
cout << s2 << endl;
return 0;
}