《C++ Primer》导学系列:第 1 章 - 开始

1.1 编写一个简单的C++程序

概述

本小节介绍了如何编写和运行一个简单的C++程序,帮助初学者了解C++程序的基本结构和编译运行过程。

编写第一个C++程序

我们从一个简单的C++程序开始,它的功能是在控制台输出 "Hello, World!"。这是学习任何编程语言的传统起点。

  • 程序代码
#include <iostream>int main() {std::cout << "Hello, World!" << std::endl;return 0;
}

代码解析
  1. 预处理指令
#include <iostream>
  • #include 是一个预处理指令,用于包含标准库头文件。
  • <iostream> 是输入输出流库,用于处理输入和输出操作。

  1. 主函数
int main() {// ...return 0;
}
  • int main() 是程序的入口点,每个C++程序都必须包含一个main函数。
  • 函数返回类型为int,表示程序执行的状态,0 通常表示成功。

  1. 输出语句
std::cout << "Hello, World!" << std::endl;
  • std::cout 是标准输出流对象,用于输出数据到控制台。
  • << 是插入运算符,将右侧的数据插入到输出流中。
  • "Hello, World!" 是要输出的字符串。
  • std::endl 是一个流操纵符,用于插入一个换行符并刷新输出缓冲区。

编译和运行

编写完第一个C++程序后,我们需要将其编译成可执行文件,然后运行它。

  1. 编译
  • 使用C++编译器将源代码编译成机器代码。
  • 示例(使用g++编译器):
g++ -o hello hello.cpp
  • -o 选项指定生成的可执行文件名称,这里是 hello

  1. 运行
  • 运行生成的可执行文件。
  • 示例:
./hello

  • 运行结果:
Hello, World!

C++程序的基本结构

通过这个简单的程序,我们可以看到一个C++程序的基本结构:

  • 预处理指令
  • 主函数
  • 输出语句

这些是每个C++程序的基础,后续章节将会详细介绍更多复杂的语法和功能。

重点与难点分析

重点

  1. 预处理指令:了解#include的作用,知道如何包含标准库头文件。
  2. 主函数结构:掌握main函数的基本结构和作用。
  3. 输出语句:理解std::cout、插入运算符<<std::endl的使用。

难点

  1. 编译过程:初学者可能对编译和链接过程不熟悉,需要多练习。
  2. 标准库<iostream> 是一个常用的标准库头文件,需要理解其基本功能。

练习题解析
  1. 练习1.1:编写并运行一个简单的C++程序,输出你的名字。
  • 示例代码:
#include <iostream>int main() {std::cout << "Your Name" << std::endl;return 0;
}

  1. 练习1.2:修改第一个C++程序,使其输出两行文字。
  • 示例代码:
#include <iostream>int main() {std::cout << "Hello, World!" << std::endl;std::cout << "Welcome to C++ Programming!" << std::endl;return 0;
}

  1. 练习1.3:尝试将std::cout替换为cout,观察编译错误,并修改代码以正确编译。
  • 示例代码:
#include <iostream>using std::cout;
using std::endl;int main() {cout << "Hello, World!" << endl;return 0;
}

总结与提高

本节总结

  1. 了解了一个简单的C++程序的基本结构,包括预处理指令、主函数和输出语句。
  2. 学会了如何编写、编译和运行一个简单的C++程序。

提高建议

  1. 多编写简单程序:通过不断练习,熟悉C++程序的基本结构和编写流程。
  2. 探索更多标准库:除了<iostream>,C++还有许多有用的标准库,可以逐步学习和使用。
  3. 了解编译器和开发环境:熟悉编译器的使用和常见选项,掌握IDE或命令行的开发环境,提高开发效率。

1.2 初识输入输出

概述

本小节介绍了C++中基本的输入输出操作,通过标准库中的cincout对象实现。这些对象是iostream库的一部分,用于处理控制台的输入输出。

使用cin进行输入

在C++中,cin对象用于从标准输入设备(通常是键盘)读取数据。ciniostream库的一部分。

  • 基本用法
#include <iostream>int main() {int number;std::cout << "Please enter a number: ";std::cin >> number;std::cout << "You entered: " << number << std::endl;return 0;
}
代码解析
  1. 读取输入
std::cin >> number;
  • std::cin 是标准输入流对象。
  • >> 是提取运算符,用于从输入流中提取数据并存储到变量中。

  1. 输入提示
std::cout << "Please enter a number: ";
  • 使用 std::cout 输出提示信息,引导用户输入。

  1. 输出结果
Please enter a number: 100
You entered: 100

处理多个输入

我们可以使用cin一次读取多个输入,并将其存储在不同的变量中。

  • 示例代码
#include <iostream>int main() {int num1, num2;std::cout << "Please enter two numbers: ";std::cin >> num1 >> num2;std::cout << "You entered: " << num1 << " and " << num2 << std::endl;return 0;
}
代码解析
  1. 读取多个输入
