Алмазный шаблон C ++ Star, записанный в выходной файл, становится беспорядочным - PullRequest
1 голос
/ 04 апреля 2019

Я учусь кодировать на C ++ и выполняю простые упражнения для начинающих.В настоящее время я сталкиваюсь с проблемой, когда вывод моего ромбовидного шаблона корректно выводится на консоль, но такой же вывод в файл становится беспорядочным .

Эта программа создает a * star diamond на основе длины строки и пытается сохранить тот же дизайн в выходной файл с именем 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
}

Консольный вывод

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

Пример вывода текстового файла

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

Ответы [ 2 ]

3 голосов
/ 04 апреля 2019

Практическое решение - взять то, что работает, и обобщить это. Что работает, так это вывод, сгенерированный 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++;
    }
}

Живой пример, показывающий std :: cout и std :: ostringstream

А вот и вывод из файла:

       *
      ***
     *****
    *******
   *********
  ***********
 *************
***************
 *************
  ***********
   *********
    *******
     *****
      ***
       *
2 голосов
/ 04 апреля 2019

Ваши строки cout и fout должны всегда идти парами и всегда должны быть идентичными.

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

Избавьтесь от << endl. Это происходит в двух местах.

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

Добавить fout << endl;. Это также происходит дважды.

...