【问题标题】:C++ Star diamond pattern written to output file becomes jumbled写入输出文件的 C++ 星形菱形图案变得混乱
【发布时间】:2019-08-25 12:40:38
【问题描述】:

我正在学习用 C++ 编写代码并进行简单的初学者练习。目前,我面临一个问题,即我的星形菱形图案正确输出到控制台,但是到文件的相同输出变得混乱

此程序根据行长度创建*星形菱形,并尝试将相同的设计保存到名为 output_diamond.txt 的输出文件中。

关于如何处理此类问题的任何提示或解决方案?我知道 C++ 部分非常严格,我确保记录我的代码并提供一个可工作的可重新创建的示例。

代码

#include <iostream>
#include <string>
#include <fstream>
#include <cassert>

using namespace std;

void pyramid(int rows);
int main() {
    pyramid(8);
    return 0;
}

/*
 * @param int rows
 *
 * Function to output to console a star pyramid
 * based on an amount of rows for a half going
 * vertical. If top half of rows is 8, than the
 * bottom half will be indetical but reverse with
 * a row count of 8.
 */
void pyramid(int rows) {
    ofstream fout;

    fout.open("output_diamond.txt");
    if (fout.is_open()) {
        /* Top Half */
        // Initialize variable for spaces equal to (rows - 1)
        int space = rows - 1;
        // Begin first for loop for top half of diamond
        for (int i = 1; i <= rows; i++) { // For 1
            // Begin for loop for spaces
            for (int count = 1; count <= space; count++) { // For 2
                // Output to console a single space
                cout << ' ';
                fout << " ";
            } // End For 2
            // Begin for loop for star/diamond char symbol
            for (int count = 1; count <= (2 * i) - 1; count++) { // For 3
                // Output to console a single *
                cout << '*';
                fout << '*' << endl;
            } // End For 3
            // Before for loop ends output end of line
            cout << endl;
            // Decrement -1 to space
            space--;
        } // End For 1

        /*  Bottom Half */
        // Set value for space variable to 1
        space = 1;
        // Begin first for loop for bottom half of diamond
        for (int i = 1; i <= rows - 1; i++) { // For 1
            // Begin loop for spaces
            for (int count = 1; count <= space; count++) { // For 2
                // Output to console a single space
                cout << ' ';
                fout << ' ';
            } // End For 2
            // Begin for loop for star/diamond char symbol
            for (int count = 1; count <= (2 * (rows - i)) - 1; count++) { // For 3
                // Output to console a single *
                cout << '*';
                fout << '*' << endl;
            } // End For 3
            // Before for loop ends output end of line
            cout << endl;
            // Increment space +1
            space++;
        } // End For 1
    } else {
        cout << "Output file did not open!" << endl;
        assert(fout);
    }
    // End
}

控制台输出

       *
      ***
     *****
    *******
   *********
  ***********
 *************
***************
 *************
  ***********
   *********
    *******
     *****
      ***
       *

示例文本文件输出

       *
      *
*
*
     *
*
*
*
*
    *
*
*
*
*
*
*
   *
*
*
*
*
*
*
*

【问题讨论】:

  • 您打印的不是相同的东西,那么您为什么希望它们产生相同的结果呢?你在 fout 中写了很多 endls 而不是 cout。
  • 当相应的控制台输出为cout &lt;&lt; '*';时,您正在使用fout &lt;&lt; '*' &lt;&lt; endl; - 这两个不一样
  • 为什么你同时向标准输出和文件输出不同的东西?你的逻辑很难遵循。为简化起见,为什么不将所有内容都写入std::stringstream,然后您可以将其内容打印到标准输出或文件中,而无需重复自己?
  • 我建议您将您的 "业务逻辑" 提取并合并为一个以 std::ostream&amp; 为参数的函数,并使用 std::coutstd::ofstream&amp; 实例。
  • @πάνταῥεῖ 的评论正是应该如何解决这个问题。创建一个接受std::ostream&amp; 的函数,将代码写入该ostream,然后简单地将流类型作为参数传递。

标签: c++ formatting fstream iostream


【解决方案1】:

实际的解决方案是采用有效的方法并将其推广。起作用的是std::cout 生成的输出,因此所需要做的就是编写一个函数,该函数接受一个流并完全执行std::cout 正在做的事情。

实现这一点的方法是认识到std::ostream 是输出流的基类,因此只需使用多态性并编写一个引用std::ostream 的函数。

这是一个例子:

#include <iostream>
#include <string>
#include <ostream>
#include <fstream>
#include <sstream>
#include <cassert>

using namespace std;

void pyramid(int rows, std::ostream& );

int main() 
{
    // use regular cout
    std::cout << "Using cout \n\n";
    pyramid(8, std::cout);

    // try file printing
    std::ofstream fout;
    fout.open("output_diamond.txt");
    pyramid(8, fout);

    // try printing to a string stream
    std::cout << "\n\nUsing ostringstream \n\n";
    std::ostringstream ostrm;
    pyramid(8, ostrm);
    std::cout << "\n";
    std::cout << ostrm.str();
    return 0;
}

void pyramid(int rows, std::ostream& sout) 
{
    int space = rows - 1;
    for (int i = 1; i <= rows; i++) { 
        for (int count = 1; count <= space; count++) { 
            sout << ' ';
        } 
        for (int count = 1; count <= (2 * i) - 1; count++) { 
            sout << '*';
        } 
        sout << endl;
        space--;
    } 
    space = 1;
    for (int i = 1; i <= rows - 1; i++) { 
        for (int count = 1; count <= space; count++) { 
            sout << ' ';
        } 
        for (int count = 1; count <= (2 * (rows - i)) - 1; count++) { 
            sout << '*';
        } 
        sout << endl;
        space++;
    }
}

Live Example showing std::cout and std::ostringstream

这是文件的输出:

       *
      ***
     *****
    *******
   *********
  ***********
 *************
***************
 *************
  ***********
   *********
    *******
     *****
      ***
       *

【讨论】:

  • 非常感谢您,您能这样做真是太好了。因为从字面上看,我只是在构建您建议的方法并且刚刚开始理解它。很高兴知道我的正是你做的。所以我实际上是在学习。
【解决方案2】:

您的coutfout 行应始终成对出现并且始终相同。

// Output to console a single *
cout << '*';
fout << '*' << endl;

摆脱&lt;&lt; endl。这发生在两个地方。

// Before for loop ends output end of line
cout << endl;

添加fout &lt;&lt; endl;。这也会发生两次。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-09
    • 2021-12-08
    • 1970-01-01
    • 2023-03-22
    • 1970-01-01
    • 2022-11-20
    相关资源
    最近更新 更多