std::cin >> num1 >> num2;
  • 使用提取运算符 >> 连续读取两个整数输入,并存储在 num1num2 中。

  1. 输出多个输入
Please enter two numbers: 10 20
You entered: 10 and 20

输入和输出的类型匹配

在使用cincout时,需要注意类型匹配。如果输入的数据类型与变量类型不匹配,会导致意外行为或错误。

  • 示例代码
#include <iostream>int main() {int num;std::cout << "Please enter an integer: ";std::cin >> num;if (std::cin.fail()) {std::cout << "Input error! Please enter a valid integer." << std::endl;} else {std::cout << "You entered: " << num << std::endl;}return 0;
}
代码解析
  1. 检查输入是否失败
if (std::cin.fail()) {std::cout << "Input error! Please enter a valid integer." << std::endl;
}
  • std::cin.fail() 用于检测输入是否失败。如果输入的数据类型与变量类型不匹配,fail() 返回 true

  1. 重置输入流
std::cin.clear();  // 重置输入流状态
std::cin.ignore(1000, '\n');  // 忽略输入缓冲区中的字符
  • std::cin.clear() 清除错误标志。
  • std::cin.ignore() 忽略输入缓冲区中的字符,避免影响后续输入操作。

重点与难点分析

重点

  1. 使用cin进行输入:掌握cin对象和提取运算符>>的基本用法。
  2. 处理多个输入:学习使用cin一次读取多个输入。
  3. 输入输出的类型匹配:理解类型匹配的重要性,学习如何处理输入错误。

难点

  1. 处理输入错误:初学者可能对输入错误处理不熟悉,需要多练习。
  2. 输入输出流状态管理:理解输入输出流的状态管理方法,如清除错误标志和忽略输入缓冲区。

练习题解析
  1. 练习1.4:编写一个程序,读取两个整数并输出它们的和。
  • 示例代码:
#include <iostream>int main() {int num1, num2;std::cout << "Please enter two integers: ";std::cin >> num1 >> num2;int sum = num1 + num2;std::cout << "The sum is: " << sum << std::endl;return 0;
}

  1. 练习1.5:编写一个程序,读取三个浮点数并输出它们的平均值。
  • 示例代码:
#include <iostream>int main() {float num1, num2, num3;std::cout << "Please enter three floating-point numbers: ";std::cin >> num1 >> num2 >> num3;float average = (num1 + num2 + num3) / 3;std::cout << "The average is: " << average << std::endl;return 0;
}

  1. 练习1.6:编写一个程序,读取一个整数并检查输入是否合法。如果输入不是整数,输出错误信息。
  • 示例代码:
#include <iostream>int main() {int num;std::cout << "Please enter an integer: ";std::cin >> num;if (std::cin.fail()) {std::cout << "Input error! Please enter a valid integer." << std::endl;std::cin.clear();  // 重置输入流状态std::cin.ignore(1000, '\n');  // 忽略输入缓冲区中的字符} else {std::cout << "You entered: " << num << std::endl;}return 0;
}

总结与提高

本节总结

  1. 学习了C++中基本的输入输出操作,包括cincout对象的使用。
  2. 掌握了使用cin进行输入,处理多个输入,以及输入输出的类型匹配。
  3. 了解了如何处理输入错误和管理输入输出流的状态。

提高建议

  1. 多练习输入输出操作:通过不断练习,熟悉cincout的基本用法和常见操作。
  2. 探索更多输入输出流功能:C++标准库提供了丰富的输入输出流功能,可以逐步学习和使用。
  3. 了解输入输出流的高级特性:如格式化输出、自定义流操纵符等,提升程序的灵活性和可读性。

1.3 注释简介

概述

注释是程序员在代码中加入的说明性文本,用于解释代码的功能、逻辑或特殊用法。注释不会被编译器执行,它们仅供阅读代码的人使用。合理的注释可以提高代码的可读性和可维护性。

C++支持两种注释方式:单行注释和多行注释。

单行注释

单行注释以 // 开头,直到行尾的所有内容都被视为注释。

  • 示例
#include <iostream>int main() {// 输出 "Hello, World!"std::cout << "Hello, World!" << std::endl; // 单行注释return 0; // 返回 0
}
代码解析
  1. 单行注释的使用
  • // 输出 "Hello, World!" 是一条单行注释,解释了下一行代码的功能。
  • // 返回 0 是一条单行注释,解释了 return 0 语句。
  1. 注释位置
  • 单行注释可以放在代码行的上方,也可以放在代码行的末尾。

多行注释

多行注释以 /* 开头,以 */ 结尾,之间的所有内容都被视为注释。

  • 示例
