目录
选择题
单选
编程题
OR62 倒置字符串⭐
【题目解析】
【解题思路1】
【解题思路2】
【解题思路3】
排序子序列⭐
【题目解析】
【解题思路】
1、使用printf函数打印一个double类型的数据,要求:输出为10进制,输出左对齐30个字符,4位精度。以下哪个选项是正确的?
%-30.4e
%4.30e
%-30.4f
%-4.30f
正确答案:
解析:
转换说明符 转换说明符 描述 %d
有符号十进制整数 %i
有符号十进制整数 %u
无符号十进制整数 %o
八进制整数 %x
十六进制整数(小写字母) %X
十六进制整数(大写字母) %f
浮点数 %e
用科学计数法表示的浮点数(小写字母e) %E
用科学计数法表示的浮点数(大写字母E) %g
根据数值的大小自动选择 %f
或%e
格式%G
根据数值的大小自动选择 %f
或%E
格式%c
单个字符 %s
字符串 %p
指针地址 %n
将已打印字符数保存在整型指针中 %%
打印一个百分号
- %-m.nf
- -m:前加 - 号,表示左对齐(不加 - 号,为右对齐),m为对齐的宽度。
- n:小数点后保留位数。
----------------------------------------------
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;
}
1,2,3,4,5,6,7
1,3,5,6
6,7
3,5
正确答案:
解析:
- 常量指针:指针所指空间的值是不能发生改变的,不能通过指针解引用修改指针所指向的空间的值,但是指针的指向是可以发生改变的。
- 指针常量:指针本身是一个常量,指针的指向不能发生改变,但是指针所指空间的值是可以发生的,可以通过指针解引用改变指针所指空间的值。
- 区分:const与*的相对位置
- const在*的左边 -- 常量指针
- const在*的右边 -- 指针常量
(1) (2) 常量指针
(3) 常量指针的指向可以发生改变
(4) 指针常量
(5) 指针常量可以通过解引用改变所指空间的值
(6) 常量指针不可以通过解引用改变所指空间的值
(7) 指针常量的指向不可以发生改变
----------------------------------------------
3、下面叙述错误的是()
char acX[]="abc";
char acY[]={'a','b','c'};
char *szX="abc";
char *szY="abc";
acX与acY的内容可以修改
szX与szY指向同一个地址
acX占用的内存空间比acY占用的大
szX的内容修改后,szY的内容也会被更改
正确答案:
解析:
- A、正确:acX与acY都是字符数组,定义的时候是在栈上开辟的,内容是可以被修改的。
- B、正确:szX与szY都是指针,指向的是同一个常量字符串,所以指向的是同一个地址。
- C、正确:"abc"与{'a', 'b', 'c'},第一个是字符串,第二个是字符数组,字符串是最后默认有一个 '\0' ,而这个 '\0' 最后也是会占一个空间的。
- D、错误: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));
1,3
1,2
2,4
3,2
正确答案:
解析:
int a[] = {1, 2, 3, 4}; int *b = a;
*b += 2;
* 优先级高于 += ,所以是首先对 b 解引用,获取到数组首元素,然后进行 += 2。
*(b + 2) = 2;
先将指针 b 向后临时偏移 2 个指针类型大小 (int),然后解引用获取到数组第三个元素,并改为2。
将b指向的内容更改为原指向的后 1 个指针类型大小 (int) 的位置。
b++;
printf("%d,%d\n", *b, *(b + 2));
----------------------------------------------
5、下列关于C/C++的宏定义,不正确的是()
宏定义不检查参数正确性,会有安全隐患
宏定义的常量更容易理解,如果可以使用宏定义常量的话,要避免使用const常量
宏的嵌套定义过多会影响程序的可读性,而且很容易出错
相对于函数调用,宏定义可以提高程序的运行效率
正确答案:
解析:
- A、正确:宏定义是没有类型安全检测的。
- B、错误:是恰恰的说反了,因为宏定义是没有类型安全检测的,并且是在预处理阶段进行的宏替换,所以是无法进行调试的,所以说我们要尽量使用const常量,而不是说避免使用const常量。
- C、正确:因为宏的定义可能会导致运算符优先级的问题,会很容易导致出错。
- D、正确:宏定义相对于函数调用,是没有创建函数栈帧和进行函数压栈的开销,所以是可以提高程序的运行效率的。
----------------------------------------------
6、有以下定义:
int a[10];
char b[80];
函数声明为:
void sss(char[],int[]);
则正确的函数调用形式是()
sss(a,b);
sss(char b[],int a[]);
sss(b[],a[]);
sss(b,a);
正确答案:
解析:
函数在调用的时候,如果函数的参数是数组类型的话,在调用的时候传入数组名(数组的地址)就可以了。
- A、错误:写反了。
- B、错误:写了数据类型。
- C、错误:不可以加[]。
----------------------------------------------
7、用变量a给出下面的定义:一个有10个指针的数组,该指针指向一个函数,该函数有一个整形参数并返回一个整型数()
int *a[10];
int (*a)[10];
int (*a)(int);
int (*a[10])(int);
正确答案:
解析:
- A、错误:[]的优先级是高于*的,所以是一个存放int*类型的10个元素的指针数组。
- B、错误:由于加了(),所以a先和*进行结合也就是一个指针,然后指针指向的是一个带[]的int类型,所以指向的是数组,然后数组的大小为10,就是一个数组指针。
- C、错误:由于加了(),所以a先和*进行结合也就是一个指针,然后指针指向的是一个带()的int类型,所以指向的是函数。所以是一个函数指针,指向的是参数为int,返回值为int的一个函数。
- D、正确:其在C的基础上将 (*a) 变为 (*a[10]) 其就会先与[]进行结合,表示一个数组,然后该数组存储的类型为int (*) (int),所以该数组存放的是函数指针,是一个函数指针数组,指向的是10个参数为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", _____, _____);
}
}
++count[a[i]-'Z']
'Z'-i
count['Z'-i]
++count['A'-a[i]]
'A'+i
count[i]
++count[i]
i
count[i]
++count['Z'-a[i]]
'Z'-i
count[i]
正确答案:
解析:
- A、错误:a[i]-'Z' <= 0
- B、错误:'A'-a[i] <= 0
- C、错误:i的值取决于n,而n又是字符数组的大小,不满足题意,而且会越界访问。
- D、正确:'Z'-a[i] -> 'A'~'Z' = 25~0。
----------------------------------------------
9、在32位cpu上选择缺省对齐的情况下,有如下结构体定义:
struct A {
unsigned a : 19;
unsigned b : 11;
unsigned c : 4;
unsigned d : 29;
char index;
};
则sizeof(struct A)的值为()
9
12
16
20
正确答案:
解析:
是以位段的形式进行定义的,':' 后面的数子是表示该变量所占的bit位个数。
由于第一个a是unsigned类型,所以是4字节(32bit),然后其会一一更具后续位断填充,直到空间不够就会开辟下一个变量的类型大小,继续放位断。
但是由于内存对齐,所以最后的大小需要是最大宽度的整数倍,就是是4的整数倍,也就是16
----------------------------------------------
10、下面代码会输出()
int main() {
int a[4] = { 1,2,3,4 };
int* ptr = (int*)(&a + 1);
printf("%d", *(ptr - 1));
}
4
1
2
3
正确答案:
解析:
需要注意数组名取地址是数组指针,数组指针是指向数组首元素的,+1是向后指针类型的大小,也就是int * [4]整个数组的大小。
最后printf打印中,由于ptr是int类型的指针,所以是向前移动一个int类型的距离,所以最后结果是4。
倒置字符串_牛客题霸_牛客网 (nowcoder.com)
将一句话的单词进行倒置,标点不倒置。比如 I like beijing. 经过函数后变为:beijing. like I
本题题意很简单,就是将一段字符串中的前后单词交换,以单词为单位逆置。
多创建一个string变量,再遍历字符串,找出分界线' ',再输入多创建的string变量。这里我们使用了string中的substr。
#include
#include
using namespace std;
int main() {
string str;
// 注意这里要使用getline,cin>>s遇到空格就接收结束了
getline(cin, str);
// 额外开辟一个string变量用于逆置
string ret_str;
int len = 0;
for(int i = str.size() - 1; i>=0; i--)
{
if(str[i] == ' ')
{
// 跳过空格,然后自行添加
ret_str += str.substr(i + 1, len);
ret_str += ' ';
i--;
len = 0;
}
len++;
}
// 最开始的单词
ret_str += str.substr(0 , len);
ret_str += ' ';
cout << ret_str << endl;
}
先将整个字符串逆置过来,再遍历字符串,找出每个单词,对单词逆置。这里我们使用了stl算法中的reverse,所以这里使用迭代器遍历string。
#include
#include
#include
using namespace std;
int main() {
string str;
// 注意这里要使用getline,cin>>s遇到空格就接收结束了
getline(cin, str);
// 翻转整个句子
reverse(str.begin(), str.end());
// 翻转单词
string::iterator start = str.begin();
while (start != str.end()) {
string::iterator 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;
}
直接利用cin>>s接收输入,遇到空格就结束了,自然就分割开了每个单词,其次将每次接收到的单词拼接到之前串的前面就逆置过来了。
#include
#include
using namespace std;
// cin读取string时自动会被空格分隔开,用另一个字符串存储进行逆序输出
int main() {
string str_tmp, str;
cin >> str;
while (cin >> str_tmp)
str = str_tmp + " " + str;
cout << str << endl;
return 0;
}
排序子序列_牛客笔试题_牛客网 (nowcoder.com)
牛牛定义排序子序列为一个数组中一段连续的子序列,并且这段子序列是非递增或者非递减排序的。牛牛有一个长度为n的整数数组A,他现在有一个任务是把数组A分为若干段排序子序列,牛牛想知道他最少可以把这个数组分为几段排序子序列。
本题要求解的是排序子序列,排序子序列为非递增或者非递减,很多同学在这个非递增、非递减问题上很纠结,注意:非递减就是a[i]<=a[i+1],递减就是a[i]>a[i+1],非递增就是a[i]>=a[i+1],递增就是a[i]
#include
#include
using namespace std;
int main() {
int n;
cin >> n;
vector a;
a.resize(n, 0);
//读入数组
int i = 0;
for (i = 0; i < n; ++i)
cin >> a[i];
i = 0;
int count = 0;
while (i < n)
{
if (a[i] < a[i + 1])
{
while (i < n && a[i] <= a[i + 1])
i++;
count++;
if(i < n) i++;
}
else if (a[i] == a[i + 1])
i++;
else
{
// 非递增子序列
while (i < n && a[i] >= a[i + 1])
i++;
count++;
if(i < n) i++;
}
}
cout << count << endl;
return 0;
}
Note:需要注意上述的代码跑的通是由于越界了牛客测不出来。
i < n 的情况会导致 a[i] 与 a[i+1] 的越界,并且我们需要注意到,并不是开辟 n + 1 就够了,而是要开辟 n + 2 !
#:最后一个子序列是非递减序列情况
(i < n && a[i] <= a[i + 1]) 以情况循环至此,于是出现 a[i] > a[i + 1] ,所以会退出循环count++,但是此时 i = 2 < 3,i会继续++,所以是要开辟 n + 2 !
此时就会因为 i = 3 = 3,而退出最外层循环。
#:最后一个子序列是非增减序列情况
(i < n && a[i] >= a[i + 1]) 以情况循环至此,于是出现 a[i] > a[i + 1] ,所以会继续循环,i会继续++,所以是要开辟 n + 2 !
此时虽然照样满足 a[i] >= a[i + 1] ,但是因为 i = 3 < 3,而退出 (i < n && a[i] >= a[i + 1]) 的循环count++,并退出最外层循环。
#:最后一个子序列是单数字情况
(i < n && a[i] <= a[i + 1]) 以情况循环至此,于是出现 a[i] > a[i + 1] ,所以会退出循环count++,但是此时 i = 1 < 3,i会继续++。
接下就又是一个 a[i] > a[i + 1] 。然后会继续循环,所以是要开辟 n + 2 !
此时虽然照样满足 a[i] >= a[i + 1] ,但是因为 i = 3 < 3,而退出 (i < n && a[i] >= a[i + 1]) 的循环count++,并退出最外层循环。
#include
#include
using namespace std;
int main() {
int n;
cin >> n;
vector a;
a.resize(n + 2, 0);
//读入数组
int i = 0;
for (i = 0; i < n; ++i)
cin >> a[i];
i = 0;
int count = 0;
while (i < n)
{
if (a[i] < a[i + 1])
{
while (i < n && a[i] <= a[i + 1])
i++;
count++;
if(i < n) i++;
}
else if (a[i] == a[i + 1])
i++;
else
{
// 非递增子序列
while (i < n && a[i] >= a[i + 1])
i++;
count++;
if(i < n) i++;
}
}
cout << count << endl;
return 0;
}