How do I fill 2D Array with the user's input?

Viewed 1020

I am new to Stack overflow and I am wondering if I can get help regarding my C++ code.

I want to fill my 2D array with the users input, for example:

  • Please Enter 16 characters: (abcdabcdabcdabcd)

Outputs a 4x4 grid that is filled with user's input in this case its (abcdabcdabcdabcd).

a b c d
a b c d 
a b c d
a b c d

Here is my progress up till now:

#include <iostream>
#include <stdlib.h>

using namespace std;

//Constants
const int SM_GRID = 3;
const int LG_GRID = 4;
const char FILL_1 = 'X';
const char FILL_2 = 'O';
const int FORWARD = 1;
const int REVERSE = 2;
const int MAXLEN = 128;

//displays an overview of the program
void displayOverview();

//fills a small array with x's and o's
void fillSmallArray(char grid[][SM_GRID]);

//prompts the user for characters, and fills a 4x4 array with them
//either fills it from top to bottom, left to right (if direction is 1)
//or bottom to top, right to left (if direction is 2)
void fillLgArray(char grid[][LG_GRID], int direction);

//outputs the small array
void outputSmallArray(char grid[][SM_GRID]);

//outputs the large array
void outputLgArray(char grid[][LG_GRID]);

//prompts for a command, and calls the appropriate function based on it
//returns true if command was valid
bool doCommand(char grid[][LG_GRID]);


int main(){

  //Overview of the program
  displayOverview();

  //set up arrays
  char myGrid[SM_GRID][SM_GRID];
  fillSmallArray (myGrid);
  outputSmallArray(myGrid);

  //declare a large array
  //declare variable: Play or Not?
  //As long as user wants to play
  //call doCommand
  char myGrid1[LG_GRID][LG_GRID];
  doCommand (myGrid1);

    //fill the small array and output it

    //fill the large array and output it, as many times as the user wants
    //1 for forward, 2 for reverse, any other character ends the game

return 0;
}


//displays an overview of the program
void displayOverview(){
  cout << "Welcome to my grid-o-matic game !! :)\n"
  << "Here is your small grid: \n";

}


//fills a small array with x's and o's
void fillSmallArray(char grid[][SM_GRID]){
  //logic: if both row and col are even, or both odd, put in a X
  //otherwise put in a O
  //loop through the grid put in a X or O as above
  for (int row = 0; row < SM_GRID; row++){
    for(int col = 0; col < SM_GRID; col++){
      if((row %2) == (col%2)){
grid [row][col] = FILL_1;
      }else{
grid [row][col] = FILL_2;
      }//if else
    }//inner for
  }//outer for
}//function



//prompts the user for characters, and fills a 4x4 array with them
//either fills it from top to bottom, left to right (if direction is 1)
//or bottom to top, right to left (if direction is 2)

void fillLgArray(char grid[][LG_GRID], int direction){


    string userInput;

    cout << "Please enter 16 characters!\n";
    cin >> userInput;

    if(userInput.length() > 16){

        userInput = userInput.substr(0, 16);
    }

    cout << "You entered " << userInput << endl;

    for (int row = 0; row < LG_GRID; row++){
        for (int col = 0; col < LG_GRID; row++){
                grid [row][col] = userInput.at(col+row*LG_GRID);
        }
    }
}//Function


//outputs the small array
void outputSmallArray(char grid[][SM_GRID]){

  for (int row=0;row <SM_GRID;row++){
    for(int col=0;col <SM_GRID;col++){
      cout << grid[row][col]<<" ";
    }
    cout << endl;
  }
}


//outputs the large array
void outputLgArray(char grid[][LG_GRID]){

    for (int row=0;row <LG_GRID;row++){
    for(int col=0;col <LG_GRID;col++){
      cout << grid[row][col]<<" ";
    }
    cout << endl;
  }
}