#include <iostream>int main() {/*这是一段多行注释解释了以下代码的功能:输出 "Hello, World!" 并返回 0*/std::cout << "Hello, World!" << std::endl;return 0;
}
代码解析
  1. 多行注释的使用
  • /**/ 之间的所有内容都是注释,可以跨越多行。
  • 多行注释通常用于解释复杂的代码段或提供详细的说明。
  1. 嵌套注释的注意事项
  • 多行注释不能嵌套,即在一个多行注释内不能再包含另一个多行注释。
  • 嵌套会导致编译错误。

注释的最佳实践

合理的注释可以显著提高代码的可读性和可维护性。以下是一些编写注释的最佳实践:

  1. 解释意图,而非解释语法
  • 注释应解释代码的目的和逻辑,而不是解释语法。例如,不要注释显而易见的语法,而是解释为什么这样写。
  1. 保持简洁明了
  • 注释应简洁明了,避免冗长。清晰的注释有助于快速理解代码。
  1. 及时更新注释
  • 代码修改后,应及时更新相应的注释,以确保注释与代码一致。
  1. 使用TODO注释
  • 对于需要进一步完善或修复的代码,可以使用 TODO 注释标记,提醒以后回顾和处理。
  • 示例:
// TODO: 处理可能的错误情况
  1. 避免过度注释
  • 虽然注释很重要,但过多的注释可能会使代码显得杂乱无章。应在关键部分添加注释,而不是每行都注释。

练习题解析
  1. 练习1.7:编写一个简单的程序,使用单行注释解释每一行代码。
  • 示例代码:
#include <iostream>  // 包含输入输出流库int main() {int num;  // 定义一个整数变量std::cout << "Please enter a number: ";  // 输出提示信息std::cin >> num;  // 从标准输入读取一个整数std::cout << "You entered: " << num << std::endl;  // 输出读取的整数return 0;  // 返回 0
}

  1. 练习1.8:编写一个程序,使用多行注释解释整个程序的功能。
  • 示例代码:
#include <iostream>int main() {/*这是一个简单的C++程序它从用户那里读取一个整数然后输出该整数*/int num;std::cout << "Please enter a number: ";std::cin >> num;std::cout << "You entered: " << num << std::endl;return 0;
}

  1. 练习1.9:编写一个复杂的代码段,使用注释解释每一步操作。
  • 示例代码:
#include <iostream>
#include <vector>int main() {// 定义一个整数向量std::vector<int> numbers;// 向向量中添加数字for (int i = 1; i <= 5; ++i) {numbers.push_back(i);  // 添加数字 i 到向量末尾}// 计算向量中数字的总和int sum = 0;for (int num : numbers) {sum += num;  // 将每个数字累加到 sum}// 输出结果std::cout << "The sum is: " << sum << std::endl;  // 输出总和return 0;
}

总结与提高

本节总结

  1. 学习了C++中的两种注释方式:单行注释和多行注释。
  2. 了解了如何在代码中添加注释,以提高代码的可读性和可维护性。
  3. 通过示例代码,掌握了注释的基本用法和最佳实践。

提高建议

  1. 多练习编写注释:在编写代码时,养成良好的注释习惯,解释代码的功能和逻辑。
  2. 阅读他人的代码:通过阅读他人代码中的注释,学习如何编写清晰有效的注释。
  3. 及时更新注释:在修改代码时,确保相应的注释也得到更新,以保持代码和注释的一致性。

1.4 控制结构

概述

控制结构是编程语言中用于控制代码执行流程的语法元素。C++提供了多种控制结构,包括条件语句、循环语句和跳转语句。本小节将介绍C++中的基本控制结构,帮助初学者理解如何控制程序的执行流程。

条件语句

条件语句用于根据某个条件的真假来决定执行哪个代码块。C++中的条件语句主要包括if语句、if-else语句。

if语句

if语句根据条件表达式的真假来决定是否执行相应的代码块。

  • 语法
if (condition) {// 如果 condition 为真,执行这里的代码
}

  • 示例
#include <iostream>int main() {int value = 42;if (value > 0) {std::cout << "Value is positive" << std::endl;}return 0;
}

if-else语句

if-else语句在条件为真时执行一个代码块,为假时执行另一个代码块。

  • 语法
if (condition) {// 如果 condition 为真,执行这里的代码
} else {// 否则,执行这里的代码
}

  • 示例
#include <iostream>int main() {int value = -10;if (value > 0) {std::cout << "Value is positive" << std::endl;} else {std::cout << "Value is not positive" << std::endl;}return 0;
}

if-else if-else语句

if-else if-else语句用于检查多个条件,依次判断每个条件表达式。

  • 语法
if (condition1) {// 如果 condition1 为真,执行这里的代码
} else if (condition2) {// 如果 condition2 为真,执行这里的代码
} else {// 如果前面的条件都不为真,执行这里的代码
}

  • 示例
