C++ primer plus 练习题:11.9.1 修改程序清单11.5,使之将一系列连续的随机漫步者位置写入到文件中。
1、修改程序清单11.5,使之将一系列连续的随机漫步者位置写入到文件中。对于每个位置,用步号进行标示。另外,让该程序将初始条件(目标距离和步长)以及结果小结写入到该文件中。该文件的内容与下面类似:
custom_input.h
#pragma once #ifndef CUSTOM_INPUT_H_ #define CUSTOM_INPUT_H_ namespace MY_IN { /* * 专用于输入double类型的变量;处理用户输入,确保用户输入的是合法数字;对于数字和字符混合的输入,数字在前的读取数字,后续的字符丢弃;若是字符在前,则要求重新输入 * 返回int值EXIT_SUCCESS * result_int:用于存放用户输入的整型数字,double*指针,对应的存放空间必须在调用之前分配好; * hint_str:const char*指针,用于提示输入的字符串的地址,用于提示用户的输入,字符串建议在结尾处添加换行符; * error_message:在用户输入错误的情况下,提示用户的信息字符串的地址,可以为空,为空则不提示,字符串建议在结尾处添加换行符 */ int in_double(double* result_int, const char* hint_str, const char* error_message = {}); /* * 处理用户输入,只处理char字符数组; * result_str:char*指针,用于存放用户输入的字符,对应的存放空间必须在调用之前分配好; * len:无符号整型,用于指定result_str最多能存储多少个字符(不包括NULL),也就是说,若是result_str能存放10个字符,那么len最多只能传递9;len的最大允许范围为0~(UINT_MAX-1) * hint_str:const char*指针,提示字符串的地址,用于提示用户的输入,字符串建议在结尾处添加换行符; * error_message:const char*指针,在用户输入错误的情况下(长度过长,或者输入为空),提示用户的信息字符串的地址,可以为空,为空则不提示,字符串建议在结尾处添加换行符 * 输入成功会返回EXIT_SUCCESS * 在len的值等于UINT_MAX时会返回EXIT_FAILURE */ int in_charArray(char* result_str, unsigned int len, const char* hint_str, const char* error_message = {}); /* * in_uint:处理用户输入,确保用户输入的是正整数; * result_int:用于存放用户输入的整型数字,unsigned int*指针,对应的存放空间必须在调用之前分配好; * hint_str:const char*指针,提示字符串的地址,用于提示用户的输入,字符串建议在结尾处添加换行符; * error_message:const char*指针,在用户输入错误的情况下,提示用户的信息字符串的地址,可以为空,为空则不提示,字符串建议在结尾处添加换行符 */ int in_uint(unsigned int* result_int, const char* hint_str, const char* error_message = {}); /* * in_int:处理用户输入,确保用户输入的是整数; * result_int:用于存放用户输入的整型数字,int*指针,对应的存放空间必须在调用之前分配好; * hint_str:const char*指针,提示字符串的地址,用于提示用户的输入,字符串建议在结尾处添加换行符; * error_message:const char*指针,在用户输入错误的情况下,提示用户的信息字符串的地址,可以为空,为空则不提示,字符串建议在结尾处添加换行符 */ int in_int(int* result_int, const char* hint_str, const char* error_message = {}); } #endif // !CUSTOM_INPUT_H_
custom_input.cpp
#include "custom_input.h" #include <iostream> #include <string> namespace MY_IN { int in_double(double* result_int, const char* hint_str, const char* error_message) { double a; while (true) { std::cout << hint_str; if (std::cin >> a) { std::cin.get(); //cin不处理回车符 *result_int = a; break; } else { if (nullptr != error_message) { std::cout << error_message; } std::cin.clear(); std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');//清除输入缓冲区的当前行 //numeric_limits:numeric_limits 类模板提供查询各种算术类型属性的标准化方式(例如 int 类型的最大可能值是 std::numeric_limits<int>::max() )。 // 通过 numeric_limits 模板的特化提供此信息。 //streamsize:类型 std::streamsize 是用于表示 I/O 操作中转移字符数或 I/O 缓冲区的大小,是有符号整数类型。 } } return EXIT_SUCCESS; } int in_charArray(char* result_str, unsigned int len, const char* hint_str, const char* error_message) { std::string a; if (UINT_MAX == len) { std::cout << "参数len的值为UINT_MAX!"; return EXIT_FAILURE; } while (true) { std::cout << hint_str; if (std::getline(std::cin, a)) { if (a.size() <= len) { const char* b = a.c_str(); strncpy_s(result_str, len + 1, b, len); /* * errno_t strncpy_s( char *strDest, size_t numberOfElements, const char *strSource, size_t count); * 函数在内部处理的时候,会因为要保留NULL字符,将numberOfElements减去1,就是说,numberOfElements最小值应该为2,否则就会触发参数无效异常 */ *(result_str + len) = NULL; break; } else { if (nullptr == error_message) { std::cout << "你输入的字符串太长了,超过了" << len << "。重新输入。" << std::endl; a = ""; } else { std::cout << error_message; a = ""; } } } else { //对于输入字符类型,这个应该是有点多余的。 std::cin.clear(); //std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');//清除输入缓冲区的当前行 ,但是若是输入缓冲区为空,就会阻塞,等待缓冲区有值才会执行。 //numeric_limits:numeric_limits 类模板提供查询各种算术类型属性的标准化方式(例如 int 类型的最大可能值是 std::numeric_limits<int>::max() )。 // 通过 numeric_limits 模板的特化提供此信息。 //streamsize:类型 std::streamsize 是用于表示 I/O 操作中转移字符数或 I/O 缓冲区的大小,是有符号整数类型。 } } return EXIT_SUCCESS; } int in_uint(unsigned int* result_int, const char* hint_str, const char* error_message) { long long a; while (true) { std::cout << hint_str; if (std::cin >> a) { std::cin.get(); //cin不处理回车符 if (a >= 0 && a <= UINT_MAX) { *result_int = static_cast<unsigned int>(a); break; } } else { std::cin.clear(); std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');//清除输入缓冲区的当前行 //numeric_limits:numeric_limits 类模板提供查询各种算术类型属性的标准化方式(例如 int 类型的最大可能值是 std::numeric_limits<int>::max() )。 // 通过 numeric_limits 模板的特化提供此信息。 //streamsize:类型 std::streamsize 是用于表示 I/O 操作中转移字符数或 I/O 缓冲区的大小,是有符号整数类型。 } if (nullptr == error_message) { std::cout << error_message; } else { std::cout << "请输入正整数!\n"; } } return EXIT_SUCCESS; } int in_int(int* result_int, const char* hint_str, const char* error_message) { int a; while (true) { std::cout << hint_str; if (std::cin >> a) { *result_int = a; std::cin.get(); //cin不处理回车符 break; } else { std::cin.clear(); std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');//清除输入缓冲区的当前行 //numeric_limits:numeric_limits 类模板提供查询各种算术类型属性的标准化方式(例如 int 类型的最大可能值是 std::numeric_limits<int>::max() )。 // 通过 numeric_limits 模板的特化提供此信息。 //streamsize:类型 std::streamsize 是用于表示 I/O 操作中转移字符数或 I/O 缓冲区的大小,是有符号整数类型。 } if (nullptr == error_message) { std::cout << error_message; } } return EXIT_SUCCESS; } }
Vector.h
#pragma once #ifndef VETOR_H_ #define VETOR_H_ #include <iostream> namespace VECTOR { enum class Mode { RECT = 0, POL = 1 }; class Vector { public: Vector(); ~Vector() {}; Vector(double n1, double n2, Mode form = Mode::RECT); void reset(double n1, double n2, Mode form = Mode::RECT); double xcal()const { return this->x; }; double yval()const { return this->y; } double magval()const { return this->mag; } double angval()const { return this->ang; } void polar_mode(); void rect_mode(); Vector operator+(const Vector& b)const; Vector operator-(const Vector& b)const; Vector operator*(double d)const; Vector operator-()const; //负号 friend Vector operator*(double d, const Vector& v); friend std::ostream& operator<<(std::ostream& os, const Vector& v); operator double()const; private: double x{}, y{}, mag{}, ang{}; Mode mode{}; void set_mag(); void set_ang(); void set_x(); void set_y(); }; } #endif // !VETOR_H_
Vector.cpp
#include "Vector.h" #include <cmath> using std::qsort; using std::sin; using std::cos; using std::atan; using std::atan2; using std::cout; namespace VECTOR { const double Rad_to_deg = 45.0 / atan(1.0); void Vector::set_mag() { //卧槽,勾股定理? this->mag = sqrt(this->x * this->x + this->y * this->y); } void Vector::set_ang() { if ((!(this->x < 0) && !(this->x > 0)) && (!(this->y < 0) && !(this->y > 0))) { //就是说x和y都要为0的时候 this->ang = 0.0; } else { this->ang = atan2(this->y, this->x); } } void Vector::set_x() { this->x = this->mag * cos(ang); } void Vector::set_y() { this->y = this->mag * sin(ang); } Vector::Vector() { this->x = this->y = this->ang = this->mag = 0; mode = Mode::RECT; } Vector::Vector(double n1, double n2, Mode form) { this->mode = form; if (form == Mode::RECT) { this->x = n1; this->y = n2; this->set_mag(); this->set_ang(); } else if (form == Mode::POL) { this->mag = n1; this->ang = n2; this->set_x(); this->set_y(); } else { cout << "Vector中没有第三种模式--\n将设置为0"; this->x = this->y = this->ang = this->mag = 0; mode = Mode::RECT; } } void Vector::reset(double n1, double n2, Mode form) { this->mode = form; if (form == Mode::RECT) { this->x = n1; this->y = n2; this->set_mag(); this->set_ang(); } else if (form == Mode::POL) { this->mag = n1; this->ang = n2; this->set_x(); this->set_y(); } else { cout << "Vector中没有第三种模式--\n将设置为0"; this->x = this->y = this->ang = this->mag; mode = Mode::RECT; } } void Vector::polar_mode() { this->mode = Mode::POL; } void Vector::rect_mode() { this->mode = Mode::RECT; } Vector Vector::operator+(const Vector& b)const { return Vector(this->x + b.x, this->y + b.y); /*Vector sum; sum.x = this->x + b.x; sum.y = this->y + b.y; sum.set_ang(); sum.set_mag(); return sum;*/ } Vector Vector::operator-(const Vector& b)const { return Vector(this->x - b.x, this->y - b.y); } Vector Vector::operator-()const { return Vector(-this->x, -this->y); } std::ostream& operator<<(std::ostream& os, const Vector& v) { if (v.mode == VECTOR::Mode::RECT) { os << "(x,y)={" << v.x << "," << v.y << ")"; } else if (v.mode == VECTOR::Mode::POL) { os << "(m,a)=(" << v.mag << "," << v.ang * VECTOR::Rad_to_deg << ")"; } else { os << "vector没有第三种模式!"; } return os; } Vector Vector::operator*(double d)const { return Vector(d * this->x, d * this->y); } Vector operator*(double d, const Vector& v) { return v * d; } Vector::operator double()const { return this->mag; } }
main.cpp
#include <string> #include<iostream> #include "Vector.h" #include "custom_input.h" #include<ctime> #include<cstdlib> #include<fstream> int main(void) { srand(static_cast<unsigned long>(time(0))); //设置随机数种子 double direction{}; VECTOR::Vector result{ 0.0, 0.0 }, step{}; unsigned long steps{}; double target{}, dstep{20}; std::string isQuit; std::ofstream ofd{}; ofd.open(R"(.\随机漫步者结果.txt)",std::ios_base::out); do { MY_IN::in_double(&target, "输入目标的距离:\n"); ofd << "目标距离:" << target << ";每一步的距离:" << dstep << "\n"; while (result.magval() < target) { direction = rand() % 360; step.reset(dstep, direction, VECTOR::Mode::POL); result = result + step; ofd << steps << ":" << result << '\n'; steps++; } ofd << "移动到目标距离共走了" << steps << "步\n"; ofd << result << std::endl << "或者:\n"; result.polar_mode(); ofd << result << "\n平均每步走的距离:" << target / steps << '\n'; result.rect_mode(); steps = {}; result.reset(0.0, 0.0); std::cout << "是否继续,是请输入y,否请输入q:\n"; std::getline(std::cin, isQuit); } while (isQuit[0] != 'q' && isQuit[0] != 'Q'); ofd.close(); return EXIT_SUCCESS; }
结果:
分类:
C++
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?