-
图书登记
C++版本:
// 50本上限是写给C看的。这里我们使用不限量容器vector(下一章学习) // 不会也可以模仿后面C的版本创建普通数组。 #include <iostream> #include <string> #include <vector> #include <limits> using namespace std; struct Book { string name; double price; long long isbn; }; void eatline() { cin.clear(); cin.ignore(numeric_limits<streamsize>::max(), '\n'); } int main() { vector<Book> books; // 50本上限是写给C看的,所以 i < 50 完全可以删掉 for (int i = 0; i < 50; i++) { cout << "-----Book" << (i + 1) << "-----" << endl; // 书名 cout << "Name: "; string name; getline(cin, name); if (name == "%%") { cout << endl; break; } // 价格 double price; cout << "Price: "; while (!(cin >> price)) { cout << "无效的价格,请重新输入: "; eatline(); } // ISBN long long isbn; cout << "ISBN: "; while (!(cin >> isbn)) { cout << "无效的ISBN,请重新输入: "; eatline(); } eatline(); books.push_back({name, price, isbn}); } // 输出结果 for (size_t i = 0; i < books.size(); i++) { cout << "-----Book" << (i + 1) << "-----" << endl; cout << "Name: " << books[i].name << endl; cout << "Price: " << books[i].price << endl; cout << "ISBN: " << books[i].isbn << endl; } cout << "\n" << books.size() << " Book(s) in total." << endl; return 0; }#include <stdio.h> #include <string.h> #include <stdlib.h> #define MAX_BOOKS 50 #define MAX_NAME_LENGTH 100 typedef struct { char name[MAX_NAME_LENGTH]; float price; long long isbn; } Book; // 用于清除缓冲区多余内容 void eatline() { int c; while ((c = getchar()) != '\n' && c != EOF); } int main() { Book books[MAX_BOOKS]; int count = 0; for (int i = 0; i < MAX_BOOKS; i++) { printf("-----Book%d-----\n", i + 1); // 书名 printf("Name: "); // 简单解释下scanf的格式化 // 空格: 会跳过所有空白字符(包括换行符、空格、制表符等), // 避免前一次输入留下的换行符导致本次读取立即结束 // %99: 限制了最多读取99个字符(留一个给\0) // [^\n]:表示读取直到遇到换行符(但不包括换行符) if (scanf(" %99[^\n]", books[i].name) != 1) { break; } // 检查结束条件 if (strcmp(books[i].name, "%%") == 0) { printf("\n"); break; } // 价格(记得错误检查) printf("Price: "); while (scanf("%f", &books[i].price) != 1) { printf("无效的价格,请重新输入: "); eatline(); } // ISBN printf("ISBN: "); while (scanf("%lld", &books[i].isbn) != 1) { printf("无效的ISBN,请重新输入: "); eatline(); } count++; // 清空输入缓冲区,避免多余的东西跑到下一本书 // 比如isbn结尾不小心多输入了字母啥的 eatline(); } for (int i = 0; i < count; i++) { printf("-----Book%d-----\n", i + 1); printf("Name: %s\n", books[i].name); printf("Price: %.2f\n", books[i].price); printf("ISBN: %lld\n", books[i].isbn); } printf("\n%d Book(s) in total.\n", count); return 0; } -
(接下来的习题只提供 C++版本的答案)
#include <iostream> #include <limits> #include <cstring> #include <cstdio> #include <cctype> using namespace std; const double PI = 3.14159265358; enum class ShapeType { RECT, CIRCLE, }; struct Shape { ShapeType type; struct { int x, y; } pos; union { struct { int width, height; } rect; struct { int radius; } circle; }; }; void eatline() { cin.clear(); cin.ignore(numeric_limits<streamsize>::max(), '\n'); } ShapeType getShapeType(); void enter_shapeInfo(ShapeType type, Shape& shape); void calc_shapeInfo(const Shape& shape); int main() { ShapeType type = getShapeType(); Shape shape; enter_shapeInfo(type, shape); calc_shapeInfo(shape); return 0; } ShapeType getShapeType() { char choice; cout << "Shape (R=Rect; C=Circle): "; while (true) { cin >> choice; choice = toupper(choice); if (cin.fail() || (choice != 'R' && choice != 'C')) { cout << "Error: Invalid shape '" << choice << "'!\n"; eatline(); continue; } break; } eatline(); return (choice == 'C') ? ShapeType::CIRCLE : ShapeType::RECT; } void enter_shapeInfo(ShapeType type, Shape& shape) { shape.type = type; cout << "Enter its position: "; while (!(cin >> shape.pos.x >> shape.pos.y)) { eatline(); cout << "Error: Invalid position!\n"; } if (type == ShapeType::RECT) { cout << "Enter its width and height: "; while (!(cin >> shape.rect.width >> shape.rect.height) || shape.rect.width <= 0 || shape.rect.height <= 0) { eatline(); cout << "Error: Invalid width and height! Values must be positive numbers.\n"; } } else { cout << "Enter its radius: "; while (!(cin >> shape.circle.radius) || shape.circle.radius <= 0) { eatline(); cout << "Error: Invalid radius! Value must be a positive number.\n"; } } } void calc_shapeInfo(const Shape& shape) { int posx, posy; string pointPos; double area; if (shape.type == ShapeType::CIRCLE) { posx = shape.pos.x; posy = shape.pos.y + shape.circle.radius; pointPos = "at the bottom"; area = PI * shape.circle.radius * shape.circle.radius; } else { posx = shape.pos.x + shape.rect.width; posy = shape.pos.y + shape.rect.height; pointPos = "in the bottom right corner"; area = shape.rect.height * shape.rect.width; } printf("Then the coordinates of the point %s are (%d, %d)\n", pointPos.c_str(), posx, posy); printf("The area of it is %.2lf\n", area); }碎碎念:版本答案?
阅读了这么多章节,读者肯定注意到了获取正确输入基本都有一个固定的模式,所以我们完全可以封装起来:
template<typename T> T get_validInput(const string& prompt, const string& errorMsg) { T value; cout << prompt; while (!(cin >> value)) { eatline(); cout << errorMsg << endl; } return value; } // 在main中使用 char choice = get_validInput<char>( "Shape (R=Rect; C=Circle): ", "Invalid shape choice!" ); choice = toupper(choice);或者利用 C++11 的元组特性,可以输入多个,顺便引入错误检查:
template<typename... Args> tuple<Args...> get_validInputs(const string& prompt, const string& errorMsg) { tuple<Args...> values; apply([&](auto&... args) { cout << prompt; while (!((cin >> ... >> args))) { eatline(); cout << errorMsg << endl; } }, values); return values; } // 使用示例: // 不过需要额外进行负数检查 auto [shape.pos.x, shape.pos.y] = get_validInputs<int, int>("Enter its width and height: ", "Invalid width and height!\n");这样代码会更简洁些
-
稍微改造下前面的通用输入函数:
#include <iostream> #include <cstdio> #include <ctime> #include <string> #include <limits> using namespace std; // 清除输入缓冲区 void eatline() { cin.clear(); cin.ignore(numeric_limits<streamsize>::max(), '\n'); } // 通用输入验证模板函数 template<typename T> T get_validInput(const string& prompt, const string& errorMsg, bool (*validateFunc)(T) = nullptr) { T value; while (true) { cout << prompt; if (cin >> value) { // 如果有验证函数,检查值是否有效 if (validateFunc && !validateFunc(value)) { cout << errorMsg << endl; eatline(); continue; } eatline(); // 清除缓冲区中的换行符 return value; } else { eatline(); cout << errorMsg << endl; } } } // 验证函数 - 检查数据包类型 bool isValidPacketType(char type) { return type == 'A' || type == 'a' || type == 'B' || type == 'b'; } // 打印时间戳的函数 void print_timestamp(long long timestamp) { time_t raw_time = (time_t)(timestamp / 1000); // 假设是毫秒时间戳 struct tm *time_info = localtime(&raw_time); printf("%04d-%02d-%02d %02d:%02d:%02d", time_info->tm_year + 1900, time_info->tm_mon + 1, time_info->tm_mday, time_info->tm_hour, time_info->tm_min, time_info->tm_sec); } // 定义数据包类型 enum class PacketType { A, B }; // 使用结构体和联合定义数据包 struct Packet { PacketType type; union { struct { int command_code; int data_length; } typeA; struct { int status_code; long long timestamp; } typeB; } data; }; int main() { Packet packet; // 获取数据包类型(带验证) char packetType = get_validInput<char>( "Packet Type (A=Command, B=Status): ", "Error: Invalid packet type! Please enter A or B.", isValidPacketType ); if (packetType == 'A' || packetType == 'a') { packet.type = PacketType::A; // 获取命令码 // 使用scanf的理由是 // 可以一次性处理八、十、十六进制各种格式的输入 // 八进制: 0100 -> 64 // 十进制: 100 -> 100 // 十六进制:0x100 -> 256 cout << "Enter command code: "; while (true) { if (scanf("%i", &packet.data.typeA.command_code) == 1) { eatline(); break; } else { eatline(); // 清除错误输入 cout << "Error: Invalid command code format! Please enter a valid integer: "; } } // 获取数据长度(带验证) // 注意前后类型匹配:<int> 和 [](int v) packet.data.typeA.data_length = get_validInput<int>( "Enter data length: ", "Error: Data length must be a positive integer!", [](int v) { return v > 0; } ); cout << "--- Packet A Info ---" << endl; // 这里hex是std::hex控制符 cout << "Command: 0x" << hex << uppercase << packet.data.typeA.command_code << endl; cout << "Data Length: " << dec << packet.data.typeA.data_length << " bytes" << endl; } else if (packetType == 'B' || packetType == 'b') { packet.type = PacketType::B; // 获取状态码 packet.data.typeB.status_code = get_validInput<int>( "Enter status code: ", "Error: Status code must be a positive integer!", [](int v) { return v > 0; } ); // 获取时间戳 packet.data.typeB.timestamp = get_validInput<long long>( "Enter timestamp: ", "Error: Timestamp must be a non-negative integer!", [](long long int v) { return v >= 0; } ); cout << "--- Packet B Info ---" << endl; cout << "Status: " << packet.data.typeB.status_code << endl; cout << "Timestamp: "; print_timestamp(packet.data.typeB.timestamp); cout << endl; } return 0; } -
修改
calc_shapeInfo即可:void calc_shapeInfo(const Shape& shape) { int posx, posy; string pointPos; double area; // 放大后的变量 int resized_posx, resized_posy; double resized_area; if (shape.type == ShapeType::CIRCLE) { posx = shape.pos.x; posy = shape.pos.y + shape.circle.radius; pointPos = "at the bottom"; area = PI * shape.circle.radius * shape.circle.radius; // 放大2倍后的计算 resized_posx = shape.pos.x; resized_posy = shape.pos.y + shape.circle.radius * 2; resized_area = PI * shape.circle.radius * 2 * shape.circle.radius * 2; } else { posx = shape.pos.x + shape.rect.width; posy = shape.pos.y + shape.rect.height; pointPos = "in the bottom right corner"; area = shape.rect.height * shape.rect.width; // 放大2倍后的计算 resized_posx = shape.pos.x + shape.rect.width * 2; resized_posy = shape.pos.y + shape.rect.height * 2; resized_area = shape.rect.height * 2 * shape.rect.width * 2; } printf("Then the coordinates of the point %s are (%d, %d)\n", pointPos.c_str(), posx, posy); printf("The area of it is %.0lf\n", area); // 添加放大后的输出 printf("If resized to 2x:\n"); printf("Then the coordinates of the point %s are (%d, %d)\n", pointPos.c_str(), resized_posx, resized_posy); printf("The area of it is %.0lf\n", resized_area); }
丙加·第9章·答案
·1413 字·7 分钟·