#include <iostream>int main() {int value = 0;if (value > 0) {std::cout << "Value is positive" << std::endl;} else if (value < 0) {std::cout << "Value is negative" << std::endl;} else {std::cout << "Value is zero" << std::endl;}return 0;
}

循环语句

循环语句用于重复执行某段代码,直到满足某个条件。C++中的循环语句主要包括while循环、do-while循环和for循环。

while循环

while循环在每次迭代之前检查条件,如果条件为真,则执行循环体。

  • 语法
while (condition) {// 如果 condition 为真,执行这里的代码
}

  • 示例
#include <iostream>int main() {int count = 0;while (count < 5) {std::cout << "Count is: " << count << std::endl;++count;}return 0;
}

do-while循环

do-while循环先执行循环体,然后检查条件,如果条件为真,则继续执行循环体。

  • 语法
do {// 先执行这里的代码
} while (condition);

  • 示例
#include <iostream>int main() {int count = 0;do {std::cout << "Count is: " << count << std::endl;++count;} while (count < 5);return 0;
}

for循环

for循环在循环开始前初始化变量,在每次迭代前检查条件,并在每次迭代后更新变量。

  • 语法
for (initialization; condition; increment) {// 如果 condition 为真,执行这里的代码
}

  • 示例
#include <iostream>int main() {for (int count = 0; count < 5; ++count) {std::cout << "Count is: " << count << std::endl;}return 0;
}

重点与难点分析

重点

  1. 条件语句:掌握ifif-elseif-else if-else语句的使用。
  2. 循环语句:理解whiledo-whilefor循环的用法。

难点

  1. 条件和循环逻辑:初学者可能会对复杂的条件和循环逻辑感到困惑,需要通过实践加深理解。
  2. 避免滥用goto:尽量避免使用goto,并学习更清晰的控制流程方法。

练习题解析
  1. 练习1.10:编写一个程序,使用while循环输出10到1的数字。
  • 示例代码:
#include <iostream>int main() {int count = 10;while (count > 0) {std::cout << "Count is: " << count << std::endl;--count;}return 0
}

  1. 练习1.11:编写一个程序,使用for循环输出1到10的数字。
  • 示例代码:
#include <iostream>int main() {for (int count = 1; count <= 10; ++count) {std::cout << "Count is: " << count << std::endl;}return 0;
}

  1. 练习1.12:编写一个程序,使用if-else语句检查输入的整数是正数、负数还是零。
  • 示例代码:
#include <iostream>int main() {int number;std::cout << "Please enter an integer: ";std::cin >> number;if (number > 0) {std::cout << "The number is positive." << std::endl;} else if (number < 0) {std::cout << "The number is negative." << std::endl;} else {std::cout << "The number is zero." << std::endl;}return 0;
}

总结与提高

本节总结

  1. 学习了C++中的基本控制结构,包括条件语句、循环语句和跳转语句。
  2. 掌握了ifif-else语句的用法。
  3. 了解了whiledo-whilefor循环的不同用法。

提高建议

  1. 多练习控制结构的使用:通过编写各种示例程序,熟悉控制结构的用法和逻辑。
  2. 理解和优化循环逻辑:在实际编程中,理解和优化循环逻辑,编写高效的代码。

1.5 类简介

概述

类是C++中的一种用户定义类型,它将数据和操作数据的方法封装在一起,是面向对象编程(OOP)的基础。类定义了一组对象的共同属性和行为,通过实例化类,可以创建具体的对象。

定义和使用类

一个类由成员变量(数据成员)和成员函数(方法)组成。成员变量用于存储对象的状态,成员函数用于定义对象的行为。

定义类
  • 语法
class ClassName {
public:// 公有成员// 成员变量// 成员函数
private:// 私有成员// 成员变量// 成员函数
};

  • 示例
#include <iostream>
#include <string>class SalesItem {
public:// 成员函数,声明和定义分离std::string isbn() const { return bookNo; }double avg_price() const;// 成员变量std::string bookNo;unsigned units_sold = 0;double revenue = 0.0;
};// 成员函数的定义
double SalesItem::avg_price() const {if (units_sold) {return revenue / units_sold;} else {return 0;}
}int main() {SalesItem item;item.bookNo = "12345";item.units_sold = 100;item.revenue = 1000.0;std::cout << "ISBN: " << item.isbn() << std::endl;std::cout << "Average Price: " << item.avg_price() << std::endl;return 0;
}
  • 注意,编译上面的代码采用如下的命令:
// 假如你将文件存储为test.cpp
// 需要加上参数 -std=c++11 表示使用C++11标准
g++ -std=c++11 test.cpp -o test

代码解析
  1. 类的定义
  • 类通过关键字class定义,后跟类名和类体。类体包含成员变量和成员函数。
  • publicprivate访问说明符用于控制成员的访问权限。
  1. 成员变量
  • 成员变量在类中声明,用于存储对象的状态。例如:std::string bookNo;
  1. 成员函数
  • 成员函数定义了操作成员变量的方法。可以在类内声明,在类外定义。例如:
std::string isbn() const { return bookNo; }
double avg_price() const;
  1. 成员函数的定义
  • 成员函数可以在类外定义,使用ClassName::FunctionName语法。例如:
double SalesItem::avg_price() const {if (units_sold) {return revenue / units_sold;} else {return 0;}
}
  1. 创建对象
  • 通过类名创建对象,访问对象的成员。例如:
SalesItem item;
item.bookNo = "12345";
item.units_sold = 100;
item.revenue = 1000.0;

重点与难点分析

重点

  1. 类的定义和使用:理解类的基本结构,包括成员变量和成员函数的定义和使用。

难点

  1. 成员函数的定义和调用:初学者需要熟悉成员函数在类外定义和调用的语法。

练习题解析
  1. 练习1.13:定义一个类Book,包含成员变量titleauthorprice,以及相应的构造函数和成员函数。
  • 示例代码:
#include <iostream>
#include <string>class Book {
public:// 默认构造函数Book() = default;// 带参数的构造函数Book(const std::string &t, const std::string &a, double p) : title(t), author(a), price(p) {}// 成员函数std::string getTitle() const { return title; }std::string getAuthor() const { return author; }double getPrice() const { return price; }private:// 成员变量std::string title;std::string author;double price = 0.0;
};int main() {Book book1;Book book2("C++ Primer", "Stanley B. Lippman", 59.99);std::cout << "Book1 Title: " << book1.getTitle() << std::endl;std::cout << "Book2 Title: " << book2.getTitle() << std::endl;return 0;
}

  1. 练习1.14:修改SalesItem类,添加一个计算总销售额的成员函数。
  • 示例代码:
#include <iostream>
#include <string>class SalesItem {
public:SalesItem() = default;SalesItem(const std::string &book, unsigned sold, double rev) : bookNo(book), units_sold(sold), revenue(rev) {}std::string isbn() const { return bookNo; }double avg_price() const;double total_revenue() const { return revenue; }private:std::string bookNo;unsigned units_sold = 0;double revenue = 0.0;
};double SalesItem::avg_price() const {if (units_sold) {return revenue / units_sold;} else {return 0;}
}int main() {SalesItem item("12345", 100, 1000.0);std::cout << "ISBN: " << item.isbn() << std::endl;std::cout << "Total Revenue: " << item.total_revenue() << std::endl;return 0;
}

  1. 练习1.15:为Book类添加析构函数,输出书籍对象销毁时的信息。
  • 示例代码:
#include <iostream>
#include <string>class Book {
public:Book() = default;Book(const std::string &t, const std::string &a, double p) : title(t), author(a), price(p) {}std::string getTitle() const { return title; }std::string getAuthor() const { return author; }double getPrice() const { return price; }~Book() {std::cout << "Book object for " << title << " is being destroyed" << std::endl;}private:std::string title;std::string author;double price = 0.0;
};int main() {Book book1("C++ Primer", "Stanley B. Lippman", 59.99);return 0;
}

总结与提高

本节总结

  1. 了解了类的基本概念和定义,包括成员变量和成员函数。
  2. 通过示例代码,掌握了类的基本用法和常见操作。

提高建议

  1. 多练习定义和使用类:通过编写各种类,熟悉类的定义、构造函数和析构函数的使用。
  2. 理解面向对象编程的基本概念:学习封装、继承和多态等面向对象编程的基本概念,编写更复杂的类。

1.6 书店程序

概述

在本小节中,我们将使用之前学到的C++基础知识,编写一个简单的书店程序。这个程序的目标是处理书籍销售记录,通过对销售数据进行统计,计算销售的总额。

需求描述

书店程序需要完成以下功能:

  1. 读取一系列书籍的销售记录。
  2. 统计每种书籍的总销售量和总销售额。
  3. 输出每种书籍的ISBN、销售总量和总销售额。

数据结构

为了处理书籍销售记录,我们需要定义一个类来表示每一本书的销售数据。该类应该包括以下成员:

  • ISBN(书籍编号)
  • 销售量
  • 总销售额

我们可以重用之前定义的SalesItem类或定义一个新的类Sales_data

定义Sales_data
  • 类定义
#include <iostream>
#include <string>class Sales_data {
public:// 成员变量std::string bookNo;unsigned units_sold = 0;double revenue = 0.0;// 成员函数std::string isbn() const { return bookNo; }Sales_data& combine(const Sales_data&);double avg_price() const;
};// 成员函数定义
Sales_data& Sales_data::combine(const Sales_data& rhs) {units_sold += rhs.units_sold;revenue += rhs.revenue;return *this;
}double Sales_data::avg_price() const {if (units_sold) {return revenue / units_sold;} else {return 0;}
}