//prompts for a command, and calls the appropriate function based on it
//returns true if command was valid
bool doCommand(char grid[][LG_GRID]){

  bool valid = true;

  char input [MAXLEN];
  int command;

  cout << "Please enter 1 for FORWARDS or 2 for reverse!\n";
  cin.getline(input,MAXLEN);

  command = atoi(input);
  switch (command){
  case FORWARD:
    cout << "Going Forwards !!!\n";
    fillLgArray(grid,command);

    outputLgArray(grid);
    break;

  case REVERSE:
    cout << "Going backwards !!\n";
    fillLgArray(grid, command);

    outputLgArray(grid);
    break;

  default:
    return false;
  }
 return valid;
}
3 Answers

In your fillLgArray function where you stated: You didn't know what to put for indexing into the user input string, there is a formula for indexing a 1D array to treat it as a 2D array. There are two variations for this formula one is for Row - Colum major and the other is for Col - Row major. In your particular situation if the user enters this from the console:

abcdabcdabcdabcd

You can count on the fact that std::string is very much like std::vector only that std::string stores its contents as char_type and has special member functions for working with string manipulation other than that std::string at the core is basically a specialized version of std::vector. Both of these containers from the stl are wrappers around a contiguous block of memory that it allocates into dynamic memory. These containers wrap around a type [size] array and they grow dynamically.

So knowing this we can treat the text from the console "abcdabcdabcdabcd" as an 1D array of characters like this:

 0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15
[a] [b] [c] [d] [a] [b] [c] [d] [a] [b] [c] [d] [a] [b] [c] [d]

So when you are traversing a double for loop to index into a 2D array you have to mentally step through the loop on each iteration.

In C languages such as C & C++ the indexing of a flat 1D array to represent a 2D array is Row-Major so the formula is as follows:

for ( row = 0; row < 4; row++ ) {
    for ( col = 0; col < 4; col ++ ) {
        2darray[row][col] = 1darray[(row * row_size or width) + col];
    }
}

This has already been asked and answered here! Map a 2D array onto a 1D

Here is a working example of your code in a minimal, complete verifiable example:

#include <string>
#include <iostream>
#include <exception>

#define LG_GRID = 4;

void fillArray( char grid[][LG_GRID] ) {
    std::string userInput;
    std::cout << "Please enter 16 characters\n";
    std::cin >> userInput;

    if( userInput.length() < 16 )
        throw std::runtime_error( "Not enough characters" );
    if( userInput.length() > 16 )
        userInput = userInput.substr( 0, 16 );

    std::cout << "You entered " << userInput << '\n';

    for( int row = 0; row < LG_GRID; row++ ) {
        for( int col = 0; col < LG_GRID; col++ ) {
            // grid[row][col] = userInput[row * LG_GRID + col];
            grid[row][col] = userInput.at( row * LG_GRID + col );
            // both lines above will work however `string.at()` will throw an out of range exception.
        }
    }
}

void displayArray( char grid[][LG_GRID] ) {
    for( int row = 0; row < LG_GRID; row++ ) {
        for( int col = 0; col < LG_GRID; col++ ) {
            std::cout << grid[row][col] << " ";
        }
        std::cout << '\n';
    }
}

int main() {
    try {
        char myGrid[LG_GRID][LG_GRID];
        fillArray( myGrid );
        displayArray( myGrid );    

    } catch( const std::runtime_error& e ) {
        std::cerr << e.what() << '\n';
        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}

And using the input you described: "abcdabcdabcdabcd" The output on the console to this program is:

Please enter 16 characters
abcdabcdabcdabcd
You entered abcdabcdabcabcd
a b c d
a b c d
a b c d
a b c d

Looking at your "IDK what to put here" line, you should probably use charAt. Something like:

grid [row][col] = userInput.at(col+row*4);

You want the character at user's input, spot 0, 1, 2, 3, 4, 5...etc

     String inputString = "abcdabcdabcdabcd";
     inputString = inputString.substring(0, 16);
     char[] inputChar = inputString.toCharArray();
     for (int i = 0; i < 4; i++) {
         String printRow = "";
        for (int j = 0; j < 4; j++) {
            printRow = printRow + inputChar[j];
        }
        System.out.println(printRow);
    }
Related