✨个人主页: 北 海
🎉所属专栏: C/C++相关题解
🎃操作环境: Visual Studio 2019 版本 16.11.17
文章目录
- 选择题
- 1.字符串/C指针
- 2.计算机组成原理
- 编程题
- 1.排序子序列
- 2.倒置字符串
选择题
1.字符串/C指针
题目:下列叙述错误的是()
char acX[]="abc";
char acY[]={'a','b','c'};
const char *szX="abc";
const char *szY="abc";
选项:
A
.acX
与acY
的内容可以修改B
.szX
与szY
指向同一个地址C
.acX
占用的内存空间比acY
占用的大D
.szX
的内容修改后,szY
的内容也会被更改
分析:本题知识点为 字符与字符串+数组名与指针的区别+常量指针的特点,字符串由字符构成,并且会多出一个结束字符 '\0'
;数组中存储的数据位于 栈
区,是可读可写的,而常量指针所指向的数据位于 常量区
,只可被读取;同时因为 常量区
中相同的数据只会存在一份,因此不同的常量指针指向的对象为同一个
因为 数组中存储的数据位于 栈区
,可读可写,所以 A
正确
常量区中的同一个数据只会存在一份,因此两个不同的常量指针指向同一个对象,地址自然相同,B
正确
在字符数相同的情况下,存储字符串所占空间比单纯存储字符大 1
字节,因此 C
正确
常量区中的数据不可被修改,D
错误;假若通过某种特殊手段对其读写权限进行更改后,szX
的内容修改确实会影响 szY
内容,但这里只是普通场景,因此错误
注意: 直接打印常量指针 szX
、szY
时,会打印其所指向的内容,如果想查看指针值(地址)需要指定输出格式或进行转换
结果:
D
2.计算机组成原理
题目:在32位cpu上选择缺省对齐的情况下,有如下结构体定义:
struct A
{
unsigned a : 19;
unsigned b : 11;
unsigned c : 4;
unsigned d : 29;
char index;
};
则 sizeof(struct A)
的值为()
选项:
A
. 9B
. 12C
. 16D
. 20
分析:本题知识点为 位段
,相关知识可以查看这篇文章 《C语言进阶——自定义类型》位段
结构在存储数据时,会根据后面的大小(表示所需要的比特位)填入待开辟的空间中,假设当前空间无法容纳下一个成员,则会重新开辟空间进行存储,所有数据存储后,会进行 内存对齐
注:unsigned
与 unsigned int
等价,都表示无符号整型
首先开辟 4
字节大小的空间(32
比特位),当成员 a
占用 19
比特位空间后,剩余 13
比特位
然后成员 b
紧接着 a
继续占用 11
比特位,此时 剩余 2
比特位
当成员 c
想占用 4
比特位时,发现 剩余的比特位(2
比特位)已经无法满足其需求了,于是编译器会重新开辟一块 4
字节大小的空间,将 c
存进去,此时新空间剩余 28
比特位,累计开辟了 8
字节空间
同理,当 d
想存储时,发现 剩余的比特位(28
比特位)也无法将自己完整的存储进去,于是编译器会再开辟 4
字节空间,将 d
进行存储,此时新空间剩余 3
比特位,累计开辟了 12
字节空间
最后虽然 index
只需 8
比特位(一个 char
占 1
字节),但因 剩余比特位(3
比特位)无法存下,于是会新开辟 1
字节大小的空间,将 index
进行存储,现在已经共计开辟了 13
字节的空间
为了方便后续数据的读取,编译器会进行 内存对齐,将所占用的空间对齐至最大已开辟新空间(int
)的整数倍,现在是占用了 13
字节,不是 int
的整数倍,因此会多开辟至 16
字节,确保 内存对齐
总的来说,struct A
中各成员的内存占用情况如下图所示:
注意: 位段
在存储时本着 共用空间 的原则,将不同需求的成员放在同一块空间中,假若放不下,则会重新开辟新空间进行存储,位段
只有在所有成员都存储后,才会进行内存对齐
结果:
C
编程题
1.排序子序列
题目链接:排序子序列
题目分析:现在有一个正整数数组 A
,牛牛想要将其分割为 非递增
或 非递减
子序列,最少可以分为几个序列;非递增
表示 递减中包含相等的情况
,非递减
则是 递增中包含相等的情况
,题目给出的数组 A
有可能是 非有序
的,因此需要将其进行划分为子序列,本题的解题关键在于 对 非递增
与 非递减
之间的切换的把握
- 首先对整个数组
A
进行遍历 - 假设
A[pos] < A[pos + 1]
说明此时即将进入非递增
区间,可以将其走完(或者走到变成非递减
),此时获得一个非递增
的子序列 - 同理如果
A[pos] > A[pos + 1]
,则一样需要往后走,直到不符合规则,获得一个非递减
的子序列 - 假设是相等的情况,可以不用管,直接正常向后走一步即可
注意: 在向后走的过程中,可能出现越界问题,可以将数组 A
的空间多开辟一块空间,确保不会越界(因为题目明确其中的值为正整数,所以最后一块空间中的 0
值不会影响子序列)
#include <iostream>
#include <vector>
using namespace std;
size_t getSubStrNum(const vector<int>& v, size_t n)
{
int strNum = 0; //子序列数
//遍历 v
size_t pos = 0;
while (pos < n)
{
if (v[pos] < v[pos + 1])
{
//进入非递减区域,开始向后走,直到不符合规则
while (pos < n && v[pos] <= v[pos + 1])
pos++;
strNum++;
pos++;
}
else if (v[pos] == v[pos + 1])
{
//相等时,可以忽略,直接向后走
pos++;
}
else
{
//进入非递增区域,开始向后走,直到不符合规则
while (pos < n && v[pos] >= v[pos + 1])
pos++;
strNum++;
pos++;
}
}
return strNum;
}
int main()
{
int n = 0; //输入的数据数
while (cin >> n)
{
vector<int> A(n + 1);
for (int i = 0; i < n; i++)
cin >> A[i]; //将数据存入 vector 中
size_t subStrNum = getSubStrNum(A, n); //获取可分割的子序列数
cout << subStrNum << endl;
}
return 0;
}
注意:
- 每次在成功获取(走完)一个子序列后,
pos
需要向后移动一位,进入新的子序列判断 - 在进行子序列获取(移动)时,需要注意越界问题,可以在开辟数组时,多开辟一块空间
2.倒置字符串
题目链接:倒置字符串
题目分析:将字符串倒置后,要确保每个单词的及标点符号的合理性,因此需要先将其整体倒置,然后再分别对每一个单词(含标点)进行倒置,这样就能达到题目要求
题目比较简单,先来看看 C++
版本(可以用库函数和容器)
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int main()
{
string str;
while (getline(cin, str))
{
//先将 str 整体倒置
reverse(str.begin(), str.end());
//再将每次单词及标点进行倒置
auto begin = str.begin();
auto end = str.begin();
while (end != str.end())
{
while (end != str.end() && *end != ' ')
end++;
reverse(begin, end);
if (end != str.end())
++end;
begin = end;
}
cout << str << endl;
}
return 0;
}
再来看看 C语言
版本(需要自己写函数)
#include <stdio.h>
#include <string.h>
#include <assert.h>
void myReverse(char* str, int begin, int end)
{
assert(str);
//双指针交换
while(begin < end)
{
char ch = str[begin];
str[begin] = str[end - 1];
str[end - 1] = ch;
begin++;
end--;
}
}
int main()
{
char str[100] = { 0 }; //str 不超过 100
while(gets(str))
{
int len = strlen(str);
//先整体倒置
myReverse(str, 0, len);
//再逐个单词及标点进行倒置
int begin = 0;
int end = 0;
while(end < len)
{
while(end < len && str[end] != ' ')
end++;
myReverse(str, begin, end);
if(end < len)
end++;
begin = end;
}
printf("%s\n", str);
}
return 0;
}
可以看出 C
还是要高效一些
注意: 在进行倒置时,需要注意边界问题,一般范围为 左闭右开
今天的选择题2中,需要重点回顾
位段
相关知识,如内存对齐;关于编程题1,需要想清楚子序列的获取判断逻辑,重点注意边界问题,编程题2也是如此
相关文章推荐
Day1 组队竞赛、删除公共字符
C++题解 | 逆波兰表达式相关
C语言题解 | 去重数组&&合并数组
C语言题解 | 消失的数字&轮转数组