代码解析
  1. 成员变量
  • std::string bookNo:书籍的ISBN编号。
  • unsigned units_sold:销售量。
  • double revenue:总销售额。
  1. 成员函数
  • std::string isbn() const:返回书籍的ISBN编号。
  • Sales_data& combine(const Sales_data&):将另一条销售记录的数据合并到当前对象。
  • double avg_price() const:计算平均售价。
  1. 成员函数定义
  • combine函数:将传入的Sales_data对象的销售量和总销售额累加到当前对象。
  • avg_price函数:计算平均售价,如果销售量为零,则返回零。

实现书店程序

我们将编写一个主函数,用于读取销售记录、统计每种书籍的总销售量和总销售额,并输出结果。

  • 主函数实现
#include <iostream>
#include <string>
#include "Sales_data.h"  // 包含Sales_data类定义int main() {Sales_data total;  // 保存当前书籍的销售总记录// 读取第一条销售记录if (std::cin >> total.bookNo >> total.units_sold >> total.revenue) {Sales_data trans;  // 保存每次读取的新销售记录// 读取并处理剩余的销售记录while (std::cin >> trans.bookNo >> trans.units_sold >> trans.revenue) {if (total.isbn() == trans.isbn()) {total.combine(trans);  // 更新当前书籍的总销售记录} else {// 输出结果std::cout << total.isbn() << " "<< total.units_sold << " "<< total.revenue << " "<< total.avg_price() << std::endl;total = trans;  // 处理下一本书的销售记录}}// 输出最后一本书的销售记录std::cout << total.isbn() << " "<< total.units_sold << " "<< total.revenue << " "<< total.avg_price() << std::endl;} else {std::cerr << "No data?!" << std::endl;return -1;  // 表示失败}return 0;
}

代码解析
  1. 变量定义
  • Sales_data total:保存当前书籍的销售总记录。
  • Sales_data trans:保存每次读取的新销售记录。
  1. 读取第一条销售记录
  • 使用std::cin读取第一条销售记录,并存储到total对象中。
  1. 处理剩余销售记录
  • 使用while循环读取剩余的销售记录,并存储到trans对象中。
  • 如果当前记录的ISBN与total对象的ISBN相同,则调用combine函数更新总记录。
  • 如果ISBN不同,则输出total对象的累计结果,并更新total对象为当前记录。
  1. 输出最后一本书的销售记录
  • 循环结束后,输出total对象的最终累计结果。
  1. 错误处理
  • 如果没有读取到任何数据,输出错误信息,并返回失败状态。

重点与难点分析

重点

  1. 类的定义和使用:复习和应用之前定义的Sales_data类,包括成员变量和成员函数。
  2. 输入输出操作:熟练使用std::cinstd::cout进行数据读取和输出。
  3. 条件判断和循环控制:使用if语句和while循环控制程序流程。

难点

  1. 数据合并逻辑:正确理解和实现combine函数的逻辑,确保销售记录的准确累计。
  2. 输入数据处理:处理标准输入中的数据,并根据ISBN判断是否需要合并或输出结果。

练习题解析
  1. 练习1.16:编写一个程序,从标准输入读取多条销售记录,并计算每条记录的总和。
  • 示例代码:
#include <iostream>
#include <string>int main() {Sales_data total;while (std::cin >> total.bookNo >> total.units_sold >> total.revenue) {std::cout << "ISBN: " << total.isbn() << ", "<< "Units Sold: " << total.units_sold << ", "<< "Revenue: " << total.revenue << ", "<< "Average Price: " << total.avg_price() << std::endl;}return 0;
}

  1. 练习1.17:修改主程序,增加输入错误处理逻辑,当输入数据格式不正确时,输出错误信息。
  • 示例代码:
#include <iostream>
#include <string>int main() {Sales_data total;while (true) {std::cout << "Enter bookNo, units_sold, and revenue: ";if (!(std::cin >> total.bookNo >> total.units_sold >> total.revenue)) {std::cerr << "Input error! Please enter valid data." << std::endl;std::cin.clear();std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');} else {std::cout << "ISBN: " << total.isbn() << ", "<< "Units Sold: " << total.units_sold << ", "<< "Revenue: " << total.revenue << ", "<< "Average Price: " << total.avg_price() << std::endl;}}return 0;
}

  1. 练习1.18:扩展程序,允许用户输入多组数据,每组数据包含多个销售记录,并计算每组数据的总和。
  • 示例代码:
