0

I know that there are already several questions answered about this topic but none of them could help me solve my problem. Please, have in mind that I have just started learning C++ Programming.

I am creating a program that reads a text and then displays it in N rows x M columns (entered by the user). So, if the user writes HarryPotter and wants it to be displayed in a 3 x 4 array it should look something like this:

H a r r
y P o t
t e r

I have already manage to do so with this code:

cout << "Number of rows: ";
cin >> nr;
cout << "Number of columns: ";
cin >> nc;
cout << "Type in text: ";
cin >> text;

char letters[100][100];

for (int row = 0; row < nr; row++)
{
    for (int col = 0; col < nc; col++)
    {
        letters[row][col]= text [i];
        i++;
    }   
}

cout << "Print array: " << endl;
for (int row = 0; row < nr; row++)
    {
        for (int col = 0; col < nc; col++)
        {
            cout << letters[row][col];
        }

    cout << "\n";
    }

And it works fine until the user writes more than one word. For example instead of HarryPotter he writes Harry Potter (I think that the blank spaces between the words is what creates the problem). Do you know why this happens and how can I solve it? Thank you very much.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • 1
    How is the variable text defined? And what to do iif the total elements of the two dimensional array is greater than the number of characters in text? – Vlad from Moscow Nov 13 '16 at 21:37
  • you should also add null terminated to to the end of the input text – Raindrop7 Nov 13 '16 at 21:40
  • I suspect [`std::getline`](http://en.cppreference.com/w/cpp/string/basic_string/getline) will soon be in your future. – WhozCraig Nov 13 '16 at 21:41
  • 1
    you should use `cin.getline()` like [here](http://stackoverflow.com/questions/5838711/stdcin-in-input-with-spaces) – saygins Nov 13 '16 at 21:42

3 Answers3

1

The problem is that the operator >> stops entering a string when a white space character is encountered in the stream. You should use standard function std::getline instead.

Take into account that to display a string there is no need to define an array. The task can be done without using an array.

Here is a demonstrative program.

#include <iostream>
#include <string>
#include <limits>
#include <algorithm>

int main() 
{
    while ( true )
    {
        std::cout << "Number of rows (0 - exit): ";

        unsigned int rows;
        if ( not ( std::cin >> rows ) or ( rows == 0 ) ) break;

        std::cout << "Number of columns (0 - exit): ";

        unsigned int cols;
        if ( not ( std::cin >> cols ) or ( cols == 0 ) ) break;

        std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );

        std::cout << "Type in text: (Enter - exit): ";

        std::string text;
        std::getline( std::cin, text );
        if ( text.empty() ) break;

        std::cout << std::endl;

        std::string::size_type n = text.size();

        n = std::min<std::string::size_type>( n, cols * rows );

        for ( std::string:: size_type i = 0; i < n; i++ )
        {
            std::cout << text[i];

            std::cout << ( ( i + 1 ) % cols == 0 ? '\n' : ' ' );
        }

        std::cout << std::endl;
    }

    return 0;
}

Its output might look like

Number of rows (0 - exit): 3
Number of columns (0 - exit): 4
Type in text: (Enter - exit): HarryPotter

H a r r
y P o t
t e r

Number of rows (0 - exit): 2
Number of columns (0 - exit): 6
Type in text: (Enter - exit): HarryPotter

H a r r y P
o t t e r 

Number of rows (0 - exit): 6
Number of columns (0 - exit): 2
Type in text: (Enter - exit): HarryPotter

H a
r r
y P
o t
t e
r 

Number of rows (0 - exit): 4
Number of columns (0 - exit): 4
Type in text: (Enter - exit): Antonella Masini 

A n t o
n e l l
a   M a
s i n i

Number of rows (0 - exit): 0

You may substitute this statement

if ( not ( std::cin >> rows ) or ( rows == 0 ) ) break;

for this statement

if ( !( std::cin >> rows ) || ( rows == 0 ) ) break;

if the compiler does not compile the first statement. If you use MS VC++ then in the properties of the project you should switch off using of the language extensions (C++, language), and the statement will be compiled.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
1

cin will consider the space between Harry and Potter as a delimiter and only save Harry in text.

With cin.getline, the entire line is read until the Enter key is pressed. Therefore, with cin.getline(text, sizeof(text)), Harry Potter will be saved in text.

Vivek
  • 320
  • 1
  • 5
  • Thank you for the answer but do I just need to replace my "cin >> text;" with "cin.getline(text, sizeof(text));" ? Because I tried that and it doesn't let me run the program because it says that "no instance of overloaded function... matches the argument list"... – Antonella Masini Nov 13 '16 at 23:50
  • You can use `getline(cin , string)` as well. – MarcD Nov 14 '16 at 03:44
  • cin.getline(czTmp, row * col) that you have used should be fine. czTmp should ideally be allocated (row*col) bytes. – Vivek Nov 17 '16 at 22:41
0

you can use a dynamic array of characters so it is sized at run-time as the user input of rows and columns:

#include <iostream>
using namespace std;

int main()
{
    int row, col;

    cout << "Row: ";
    cin >> row;
    cout << "Col: ";
    cin >> col;

    char** cText = new char*[row];
    for(int i(0); i < row; i++)
        cText[i] = new char[col];

    cin.sync(); // clearing the input buffer
    cout << "Text: ";

    char czTmp[100];
    cin.getline(czTmp, row * col); // getting user input text which fits to our 2d array of chars

    int k = 0;
    for(int i = 0; i < row; i++)
    {
        for(int j = 0; j < col; j++)
        {
            cText[i][j] = czTmp[k]; // inputting our array
            k++;
        }
    }

    cText[row - 1][col - 1] = '\0'; // adding a null-terminator because it is not added automatically

    // printing our array
    for(int i = 0; i < row; i++)
    {
        for(int j(0); j < col; j++)
            cout << cText[i][j];
        cout << endl;
    }

    // don't forget to free memory created by new

    for(int i(0); i < row; i++)
        delete[] cText[i];
    delete[] cText;
    cout << endl << endl;
    return 0;
} 
Raindrop7
  • 3,889
  • 3
  • 16
  • 27