This is a line.
This is another line.04 编程题模板:题干先拆,代码逐行背
这页不是只给答案。每题都先放题干,再告诉你为什么这样写,最后标出题目改了要改哪里。
第3题
输入整数,判断是否合法,然后求平方
从键盘输入一个整数,求它的平方。要求做容错处理,判断输入的是否为数字。
关键词:“输入整数” → 用
int n; 和 cin。关键词:“判断是否为数字” → 用
if (cin >> n) 判断输入是否成功。关键词:“平方” → 输出
n * n。#include <iostream> // 使用 cin 和 cout 必须包含 iostream
using namespace std; // 这样可以直接写 cin、cout,不用 std::cin
int main() {
int n; // n 用来保存用户输入的整数
cout << "请输入一个整数: ";
// cin >> n 如果成功,说明输入能被当成整数
// 比如输入 5 成功;输入 abc 失败
if (cin >> n) {
cout << n * n << endl; // 平方就是 n 乘 n
} else {
cout << "输入错误,不是数字" << endl;
}
return 0; // main 正常结束
}
| 如果题目改了 | 改哪里 |
|---|---|
| 改成求立方 | 把 n * n 改成 n * n * n。 |
| 改成输入小数 | 把 int n 改成 double n。 |
| 改成输出提示语不同 | 只改 cout 里的文字,不动判断逻辑。 |
第38题
数组最大值模板函数
编写求数组最大值的模板函数,使如下程序输出
20 3。int arr1[] = {10, 20, 15, 12};
char arr2[] = {1, 2, 3};
cout << arrMax<int>(arr1, n1) << endl;
cout << arrMax<char>(arr2, n2);
template <typename T>:T 是类型占位符,int、char、double 都能塞进来。T arr[]:数组里装的是 T 类型。T maxVal:最大值也应该是 T 类型,数组是什么类型,最大值就是什么类型。// template 表示这是模板函数
// typename T 表示 T 是一个“类型占位符”
template <typename T>
T arrMax(T arr[], int n) {
T maxVal = arr[0]; // 先假设第 0 个元素最大
// 从第 1 个元素开始比较,因为第 0 个已经拿来当初始最大值了
for (int i = 1; i < n; i++) {
if (arr[i] > maxVal) {
maxVal = arr[i]; // 发现更大的,就更新最大值
}
}
return maxVal; // 把最大值交回给 main
}
| 如果题目改了 | 改哪里 |
|---|---|
| 改成求最小值 | arr[i] > maxVal 改成 arr[i] < minVal,变量名也可以改成 minVal。 |
| 数组元素变成 double | 函数不用改,调用时写 arrMax<double>。 |
| 输出不同行 | 改 main 里的 cout,模板函数不动。 |
第39题
文件写入和读取
运行题目给出的写文件程序后,文件
example.txt 中的内容是什么?再编写程序读取 example.txt 的内容并显示。题目给的写文件程序:它先把内容写进文件
#include <iostream>
#include <fstream> // 文件流:ofstream / ifstream 都在这里
using namespace std;
int main() {
// ofstream = output file stream,专门负责“往文件里写”
ofstream myfile("example.txt");
if (myfile.is_open()) { // 文件成功打开,才可以写
myfile << "This is a line.\n";
myfile << "This is another line.\n";
myfile.close(); // 写完关闭文件
} else {
cout << "Unable to open file";
}
return 0;
}
文件内容
ofstream:out file stream,写文件。ifstream:in file stream,读文件。getline(myfile, line):从文件读一整行到 line。你要补写的读文件程序:再从文件里读出来
#include <iostream> // cout
#include <fstream> // ifstream / ofstream
#include <string> // string 和 getline
using namespace std;
int main() {
ifstream myfile("example.txt"); // 打开 example.txt 准备读取
string line; // line 用来保存每一行文字
if (myfile.is_open()) { // 判断文件是否成功打开
while (getline(myfile, line)) {
cout << line << endl; // 读到一行,就输出一行
}
myfile.close(); // 用完文件要关闭
} else {
cout << "Unable to open file";
}
return 0;
}
| 如果题目改了 | 改哪里 |
|---|---|
| 文件名改了 | 改 "example.txt"。 |
| 要求写文件 | 把 ifstream 换成 ofstream,用 myfile << ... 写入。 |
| 要求逐词读取 | 把 getline(myfile, line) 改成 myfile >> word。 |
第40题
继承 + virtual print
定义
computer 类,包含 name 和 print;定义派生类 Macintosh,包含 color 和 print。测试代码用 computer *p 指向 Macintosh 对象,并希望输出 name 和 color。int main() {
computer *p;
Macintosh imac("Joe's IMAC", "Blue");
p = &imac;
p->print();
return 0;
}
#include <iostream>
#include <string>
using namespace std;
class computer {
protected:
string name; // protected: 子类可以直接用 name
public:
computer(string n) : name(n) {} // 构造函数:把参数 n 存进 name
// 关键:父类指针 p 调用 print 时,想进入子类版本,就必须 virtual
virtual void print() {
cout << "name: " << name << endl;
}
};
class Macintosh : public computer {
private:
string color; // Macintosh 比 computer 多一个 color
public:
// 先调用 computer(n) 初始化父类的 name,再初始化自己的 color
Macintosh(string n, string c) : computer(n), color(c) {}
void print() {
cout << "name: " << name << endl;
cout << "color:" << color << endl;
}
};
最容易丢分忘记在父类
print 前面加 virtual。不加的话,p->print() 只看 p 的声明类型 computer。| 如果题目改了 | 改哪里 |
|---|---|
| 类名改成 Phone/iPhone | 替换类名,继承关系和 virtual 逻辑不变。 |
| 多一个成员 price | 在子类加成员、构造函数参数、print 输出。 |
| 输出格式变了 | 只改 cout 里的文字和空格。 |
第42题
String 类:构造、析构、拷贝、赋值
已知
String 类原型如下,请编写构造函数、析构函数、拷贝构造函数,并重载赋值运算符。class String {
public:
String(const char *str = NULL);
String(const String &other);
~String(void);
String & operator=(const String &other);
private:
char *m_data;
};
先记住只要类里有
char* 这种指针成员,就要小心深拷贝。不能让两个对象共用同一块字符串内存。#include <cstring> // strlen / strcpy
// 普通构造:用 C 字符串创建 String 对象
String::String(const char *str) {
if (str == NULL) { // 如果传进来的是空指针
m_data = new char[1]; // 也要分配 1 个字符空间
m_data[0] = '\0'; // '\0' 表示空字符串结束
} else {
m_data = new char[strlen(str) + 1]; // +1 是给 '\0'
strcpy(m_data, str); // 把 str 内容复制进 m_data
}
}
// 拷贝构造:用另一个 String 创建新 String
String::String(const String &other) {
m_data = new char[strlen(other.m_data) + 1]; // 给新对象开新内存
strcpy(m_data, other.m_data); // 复制内容,不共用地址
}
// 析构:对象销毁时释放自己申请的内存
String::~String(void) {
delete [] m_data; // new char[] 必须配 delete[]
}
// 赋值运算符:已有对象 = 另一个已有对象
String& String::operator=(const String &other) {
if (this == &other) { // 防止自己给自己赋值
return *this;
}
delete [] m_data; // 先释放旧内容
m_data = new char[strlen(other.m_data) + 1]; // 再开新内存
strcpy(m_data, other.m_data); // 复制新内容
return *this; // 返回自己,支持 a = b = c
}
| 句子 | 为什么要写 |
|---|---|
const String &other | 引用传参避免再次拷贝;const 保证不改 other。 |
this == &other | 防自赋值,不然先 delete 自己,再复制自己,会出事。 |
strlen(...) + 1 | C 字符串末尾有 '\0',要多留一个位置。 |
delete [] m_data | 数组 new 出来的内存,要用 delete[]。 |
第43题
Stack 类模板:后进先出
实现一个
Stack 类模板,包含动态数组 data、栈顶 top、容量 capacity,支持 push、pop、peek、getSize、析构和 operator<< 输出。top = -1:表示栈是空的。data[++top] = value:先让 top 上移,再把值放进去。return data[top--]:先返回栈顶,再让 top 下移。#include <iostream>
#include <stdexcept> // underflow_error
using namespace std;
template <typename T>
class Stack {
private:
T* data; // 动态数组,真正存数据的地方
int top; // 栈顶下标;空栈时 top = -1
int capacity; // 当前数组容量
void resize() {
capacity *= 2; // 容量翻倍
T* newData = new T[capacity]; // 开一块更大的新空间
for (int i = 0; i <= top; i++) {
newData[i] = data[i]; // 把旧数据搬过去
}
delete[] data; // 释放旧数组
data = newData; // data 指向新数组
}
public:
Stack(int initialCapacity = 8) {
capacity = initialCapacity;
top = -1; // 一开始没有元素
data = new T[capacity]; // 开初始容量的数组
}
void push(T value) {
if (top + 1 >= capacity) {
resize(); // 满了就扩容
}
data[++top] = value; // 先 top+1,再放入 value
}
T pop() {
if (top < 0) {
throw underflow_error("Stack is empty");
}
return data[top--]; // 返回栈顶,然后 top-1
}
T peek() const {
if (top < 0) {
throw underflow_error("Stack is empty");
}
return data[top]; // 只看栈顶,不弹出
}
int getSize() const {
return top + 1; // top 是下标,所以个数是 top+1
}
~Stack() {
delete[] data; // 析构时释放动态数组
}
friend ostream& operator<<(ostream& os, const Stack<T>& s) {
for (int i = s.top; i >= 0; i--) { // 从栈顶到栈底
os << s.data[i];
if (i > 0) os << " ";
}
return os;
}
};
| 如果题目改了 | 改哪里 |
|---|---|
| 初始容量不是 8 | 改构造函数默认值 initialCapacity = 8。 |
| 扩容不是翻倍 | 改 capacity *= 2。 |
| 输出从栈底到栈顶 | operator<< 里的循环改成从 0 到 top。 |
| 空栈不抛异常,返回默认值 | 改 pop 和 peek 里 throw 的处理。 |