#include <iostream>
#include <string>int main() {Sales_data total;while (true) {std::cout << "Enter bookNo, units_sold, and revenue (enter 'end' to finish): ";std::string bookNo;if (!(std::cin >> bookNo)) break;if (bookNo == "end") break;total.bookNo = bookNo;if (!(std::cin >> total.units_sold >> total.revenue)) {std::cerr << "Input error! Please enter valid data." << std::endl;std::cin.clear();std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');continue;}Sales_data trans;while (true) {std::cout << "Enter another record for the same book (enter 'done' to finish this book): ";std::string transBookNo;if (!(std::cin >> transBookNo)) break;if (transBookNo == "done") break;trans.bookNo = transBookNo;if (!(std::cin >> trans.units_sold >> trans.revenue)) {std::cerr << "Input error! Please enter valid data." << std::endl;std::cin.clear();std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');continue;}if (total.isbn() == trans.isbn()) {total.combine(trans);} else {std::cerr << "ISBN mismatch! Please enter the correct record." << std::endl;}}std::cout << "Total for book " << total.isbn() << ": "<< "Units Sold: " << total.units_sold << ", "<< "Revenue: " << total.revenue << ", "<< "Average Price: " << total.avg_price() << std::endl;}return 0;
}

总结与提高

本节总结

  1. 通过实现书店程序,综合应用了类、输入输出、条件判断和循环控制等C++基础知识。
  2. 学习了如何定义和使用一个类来处理实际问题中的数据。
  3. 掌握了如何从标准输入读取数据,处理和统计这些数据,并输出结果。

提高建议

  1. 多练习实际应用场景:通过更多实际应用场景的练习,巩固和加深对C++基础知识的理解和应用。
  2. 优化程序逻辑:在编写程序时,注重代码的结构和逻辑,提高代码的可读性和可维护性。
  3. 处理输入错误和异常情况:在实际应用中,输入数据可能会有错误,需要学习如何处理这些错误和异常情况,编写健壮的程序。

本主页会定期更新,为了能够及时获得更新,敬请关注我:点击左下角的关注。也可以关注公众号:请在微信上搜索公众号“iShare爱分享”并关注,或者扫描以下公众号二维码关注,以便在内容更新时直接向您推送。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/349467.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

File及典型案例

File File对象表示一个路径&#xff0c;可以是文件的路径&#xff0c;也可以是文件夹的路径 这个路径可以是存在的&#xff0c;也允许不存在 常见的构造方法 图来自黑马程序员网课 package com.lazyGirl.filedemo;import java.io.File;public class Demo1 {public static vo…

easyexcel的简单使用(execl模板导出)

模板支持功能点 支持列表支持自定义头名称支持自定义fileName支持汇总 模板示例 操作 pom引入 <dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>${easyexcel.version}</version></dep…

github 本地仓库上传及报错处理

一.本地文件上传 这里为上传部分&#xff0c;关于gitbash安装配置&#xff0c;读者可自行搜索&#xff0c;由于已经安装完成&#xff0c;未进行截图保存&#xff0c;这里便不做赘述。 1.登录git账号并创建一个仓库 点击仓库打开后会看到这个仓库的网址链接&#xff08;这个链…

防止暴力破解,教你如何在登录失败后实施10分钟账户锁定策略!

最近&#xff0c;在服务器上发现了异常的登录尝试。尽管您的团队已经采取了强密码策略和其他安全措施来加固服务器&#xff0c;但恶意程序仍然通过暴力破解的方式试图多次尝试猜测正确的凭据以获取访问权限。为了增强系统的安全性&#xff0c;特别是防止此类暴力破解攻击&#…

项目实战--文档搜索引擎

在我们的学习过程中&#xff0c;会阅读很多的文档&#xff0c;例如jdk的API文档&#xff0c;但是在这样的大型文档中&#xff0c;如果没有搜索功能&#xff0c;我们是很难找到我们想查阅的内容的&#xff0c;于是我们可以实现一个搜索引擎来帮助我们阅读文档。 1. 实现思路 1…

ComfyUI-全民舞王-MusePose

musepose-demo 项目介绍 https://github.com/TMElyralab/MusePose发布的模型能够根据给定的姿势序列&#xff0c;生成参考图中人物的舞蹈视频&#xff0c;结果质量超越了同一主题中几乎所有当前开源的模型。发布pose align算法&#xff0c;以便用户可以将任意舞蹈视频与任意参…

第二届人工智能、系统与网络安全国际学术会议 (AISNS 2024)

第二届人工智能、系统与网络安全国际学术会议 (AISNS 2024&#xff09; 2024 2nd International Conference on Artificial Intelligence, Systems and Network Security 一、重要信息 大会官网&#xff1a;www.aisns.org &#xff08;点击参会/投稿/了解会议详情&#xff09…

基于GTX 8B10B编码的自定义PHY上板测试(高速收发器十四)

前文整理了GTX IP&#xff0c;完成了自定义PHY协议的收发模块设计&#xff0c;本文将通过光纤回环&#xff0c;对这些模块上板测试&#xff0c;首先需要编写一个用于生成测试数据的用户模块。 1、测试数据生成模块 本模块用于生成自定义PHY协议的测试数据&#xff0c;通过axi_…

什么是网站页面组件,有什么用处

1.组件是页面的组成部分 网站的每个页面都是由每个小组件拼接而成的&#xff0c;当然了&#xff0c;有一些网站并不是用小组件拼接的&#xff0c;但是像这些网站它是固定住标签&#xff0c;然后用js直接调用数据显示&#xff0c;这个就是定制化的体现。像那些用小组件组…

Elastic 索引结构-倒排索引

前言 Elastic 在数据库分类中一般被分为全文检索的数据库&#xff0c;那为什么这么区分呢&#xff1f;主要是因为其独特的索引结构 即倒排索引。 倒排索引 倒排索引先将文档中包含的关键字全部提取出来&#xff0c;然后再将关键字与文档的对应关系保存起来&#xff0c;最后再…

多模态大模型:识别和处理图片与视频的技术详解

多模态大模型&#xff1a;识别和处理图片与视频的技术详解 多模态大模型&#xff1a;识别和处理图片与视频的技术详解1. 什么是多模态大模型&#xff1f;2. 多模态大模型的基本架构3. 识别和处理图片3.1 图像特征提取3.2 图像分类与识别3.3 图像生成与增强 4. 识别和处理视频4.…

WebSocket 快速入门 与 应用

WebSocket 是一种在 Web 应用程序中实现实时、双向通信的技术。它允许客户端和服务器之间建立持久性的连接&#xff0c;以便可以在两者之间双向传输数据。 以下是 WebSocket 的一些关键特点和工作原理&#xff1a; 0.特点&#xff1a; 双向通信&#xff1a;WebSocket 允许服务…

什么是端口转发?路由器如何正确的设置端口转发和范围转发?(外网访问必备设置)

文章目录 📖 介绍 📖🏡 演示环境 🏡📒 端口转发 📒🚀 端口转发的应用场景💡 路由器如何设置端口转发(示例)💡 端口范围转发(示例)🎯 范围转发的应用场景🛠️ 设置范围转发📝 范围转发实操示例🎈 注意事项 🎈⚓️ 相关链接 ⚓️📖 介绍 📖 …

遗传算法求解车间调度问题(附python代码)

背景介绍 车间调度问题&#xff08;Job Shop Scheduling Problem, JSSP&#xff09;是一类经典的组合优化问题&#xff0c;它在制造业和生产管理中有着广泛的应用。JSSP 的目标是对车间中的一系列作业进行排程&#xff0c;以使得作业在不同机器上的加工顺序是最优的&#xff0…

什么是场外期权?场外期权有几种做法?

今天带你了解什么是场外期权&#xff1f;场外期权有几种做法&#xff1f;期权分为场内期权&#xff0c;场外期权。场内期权我们都知道&#xff0c;是在期货盘里购买的期权&#xff0c;但场外期权呢&#xff1f; 什么是场外期权&#xff1f; 场外期权是一种在交易所之外进行交易…

WinForm之TCP服务端

目录 一 原型 二 源码 一 原型 二 源码 using System.Net; using System.Net.Sockets; using System.Text;namespace TCP网络服务端通讯 {public partial class Form1 : Form{public Form1(){InitializeComponent();}TcpListener listener null;TcpClient handler null;Ne…

【Linux】从零开始配置新的服务器的机器学习环境

终端远程登录 ssh -p [端口号] [服务器用户名][服务器IP]或者 ssh [用户名][主机地址]第二种的前提是在.ssh\config中配置了host 安装文本编辑器vim 主要用于后续的文本编辑&#xff0c;个人比较习惯用vim&#xff0c;根据自己喜好选择 更新apt sudo apt update安装文本编辑…

陪诊小程序开发,陪诊师在线接单

近几年&#xff0c;陪诊师成为了一个新兴行业&#xff0c;在科技时代中&#xff0c;陪诊小程序作为互联网下的产物&#xff0c;为陪诊市场带来了更多的便利。 当下生活压力大&#xff0c;老龄化逐渐严重&#xff0c;年轻人很难做到陪同家属看病。此外&#xff0c;就诊中出现了…

【npm】安装报错(大多是版本冲突)

1.eslint版本太高&#xff0c;Vuex报错 我使用的是vue2.x&#xff0c;npm 安装Vuex3版本&#xff0c;控制台报错说eslint版本太高 解决办法&#xff1a;Vue2项目安装 vuex3 出现版本报错解决方法_安装 vuex3版本 eslint 报错-CSDN博客

在Lua解释器中注册自定义函数库

本文目录 1、引言2、注册原理3、实例4、程序验证 文章对应视频教程&#xff1a; 暂无&#xff0c;可以关注我的B站账号等待更新。 点击图片或链接访问我的B站主页~~~ 1、引言 在现代软件开发中&#xff0c;Lua因其轻量级、高效和可嵌入性而被广泛使用。作为一种灵活的脚本语言…