2D pointer Array does not cointain value in element after initialization
My main.cpp looks like this.
int row = 7, column = 7, size = 7, userChoice;
char typeOfUserTile;
char **boardOfGame;
int* sizeOfBoardGame = NULL;
sizeOfBoardGame = &size;
boardOfGame = new char*[row];
for (int i = 0; i < row; i++)
{
boardOfGame[i] = new char[column];
}
initializeBoardGame(boardOfGame, sizeOfBoardGame);
And my func.cpp looks like this.
#include "dtt0055HW4func.h"
#include <iostream>
#include <fstream>
#include <cstdlib>
using namespace std;
void initializeBoardGame(char **boardOfGame,int* sizeOfBoardGame)
{
char nameOfFile[30],c;
ifstream inFS;
cout << "Please enter the name of the input file: ";
cin >> nameOfFile;
inFS.open(nameOfFile);
if (inFS.fail())
{
while(inFS.fail())
{
cout << "Unable to open the file, please enter the name of the file again. ";
cin >> nameOfFile;
inFS.open(nameOfFile);
}
}
while (!inFS.eof())
{
for (int i = 0; i < *sizeOfBoardGame; i++)
{
for (int j = 0; j < *sizeOfBoardGame; j++)
{
inFS.get(c);
boardOfGame[i][j] = c;
cout << boardOfGame[i][j];
}
}
}
inFS.close();
}
My program will read data from a user's file, then assign each character to be the value of 2D array, then display it on the terminal. However, after display the data to the terminal, my 2D array becomes blank, it does not cointain any value at all. I try to display it using the for loop but it gives me nothing. Can you explain why?
For example, my file is: * * * * *
Then it will display in the terminal as: * * * * *
If I use the for loop to simply display it, it will give me this: ______
*_ indicates blank, nothing at all.
Another question is do you know how to insert an element in 2D pointer array and push existing element to next element. If an element is pushed out of the array boundaries, we will delete that element. For example, I have a 2D array like char **board = (5,6,7,8,9). Now I want to insert a char 'c' into the element, and my array will look like (c,5,6,7,8).
Another question is, is there any way to compare a text color in c++? I try to research this but found nothing. For example, i want to compare a value in my 2D array that is a cross '+' in red color to see if it match.
if (boardOfGame[i][j] == '+' in Red) something like this.
Here is my new code for handling the read stream.
while (row < *sizeOfBoardGame && inFS.get(c))
{
if (!isspace(c))
{
boardOfGame[row][column++] = c;
if (column == *sizeOfBoardGame)
{
column = 0;
row++;
}
}
}
Then I print the array using for loop as normal.
c++
|
show 1 more comment
My main.cpp looks like this.
int row = 7, column = 7, size = 7, userChoice;
char typeOfUserTile;
char **boardOfGame;
int* sizeOfBoardGame = NULL;
sizeOfBoardGame = &size;
boardOfGame = new char*[row];
for (int i = 0; i < row; i++)
{
boardOfGame[i] = new char[column];
}
initializeBoardGame(boardOfGame, sizeOfBoardGame);
And my func.cpp looks like this.
#include "dtt0055HW4func.h"
#include <iostream>
#include <fstream>
#include <cstdlib>
using namespace std;
void initializeBoardGame(char **boardOfGame,int* sizeOfBoardGame)
{
char nameOfFile[30],c;
ifstream inFS;
cout << "Please enter the name of the input file: ";
cin >> nameOfFile;
inFS.open(nameOfFile);
if (inFS.fail())
{
while(inFS.fail())
{
cout << "Unable to open the file, please enter the name of the file again. ";
cin >> nameOfFile;
inFS.open(nameOfFile);
}
}
while (!inFS.eof())
{
for (int i = 0; i < *sizeOfBoardGame; i++)
{
for (int j = 0; j < *sizeOfBoardGame; j++)
{
inFS.get(c);
boardOfGame[i][j] = c;
cout << boardOfGame[i][j];
}
}
}
inFS.close();
}
My program will read data from a user's file, then assign each character to be the value of 2D array, then display it on the terminal. However, after display the data to the terminal, my 2D array becomes blank, it does not cointain any value at all. I try to display it using the for loop but it gives me nothing. Can you explain why?
For example, my file is: * * * * *
Then it will display in the terminal as: * * * * *
If I use the for loop to simply display it, it will give me this: ______
*_ indicates blank, nothing at all.
Another question is do you know how to insert an element in 2D pointer array and push existing element to next element. If an element is pushed out of the array boundaries, we will delete that element. For example, I have a 2D array like char **board = (5,6,7,8,9). Now I want to insert a char 'c' into the element, and my array will look like (c,5,6,7,8).
Another question is, is there any way to compare a text color in c++? I try to research this but found nothing. For example, i want to compare a value in my 2D array that is a cross '+' in red color to see if it match.
if (boardOfGame[i][j] == '+' in Red) something like this.
Here is my new code for handling the read stream.
while (row < *sizeOfBoardGame && inFS.get(c))
{
if (!isspace(c))
{
boardOfGame[row][column++] = c;
if (column == *sizeOfBoardGame)
{
column = 0;
row++;
}
}
}
Then I print the array using for loop as normal.
c++
Why !.eof() inside a loop condition is always wrong. You will want to review Why is iostream::eof inside a loop condition considered wrong?
– David C. Rankin
Nov 21 at 0:42
Thank you sir, I try to fix and now my array has value in its elements. I just still dont understand the part that If i can display my array to the terminal by assigning c to the element, why cant my array keep that value to element?
– Dat To
Nov 21 at 0:55
What happens isEOF
isn't set until you attempt to read after reading the final character in the file. Your read of the final character does Not setEOF
(as it was a good read). However, on your next read, you encounterEOF
-- but in your loop, it's to late, you hitEOF
withinFS.get(c);
, then you attempt to assign an unknown value forc
toboardOfGame[i][j] = c;
invoking Undefined Behavior - so all bets are off at that point.
– David C. Rankin
Nov 21 at 0:59
Instead, control your entire read loop withwhile ((inFS.get(c))) { /* now use c */ }
– David C. Rankin
Nov 21 at 1:02
I have tried three different ways to control the read loop like this: while (inFS >> c); while (inFS.get(c)); while(!(inFS >> c).eof()); These three works properly, which i means it does read a character from my file then assign that character to boardOfGame[i][j]. However, it displays terribly with a weird pattern in the terminal as one character will be displayed 49 times (my 2D array is 7 * 7). I do not know what causes this?
– Dat To
Nov 21 at 1:15
|
show 1 more comment
My main.cpp looks like this.
int row = 7, column = 7, size = 7, userChoice;
char typeOfUserTile;
char **boardOfGame;
int* sizeOfBoardGame = NULL;
sizeOfBoardGame = &size;
boardOfGame = new char*[row];
for (int i = 0; i < row; i++)
{
boardOfGame[i] = new char[column];
}
initializeBoardGame(boardOfGame, sizeOfBoardGame);
And my func.cpp looks like this.
#include "dtt0055HW4func.h"
#include <iostream>
#include <fstream>
#include <cstdlib>
using namespace std;
void initializeBoardGame(char **boardOfGame,int* sizeOfBoardGame)
{
char nameOfFile[30],c;
ifstream inFS;
cout << "Please enter the name of the input file: ";
cin >> nameOfFile;
inFS.open(nameOfFile);
if (inFS.fail())
{
while(inFS.fail())
{
cout << "Unable to open the file, please enter the name of the file again. ";
cin >> nameOfFile;
inFS.open(nameOfFile);
}
}
while (!inFS.eof())
{
for (int i = 0; i < *sizeOfBoardGame; i++)
{
for (int j = 0; j < *sizeOfBoardGame; j++)
{
inFS.get(c);
boardOfGame[i][j] = c;
cout << boardOfGame[i][j];
}
}
}
inFS.close();
}
My program will read data from a user's file, then assign each character to be the value of 2D array, then display it on the terminal. However, after display the data to the terminal, my 2D array becomes blank, it does not cointain any value at all. I try to display it using the for loop but it gives me nothing. Can you explain why?
For example, my file is: * * * * *
Then it will display in the terminal as: * * * * *
If I use the for loop to simply display it, it will give me this: ______
*_ indicates blank, nothing at all.
Another question is do you know how to insert an element in 2D pointer array and push existing element to next element. If an element is pushed out of the array boundaries, we will delete that element. For example, I have a 2D array like char **board = (5,6,7,8,9). Now I want to insert a char 'c' into the element, and my array will look like (c,5,6,7,8).
Another question is, is there any way to compare a text color in c++? I try to research this but found nothing. For example, i want to compare a value in my 2D array that is a cross '+' in red color to see if it match.
if (boardOfGame[i][j] == '+' in Red) something like this.
Here is my new code for handling the read stream.
while (row < *sizeOfBoardGame && inFS.get(c))
{
if (!isspace(c))
{
boardOfGame[row][column++] = c;
if (column == *sizeOfBoardGame)
{
column = 0;
row++;
}
}
}
Then I print the array using for loop as normal.
c++
My main.cpp looks like this.
int row = 7, column = 7, size = 7, userChoice;
char typeOfUserTile;
char **boardOfGame;
int* sizeOfBoardGame = NULL;
sizeOfBoardGame = &size;
boardOfGame = new char*[row];
for (int i = 0; i < row; i++)
{
boardOfGame[i] = new char[column];
}
initializeBoardGame(boardOfGame, sizeOfBoardGame);
And my func.cpp looks like this.
#include "dtt0055HW4func.h"
#include <iostream>
#include <fstream>
#include <cstdlib>
using namespace std;
void initializeBoardGame(char **boardOfGame,int* sizeOfBoardGame)
{
char nameOfFile[30],c;
ifstream inFS;
cout << "Please enter the name of the input file: ";
cin >> nameOfFile;
inFS.open(nameOfFile);
if (inFS.fail())
{
while(inFS.fail())
{
cout << "Unable to open the file, please enter the name of the file again. ";
cin >> nameOfFile;
inFS.open(nameOfFile);
}
}
while (!inFS.eof())
{
for (int i = 0; i < *sizeOfBoardGame; i++)
{
for (int j = 0; j < *sizeOfBoardGame; j++)
{
inFS.get(c);
boardOfGame[i][j] = c;
cout << boardOfGame[i][j];
}
}
}
inFS.close();
}
My program will read data from a user's file, then assign each character to be the value of 2D array, then display it on the terminal. However, after display the data to the terminal, my 2D array becomes blank, it does not cointain any value at all. I try to display it using the for loop but it gives me nothing. Can you explain why?
For example, my file is: * * * * *
Then it will display in the terminal as: * * * * *
If I use the for loop to simply display it, it will give me this: ______
*_ indicates blank, nothing at all.
Another question is do you know how to insert an element in 2D pointer array and push existing element to next element. If an element is pushed out of the array boundaries, we will delete that element. For example, I have a 2D array like char **board = (5,6,7,8,9). Now I want to insert a char 'c' into the element, and my array will look like (c,5,6,7,8).
Another question is, is there any way to compare a text color in c++? I try to research this but found nothing. For example, i want to compare a value in my 2D array that is a cross '+' in red color to see if it match.
if (boardOfGame[i][j] == '+' in Red) something like this.
Here is my new code for handling the read stream.
while (row < *sizeOfBoardGame && inFS.get(c))
{
if (!isspace(c))
{
boardOfGame[row][column++] = c;
if (column == *sizeOfBoardGame)
{
column = 0;
row++;
}
}
}
Then I print the array using for loop as normal.
c++
c++
edited Nov 21 at 4:15
asked Nov 21 at 0:39
Dat To
184
184
Why !.eof() inside a loop condition is always wrong. You will want to review Why is iostream::eof inside a loop condition considered wrong?
– David C. Rankin
Nov 21 at 0:42
Thank you sir, I try to fix and now my array has value in its elements. I just still dont understand the part that If i can display my array to the terminal by assigning c to the element, why cant my array keep that value to element?
– Dat To
Nov 21 at 0:55
What happens isEOF
isn't set until you attempt to read after reading the final character in the file. Your read of the final character does Not setEOF
(as it was a good read). However, on your next read, you encounterEOF
-- but in your loop, it's to late, you hitEOF
withinFS.get(c);
, then you attempt to assign an unknown value forc
toboardOfGame[i][j] = c;
invoking Undefined Behavior - so all bets are off at that point.
– David C. Rankin
Nov 21 at 0:59
Instead, control your entire read loop withwhile ((inFS.get(c))) { /* now use c */ }
– David C. Rankin
Nov 21 at 1:02
I have tried three different ways to control the read loop like this: while (inFS >> c); while (inFS.get(c)); while(!(inFS >> c).eof()); These three works properly, which i means it does read a character from my file then assign that character to boardOfGame[i][j]. However, it displays terribly with a weird pattern in the terminal as one character will be displayed 49 times (my 2D array is 7 * 7). I do not know what causes this?
– Dat To
Nov 21 at 1:15
|
show 1 more comment
Why !.eof() inside a loop condition is always wrong. You will want to review Why is iostream::eof inside a loop condition considered wrong?
– David C. Rankin
Nov 21 at 0:42
Thank you sir, I try to fix and now my array has value in its elements. I just still dont understand the part that If i can display my array to the terminal by assigning c to the element, why cant my array keep that value to element?
– Dat To
Nov 21 at 0:55
What happens isEOF
isn't set until you attempt to read after reading the final character in the file. Your read of the final character does Not setEOF
(as it was a good read). However, on your next read, you encounterEOF
-- but in your loop, it's to late, you hitEOF
withinFS.get(c);
, then you attempt to assign an unknown value forc
toboardOfGame[i][j] = c;
invoking Undefined Behavior - so all bets are off at that point.
– David C. Rankin
Nov 21 at 0:59
Instead, control your entire read loop withwhile ((inFS.get(c))) { /* now use c */ }
– David C. Rankin
Nov 21 at 1:02
I have tried three different ways to control the read loop like this: while (inFS >> c); while (inFS.get(c)); while(!(inFS >> c).eof()); These three works properly, which i means it does read a character from my file then assign that character to boardOfGame[i][j]. However, it displays terribly with a weird pattern in the terminal as one character will be displayed 49 times (my 2D array is 7 * 7). I do not know what causes this?
– Dat To
Nov 21 at 1:15
Why !.eof() inside a loop condition is always wrong. You will want to review Why is iostream::eof inside a loop condition considered wrong?
– David C. Rankin
Nov 21 at 0:42
Why !.eof() inside a loop condition is always wrong. You will want to review Why is iostream::eof inside a loop condition considered wrong?
– David C. Rankin
Nov 21 at 0:42
Thank you sir, I try to fix and now my array has value in its elements. I just still dont understand the part that If i can display my array to the terminal by assigning c to the element, why cant my array keep that value to element?
– Dat To
Nov 21 at 0:55
Thank you sir, I try to fix and now my array has value in its elements. I just still dont understand the part that If i can display my array to the terminal by assigning c to the element, why cant my array keep that value to element?
– Dat To
Nov 21 at 0:55
What happens is
EOF
isn't set until you attempt to read after reading the final character in the file. Your read of the final character does Not set EOF
(as it was a good read). However, on your next read, you encounter EOF
-- but in your loop, it's to late, you hit EOF
with inFS.get(c);
, then you attempt to assign an unknown value for c
to boardOfGame[i][j] = c;
invoking Undefined Behavior - so all bets are off at that point.– David C. Rankin
Nov 21 at 0:59
What happens is
EOF
isn't set until you attempt to read after reading the final character in the file. Your read of the final character does Not set EOF
(as it was a good read). However, on your next read, you encounter EOF
-- but in your loop, it's to late, you hit EOF
with inFS.get(c);
, then you attempt to assign an unknown value for c
to boardOfGame[i][j] = c;
invoking Undefined Behavior - so all bets are off at that point.– David C. Rankin
Nov 21 at 0:59
Instead, control your entire read loop with
while ((inFS.get(c))) { /* now use c */ }
– David C. Rankin
Nov 21 at 1:02
Instead, control your entire read loop with
while ((inFS.get(c))) { /* now use c */ }
– David C. Rankin
Nov 21 at 1:02
I have tried three different ways to control the read loop like this: while (inFS >> c); while (inFS.get(c)); while(!(inFS >> c).eof()); These three works properly, which i means it does read a character from my file then assign that character to boardOfGame[i][j]. However, it displays terribly with a weird pattern in the terminal as one character will be displayed 49 times (my 2D array is 7 * 7). I do not know what causes this?
– Dat To
Nov 21 at 1:15
I have tried three different ways to control the read loop like this: while (inFS >> c); while (inFS.get(c)); while(!(inFS >> c).eof()); These three works properly, which i means it does read a character from my file then assign that character to boardOfGame[i][j]. However, it displays terribly with a weird pattern in the terminal as one character will be displayed 49 times (my 2D array is 7 * 7). I do not know what causes this?
– Dat To
Nov 21 at 1:15
|
show 1 more comment
1 Answer
1
active
oldest
votes
There are a number of ways to control the read loop -- however, the control must be based upon a successful read from the file. You can either use your nested loops and read, e.g.
for (int i = 0; i < *sizeOfBoardGame; i++) {
for (int j = 0; j < *sizeOfBoardGame; j++) {
if (!(inFS.get(c)))
goto readdone;
boardOfGame[i][j] = c;
}
}
readdone:;
(note: using fixed for
loops -- you cannot account for additional characters like spaces or the terminating 'n'
. for
loops will only execute that specific number of times regardless what the character read is. Better to use while
loops and counter-variables to ensure you fill each row and column with a valid character)
Or, preferably, just control the read itself, e.g.
while (row < BRDSZ && inFS.get(c)) {
if (!isspace (c)) {
boardOfGame[row][col++] = c;
if (col == BRDSZ) {
col = 0;
row++;
}
}
}
inFS.close();
Putting it into a short example you could do:
#include <iostream>
#include <fstream>
#include <cctype>
using namespace std;
#define BRDSZ 7 /* if you need constants, #define them */
#define MAXFN 1024
void initializeBoardGame (char (*boardOfGame)[BRDSZ]);
int main (void) {
char boardOfGame[BRDSZ][BRDSZ] = {{0}};
initializeBoardGame (boardOfGame);
for (int i = 0; i < BRDSZ; i++) {
for (int j = 0; j < BRDSZ; j++)
cout << " " << boardOfGame[i][j];
cout << 'n';
}
}
void initializeBoardGame (char (*boardOfGame)[BRDSZ])
{
char nameOfFile[MAXFN],
c;
int row = 0,
col = 0;
ifstream inFS;
cout << "Please enter the name of the input file: ";
if (!(cin >> nameOfFile)) {
cerr << "error: invalid filename entryn";
exit (EXIT_FAILURE);
}
inFS.open (nameOfFile);
if (!(inFS.is_open())) {
cerr << "error: file open failed '" << nameOfFile << "'.n";
exit (EXIT_FAILURE);
}
while (row < BRDSZ && inFS.get(c)) {
if (!isspace (c)) {
boardOfGame[row][col++] = c;
if (col == BRDSZ) {
col = 0;
row++;
}
}
}
inFS.close();
if (row != BRDSZ) {
cerr << "error: insufficient values read from file.n";
exit (EXIT_FAILURE);
}
}
Example Input File
$ cat dat/board_7x7.txt
1 6 7 0 4 2 1
2 1 1 2 4 4 9
5 7 9 4 1 5 1
1 6 8 1 1 4 4
2 7 0 7 0 2 9
6 5 8 3 0 0 1
2 5 6 7 4 1 3
Example Use/Output
$ ./bin/readboard
Please enter the name of the input file: dat/board_7x7.txt
1 6 7 0 4 2 1
2 1 1 2 4 4 9
5 7 9 4 1 5 1
1 6 8 1 1 4 4
2 7 0 7 0 2 9
6 5 8 3 0 0 1
2 5 6 7 4 1 3
Look things over and let me know if you need further help.
Update To Read X,X,X,X
Now that I understand you want to read 4 values and replace the ','
in the input file with an actual ' '
(space
character) in your array, you can tweak the read loop to read each character, if the character is !isspace(c)
then store the character, if c == ','
then store a space, e.g.
while (row < BRDSZ && inFS.get(c)) {
if (c == ',')
boardOfGame[row][col++] = ' ';
else if (!isspace(c))
boardOfGame[row][col++] = c;
if (col == BRDSZ) {
col = 0;
row++;
}
}
Since you are storing a space between each X
(or character value) in your array, when you want to insert a character and move the existing column values to the right, you must move the column values by 2 instead of just shifting by 1
to account for the space
that is stored before the value, e.g. (to insert the letter 'c'
as the new first value in the array at boardOfGame[0][0]
, you could do:
memmove (&boardOfGame[0][2], &boardOfGame[0][0], BRDSZ - 2);
boardOfGame[0][0] = 'c';
boardOfGame[0][1] = ' ';
Putting that altogether in an example (and printing with an additional space between columns), you could do:
#include <iostream>
#include <fstream>
#include <cctype>
#include <cstring>
using namespace std;
#define BRDSZ 7 /* if you need constants, #define them */
#define MAXFN 1024
void initializeBoardGame (char (*boardOfGame)[BRDSZ]);
int main (void) {
char boardOfGame[BRDSZ][BRDSZ] = {{0}};
initializeBoardGame (boardOfGame);
for (int i = 0; i < BRDSZ; i++) { /* output original values */
for (int j = 0; j < BRDSZ; j++)
cout << " " << boardOfGame[i][j];
cout << 'n';
}
cout << 'n';
/* insert 'c' at boardOfGame[0][0] - shif existing right */
memmove (&boardOfGame[0][2], &boardOfGame[0][0], BRDSZ - 2);
boardOfGame[0][0] = 'c';
boardOfGame[0][1] = ' ';
for (int i = 0; i < BRDSZ; i++) { /* output with new value */
for (int j = 0; j < BRDSZ; j++)
cout << " " << boardOfGame[i][j];
cout << 'n';
}
}
void initializeBoardGame (char (*boardOfGame)[BRDSZ])
{
char nameOfFile[MAXFN],
c;
int row = 0,
col = 0;
ifstream inFS;
cout << "Please enter the name of the input file: ";
if (!(cin >> nameOfFile)) {
cerr << "error: invalid filename entryn";
exit (EXIT_FAILURE);
}
inFS.open (nameOfFile);
if (!(inFS.is_open())) {
cerr << "error: file open failed '" << nameOfFile << "'.n";
exit (EXIT_FAILURE);
}
while (row < BRDSZ && inFS.get(c)) {
if (c == ',')
boardOfGame[row][col++] = ' ';
else if (!isspace(c))
boardOfGame[row][col++] = c;
if (col == BRDSZ) {
col = 0;
row++;
}
}
inFS.close();
if (row != BRDSZ) {
cerr << "error: insufficient values read from file.n";
exit (EXIT_FAILURE);
}
}
Example Input File
$ cat dat/board_7x7-2.txt
5,9,3,7
2,6,2,1
1,9,0,9
2,1,7,3
6,1,6,3
1,7,3,8
3,0,6,4
Example Use/Output
$ ./bin/readboard2
Please enter the name of the input file: dat/board_7x7-2.txt
5 9 3 7
2 6 2 1
1 9 0 9
2 1 7 3
6 1 6 3
1 7 3 8
3 0 6 4
c 5 9 3
2 6 2 1
1 9 0 9
2 1 7 3
6 1 6 3
1 7 3 8
3 0 6 4
Reading from File with Unequal Rows
If I understand now and your data file looks similar to:
Example Input File
$ cat dat/board_7x7-3.txt
X, ,X, ,X, ,X
, , , , , , ,
X, ,X, ,X, ,X
, , , , , , ,
X, ,X, ,X, ,X
, , , , , , ,
X, ,X, ,X, ,X
And, your job is to read the X
values storing them in a 2D array with spaces stored between the X
values, then you will need to pass a pointer to either int
or size_t
as a parameter to your function so that it can be updated with the number of rows actually stored (since the rows containing all commas contain no values). The approach to reading is essentially the same, accept this time you will determine when valid data is read and if it is not the 1st column, you will add a space before it in your array, e.g.
while (row < BRDSZ && inFS.get(c)) {
if ((!isspace(c) && c != ',')) { /* read store only values */
if (col) /* if not 1st, store ' ' */
boardOfGame[row][col++] = ' ';
boardOfGame[row][col++] = c;
}
if (col == BRDSZ) {
col = 0;
row++;
}
}
The complete example with the additional pointer parameter added and the number of rows filled updated within the function is:
#include <iostream>
#include <fstream>
#include <cctype>
#include <cstring>
using namespace std;
#define BRDSZ 7 /* if you need constants, #define them */
#define MAXFN 1024
void initializeBoardGame (char (*boardOfGame)[BRDSZ], int *nrows);
int main (void) {
char boardOfGame[BRDSZ][BRDSZ] = {{0}};
int nrows = BRDSZ;
initializeBoardGame (boardOfGame, &nrows);
for (int i = 0; i < nrows; i++) { /* output original values */
for (int j = 0; j < BRDSZ; j++)
cout << boardOfGame[i][j];
cout << 'n';
}
cout << 'n';
/* insert 'c' at boardOfGame[0][0] - shif existing right */
memmove (&boardOfGame[0][2], &boardOfGame[0][0], BRDSZ - 2);
boardOfGame[0][0] = 'c';
boardOfGame[0][1] = ' ';
for (int i = 0; i < nrows; i++) { /* output with new value */
for (int j = 0; j < BRDSZ; j++)
cout << boardOfGame[i][j];
cout << 'n';
}
}
void initializeBoardGame (char (*boardOfGame)[BRDSZ], int *nrows)
{
char nameOfFile[MAXFN],
c;
int row = 0,
col = 0;
ifstream inFS;
cout << "Please enter the name of the input file: ";
if (!(cin >> nameOfFile)) {
cerr << "error: invalid filename entryn";
exit (EXIT_FAILURE);
}
inFS.open (nameOfFile);
if (!(inFS.is_open())) {
cerr << "error: file open failed '" << nameOfFile << "'.n";
exit (EXIT_FAILURE);
}
while (row < BRDSZ && inFS.get(c)) {
if ((!isspace(c) && c != ',')) { /* read store only values */
if (col) /* if not 1st, store ' ' */
boardOfGame[row][col++] = ' ';
boardOfGame[row][col++] = c;
}
if (col == BRDSZ) {
col = 0;
row++;
}
}
inFS.close();
if (row != BRDSZ)
*nrows = row;
}
Example Use/Output
$ ./bin/readboard3
Please enter the name of the input file: dat/board_7x7-3.txt
X X X X
X X X X
X X X X
X X X X
c X X X
X X X X
X X X X
X X X X
If this is not what you intend, the post the exact output you expect so I will know what your intent is regarding input lines that are all commas.
Last But Not Least
What this all boils down to is that your separators change between odd and even rows. This is a fairly ridiculous case, but it has educational value in helping you think through reading data with varying states of input.
When your rows are odd, your file is a comma-separated file. When you rows are even your file is a space-separated file. The simplest and most efficient test of whether an integer value (like row
in the code) is odd or even is simply to test if the 1-bit
is set (e.g. row & 1 == 0
is row is even and row & 1 == 1
row is odd)
So you simply swap which separator you are looking for based on whether your row
is odd or even, e.g.
while (row < BRDSZ && inFS.get(c)) { /* protect row bounds, read c */
if (col < BRDSZ) { /* protect col bounds */
if ((row & 1) == 0) { /* even no. row */
if (c != ',' && c != 'n') /* separator is ',' */
boardOfGame[row][col++] = c; /* assign c */
}
else { /* odd no. row */
if (!isspace(c) && c != 'n') { /* seperator is ' ' */
if (c == ',') /* if c ',' save ' ' */
boardOfGame[row][col++] = ' ';
else /* otherwise, use c */
boardOfGame[row][col++] = c;
}
}
}
if (c == 'n') { /* when newline reached */
col = 0; /* reset values, increment row */
row++;
}
}
inFS.close();
When you substitute this read into the last example, you end up with:
Example Use/Output
$ ./bin/readboard4
Please enter the name of the input file: dat/board_7x7-3.txt
X X X X
X X X X
X X X X
X X X X
c X X X
X X X X
X X X X
X X X X
Now having gone though this multiple ways, you should be picking up on the fact that reading data character by character is a simple matter of:
- testing the character "What do I have?";
- handling the character based on your needs, e.g. "What do I do with it?"; and
never forget to account for your line-ending characters (e.g.
'n'
) also being read as part of your read loop.
If you think of it that way, you should be able to sort it all out.
Thank you so much for your help! I'm be able to control the array right now. However, it will not display the same in the terminal as in the original file. It will print 7 rows, but only 5 columns for each row instead of 7, it not display like your example. Do you perhaps know how to fix it ? What does it mean when you use the if(!isspace(c)) to check whether it is a space or not? In my case, I must include the space. For example my file is: X, ,X, ,X, ,X - It prints: X, ,X, ,X
– Dat To
Nov 21 at 2:09
You don't read the space into your array. You only store characters. You handle the space in the output by including one in the output, e.g. as incout << " " << boardOfGame[i][j];
. I suspect that is where your column problem is partially coming from. Edit your question and add (but do not delete your original code) your new code to your question and I'll take a look.
– David C. Rankin
Nov 21 at 2:20
Dear David, I just add my new code in the original post, can you please take a look again? Thanks.
– Dat To
Nov 21 at 4:43
Your new code looks fine, but using the pointersizeOfBoardGame
is a bit "weird". For inserting'c'
in your array and pushing the other values one to the right in a row, since you are effectively using a 2D array, you will simply want tomemmove
the values to the right. Example to insert'c'
atboardOfGame[0][0]
you wouldmemmove (&boardOfGame[0][1], &boardOfGame[0][0], 6); boardOfGame[0][0] = 'c';
(you can also do the same thing with a simplefor
loop beginning atcol = 1
and settingcurrent column = column - 1
)
– David C. Rankin
Nov 21 at 4:52
Dear David, If i change the condition of if(isspace) to if(c != ',') then it will print only X X X X with proper space. However, it stop at the fourth row first column. For example, I will have a total of 7 row, in each row there will be an X for each column with space between each X for a total of 4 X and 3 spaces. Then if I run the code, it only display until reach boardOfGame[6][0] and stop, missing total 6 elements for the last row.
– Dat To
Nov 21 at 5:28
|
show 10 more comments
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53403718%2f2d-pointer-array-does-not-cointain-value-in-element-after-initialization%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
There are a number of ways to control the read loop -- however, the control must be based upon a successful read from the file. You can either use your nested loops and read, e.g.
for (int i = 0; i < *sizeOfBoardGame; i++) {
for (int j = 0; j < *sizeOfBoardGame; j++) {
if (!(inFS.get(c)))
goto readdone;
boardOfGame[i][j] = c;
}
}
readdone:;
(note: using fixed for
loops -- you cannot account for additional characters like spaces or the terminating 'n'
. for
loops will only execute that specific number of times regardless what the character read is. Better to use while
loops and counter-variables to ensure you fill each row and column with a valid character)
Or, preferably, just control the read itself, e.g.
while (row < BRDSZ && inFS.get(c)) {
if (!isspace (c)) {
boardOfGame[row][col++] = c;
if (col == BRDSZ) {
col = 0;
row++;
}
}
}
inFS.close();
Putting it into a short example you could do:
#include <iostream>
#include <fstream>
#include <cctype>
using namespace std;
#define BRDSZ 7 /* if you need constants, #define them */
#define MAXFN 1024
void initializeBoardGame (char (*boardOfGame)[BRDSZ]);
int main (void) {
char boardOfGame[BRDSZ][BRDSZ] = {{0}};
initializeBoardGame (boardOfGame);
for (int i = 0; i < BRDSZ; i++) {
for (int j = 0; j < BRDSZ; j++)
cout << " " << boardOfGame[i][j];
cout << 'n';
}
}
void initializeBoardGame (char (*boardOfGame)[BRDSZ])
{
char nameOfFile[MAXFN],
c;
int row = 0,
col = 0;
ifstream inFS;
cout << "Please enter the name of the input file: ";
if (!(cin >> nameOfFile)) {
cerr << "error: invalid filename entryn";
exit (EXIT_FAILURE);
}
inFS.open (nameOfFile);
if (!(inFS.is_open())) {
cerr << "error: file open failed '" << nameOfFile << "'.n";
exit (EXIT_FAILURE);
}
while (row < BRDSZ && inFS.get(c)) {
if (!isspace (c)) {
boardOfGame[row][col++] = c;
if (col == BRDSZ) {
col = 0;
row++;
}
}
}
inFS.close();
if (row != BRDSZ) {
cerr << "error: insufficient values read from file.n";
exit (EXIT_FAILURE);
}
}
Example Input File
$ cat dat/board_7x7.txt
1 6 7 0 4 2 1
2 1 1 2 4 4 9
5 7 9 4 1 5 1
1 6 8 1 1 4 4
2 7 0 7 0 2 9
6 5 8 3 0 0 1
2 5 6 7 4 1 3
Example Use/Output
$ ./bin/readboard
Please enter the name of the input file: dat/board_7x7.txt
1 6 7 0 4 2 1
2 1 1 2 4 4 9
5 7 9 4 1 5 1
1 6 8 1 1 4 4
2 7 0 7 0 2 9
6 5 8 3 0 0 1
2 5 6 7 4 1 3
Look things over and let me know if you need further help.
Update To Read X,X,X,X
Now that I understand you want to read 4 values and replace the ','
in the input file with an actual ' '
(space
character) in your array, you can tweak the read loop to read each character, if the character is !isspace(c)
then store the character, if c == ','
then store a space, e.g.
while (row < BRDSZ && inFS.get(c)) {
if (c == ',')
boardOfGame[row][col++] = ' ';
else if (!isspace(c))
boardOfGame[row][col++] = c;
if (col == BRDSZ) {
col = 0;
row++;
}
}
Since you are storing a space between each X
(or character value) in your array, when you want to insert a character and move the existing column values to the right, you must move the column values by 2 instead of just shifting by 1
to account for the space
that is stored before the value, e.g. (to insert the letter 'c'
as the new first value in the array at boardOfGame[0][0]
, you could do:
memmove (&boardOfGame[0][2], &boardOfGame[0][0], BRDSZ - 2);
boardOfGame[0][0] = 'c';
boardOfGame[0][1] = ' ';
Putting that altogether in an example (and printing with an additional space between columns), you could do:
#include <iostream>
#include <fstream>
#include <cctype>
#include <cstring>
using namespace std;
#define BRDSZ 7 /* if you need constants, #define them */
#define MAXFN 1024
void initializeBoardGame (char (*boardOfGame)[BRDSZ]);
int main (void) {
char boardOfGame[BRDSZ][BRDSZ] = {{0}};
initializeBoardGame (boardOfGame);
for (int i = 0; i < BRDSZ; i++) { /* output original values */
for (int j = 0; j < BRDSZ; j++)
cout << " " << boardOfGame[i][j];
cout << 'n';
}
cout << 'n';
/* insert 'c' at boardOfGame[0][0] - shif existing right */
memmove (&boardOfGame[0][2], &boardOfGame[0][0], BRDSZ - 2);
boardOfGame[0][0] = 'c';
boardOfGame[0][1] = ' ';
for (int i = 0; i < BRDSZ; i++) { /* output with new value */
for (int j = 0; j < BRDSZ; j++)
cout << " " << boardOfGame[i][j];
cout << 'n';
}
}
void initializeBoardGame (char (*boardOfGame)[BRDSZ])
{
char nameOfFile[MAXFN],
c;
int row = 0,
col = 0;
ifstream inFS;
cout << "Please enter the name of the input file: ";
if (!(cin >> nameOfFile)) {
cerr << "error: invalid filename entryn";
exit (EXIT_FAILURE);
}
inFS.open (nameOfFile);
if (!(inFS.is_open())) {
cerr << "error: file open failed '" << nameOfFile << "'.n";
exit (EXIT_FAILURE);
}
while (row < BRDSZ && inFS.get(c)) {
if (c == ',')
boardOfGame[row][col++] = ' ';
else if (!isspace(c))
boardOfGame[row][col++] = c;
if (col == BRDSZ) {
col = 0;
row++;
}
}
inFS.close();
if (row != BRDSZ) {
cerr << "error: insufficient values read from file.n";
exit (EXIT_FAILURE);
}
}
Example Input File
$ cat dat/board_7x7-2.txt
5,9,3,7
2,6,2,1
1,9,0,9
2,1,7,3
6,1,6,3
1,7,3,8
3,0,6,4
Example Use/Output
$ ./bin/readboard2
Please enter the name of the input file: dat/board_7x7-2.txt
5 9 3 7
2 6 2 1
1 9 0 9
2 1 7 3
6 1 6 3
1 7 3 8
3 0 6 4
c 5 9 3
2 6 2 1
1 9 0 9
2 1 7 3
6 1 6 3
1 7 3 8
3 0 6 4
Reading from File with Unequal Rows
If I understand now and your data file looks similar to:
Example Input File
$ cat dat/board_7x7-3.txt
X, ,X, ,X, ,X
, , , , , , ,
X, ,X, ,X, ,X
, , , , , , ,
X, ,X, ,X, ,X
, , , , , , ,
X, ,X, ,X, ,X
And, your job is to read the X
values storing them in a 2D array with spaces stored between the X
values, then you will need to pass a pointer to either int
or size_t
as a parameter to your function so that it can be updated with the number of rows actually stored (since the rows containing all commas contain no values). The approach to reading is essentially the same, accept this time you will determine when valid data is read and if it is not the 1st column, you will add a space before it in your array, e.g.
while (row < BRDSZ && inFS.get(c)) {
if ((!isspace(c) && c != ',')) { /* read store only values */
if (col) /* if not 1st, store ' ' */
boardOfGame[row][col++] = ' ';
boardOfGame[row][col++] = c;
}
if (col == BRDSZ) {
col = 0;
row++;
}
}
The complete example with the additional pointer parameter added and the number of rows filled updated within the function is:
#include <iostream>
#include <fstream>
#include <cctype>
#include <cstring>
using namespace std;
#define BRDSZ 7 /* if you need constants, #define them */
#define MAXFN 1024
void initializeBoardGame (char (*boardOfGame)[BRDSZ], int *nrows);
int main (void) {
char boardOfGame[BRDSZ][BRDSZ] = {{0}};
int nrows = BRDSZ;
initializeBoardGame (boardOfGame, &nrows);
for (int i = 0; i < nrows; i++) { /* output original values */
for (int j = 0; j < BRDSZ; j++)
cout << boardOfGame[i][j];
cout << 'n';
}
cout << 'n';
/* insert 'c' at boardOfGame[0][0] - shif existing right */
memmove (&boardOfGame[0][2], &boardOfGame[0][0], BRDSZ - 2);
boardOfGame[0][0] = 'c';
boardOfGame[0][1] = ' ';
for (int i = 0; i < nrows; i++) { /* output with new value */
for (int j = 0; j < BRDSZ; j++)
cout << boardOfGame[i][j];
cout << 'n';
}
}
void initializeBoardGame (char (*boardOfGame)[BRDSZ], int *nrows)
{
char nameOfFile[MAXFN],
c;
int row = 0,
col = 0;
ifstream inFS;
cout << "Please enter the name of the input file: ";
if (!(cin >> nameOfFile)) {
cerr << "error: invalid filename entryn";
exit (EXIT_FAILURE);
}
inFS.open (nameOfFile);
if (!(inFS.is_open())) {
cerr << "error: file open failed '" << nameOfFile << "'.n";
exit (EXIT_FAILURE);
}
while (row < BRDSZ && inFS.get(c)) {
if ((!isspace(c) && c != ',')) { /* read store only values */
if (col) /* if not 1st, store ' ' */
boardOfGame[row][col++] = ' ';
boardOfGame[row][col++] = c;
}
if (col == BRDSZ) {
col = 0;
row++;
}
}
inFS.close();
if (row != BRDSZ)
*nrows = row;
}
Example Use/Output
$ ./bin/readboard3
Please enter the name of the input file: dat/board_7x7-3.txt
X X X X
X X X X
X X X X
X X X X
c X X X
X X X X
X X X X
X X X X
If this is not what you intend, the post the exact output you expect so I will know what your intent is regarding input lines that are all commas.
Last But Not Least
What this all boils down to is that your separators change between odd and even rows. This is a fairly ridiculous case, but it has educational value in helping you think through reading data with varying states of input.
When your rows are odd, your file is a comma-separated file. When you rows are even your file is a space-separated file. The simplest and most efficient test of whether an integer value (like row
in the code) is odd or even is simply to test if the 1-bit
is set (e.g. row & 1 == 0
is row is even and row & 1 == 1
row is odd)
So you simply swap which separator you are looking for based on whether your row
is odd or even, e.g.
while (row < BRDSZ && inFS.get(c)) { /* protect row bounds, read c */
if (col < BRDSZ) { /* protect col bounds */
if ((row & 1) == 0) { /* even no. row */
if (c != ',' && c != 'n') /* separator is ',' */
boardOfGame[row][col++] = c; /* assign c */
}
else { /* odd no. row */
if (!isspace(c) && c != 'n') { /* seperator is ' ' */
if (c == ',') /* if c ',' save ' ' */
boardOfGame[row][col++] = ' ';
else /* otherwise, use c */
boardOfGame[row][col++] = c;
}
}
}
if (c == 'n') { /* when newline reached */
col = 0; /* reset values, increment row */
row++;
}
}
inFS.close();
When you substitute this read into the last example, you end up with:
Example Use/Output
$ ./bin/readboard4
Please enter the name of the input file: dat/board_7x7-3.txt
X X X X
X X X X
X X X X
X X X X
c X X X
X X X X
X X X X
X X X X
Now having gone though this multiple ways, you should be picking up on the fact that reading data character by character is a simple matter of:
- testing the character "What do I have?";
- handling the character based on your needs, e.g. "What do I do with it?"; and
never forget to account for your line-ending characters (e.g.
'n'
) also being read as part of your read loop.
If you think of it that way, you should be able to sort it all out.
Thank you so much for your help! I'm be able to control the array right now. However, it will not display the same in the terminal as in the original file. It will print 7 rows, but only 5 columns for each row instead of 7, it not display like your example. Do you perhaps know how to fix it ? What does it mean when you use the if(!isspace(c)) to check whether it is a space or not? In my case, I must include the space. For example my file is: X, ,X, ,X, ,X - It prints: X, ,X, ,X
– Dat To
Nov 21 at 2:09
You don't read the space into your array. You only store characters. You handle the space in the output by including one in the output, e.g. as incout << " " << boardOfGame[i][j];
. I suspect that is where your column problem is partially coming from. Edit your question and add (but do not delete your original code) your new code to your question and I'll take a look.
– David C. Rankin
Nov 21 at 2:20
Dear David, I just add my new code in the original post, can you please take a look again? Thanks.
– Dat To
Nov 21 at 4:43
Your new code looks fine, but using the pointersizeOfBoardGame
is a bit "weird". For inserting'c'
in your array and pushing the other values one to the right in a row, since you are effectively using a 2D array, you will simply want tomemmove
the values to the right. Example to insert'c'
atboardOfGame[0][0]
you wouldmemmove (&boardOfGame[0][1], &boardOfGame[0][0], 6); boardOfGame[0][0] = 'c';
(you can also do the same thing with a simplefor
loop beginning atcol = 1
and settingcurrent column = column - 1
)
– David C. Rankin
Nov 21 at 4:52
Dear David, If i change the condition of if(isspace) to if(c != ',') then it will print only X X X X with proper space. However, it stop at the fourth row first column. For example, I will have a total of 7 row, in each row there will be an X for each column with space between each X for a total of 4 X and 3 spaces. Then if I run the code, it only display until reach boardOfGame[6][0] and stop, missing total 6 elements for the last row.
– Dat To
Nov 21 at 5:28
|
show 10 more comments
There are a number of ways to control the read loop -- however, the control must be based upon a successful read from the file. You can either use your nested loops and read, e.g.
for (int i = 0; i < *sizeOfBoardGame; i++) {
for (int j = 0; j < *sizeOfBoardGame; j++) {
if (!(inFS.get(c)))
goto readdone;
boardOfGame[i][j] = c;
}
}
readdone:;
(note: using fixed for
loops -- you cannot account for additional characters like spaces or the terminating 'n'
. for
loops will only execute that specific number of times regardless what the character read is. Better to use while
loops and counter-variables to ensure you fill each row and column with a valid character)
Or, preferably, just control the read itself, e.g.
while (row < BRDSZ && inFS.get(c)) {
if (!isspace (c)) {
boardOfGame[row][col++] = c;
if (col == BRDSZ) {
col = 0;
row++;
}
}
}
inFS.close();
Putting it into a short example you could do:
#include <iostream>
#include <fstream>
#include <cctype>
using namespace std;
#define BRDSZ 7 /* if you need constants, #define them */
#define MAXFN 1024
void initializeBoardGame (char (*boardOfGame)[BRDSZ]);
int main (void) {
char boardOfGame[BRDSZ][BRDSZ] = {{0}};
initializeBoardGame (boardOfGame);
for (int i = 0; i < BRDSZ; i++) {
for (int j = 0; j < BRDSZ; j++)
cout << " " << boardOfGame[i][j];
cout << 'n';
}
}
void initializeBoardGame (char (*boardOfGame)[BRDSZ])
{
char nameOfFile[MAXFN],
c;
int row = 0,
col = 0;
ifstream inFS;
cout << "Please enter the name of the input file: ";
if (!(cin >> nameOfFile)) {
cerr << "error: invalid filename entryn";
exit (EXIT_FAILURE);
}
inFS.open (nameOfFile);
if (!(inFS.is_open())) {
cerr << "error: file open failed '" << nameOfFile << "'.n";
exit (EXIT_FAILURE);
}
while (row < BRDSZ && inFS.get(c)) {
if (!isspace (c)) {
boardOfGame[row][col++] = c;
if (col == BRDSZ) {
col = 0;
row++;
}
}
}
inFS.close();
if (row != BRDSZ) {
cerr << "error: insufficient values read from file.n";
exit (EXIT_FAILURE);
}
}
Example Input File
$ cat dat/board_7x7.txt
1 6 7 0 4 2 1
2 1 1 2 4 4 9
5 7 9 4 1 5 1
1 6 8 1 1 4 4
2 7 0 7 0 2 9
6 5 8 3 0 0 1
2 5 6 7 4 1 3
Example Use/Output
$ ./bin/readboard
Please enter the name of the input file: dat/board_7x7.txt
1 6 7 0 4 2 1
2 1 1 2 4 4 9
5 7 9 4 1 5 1
1 6 8 1 1 4 4
2 7 0 7 0 2 9
6 5 8 3 0 0 1
2 5 6 7 4 1 3
Look things over and let me know if you need further help.
Update To Read X,X,X,X
Now that I understand you want to read 4 values and replace the ','
in the input file with an actual ' '
(space
character) in your array, you can tweak the read loop to read each character, if the character is !isspace(c)
then store the character, if c == ','
then store a space, e.g.
while (row < BRDSZ && inFS.get(c)) {
if (c == ',')
boardOfGame[row][col++] = ' ';
else if (!isspace(c))
boardOfGame[row][col++] = c;
if (col == BRDSZ) {
col = 0;
row++;
}
}
Since you are storing a space between each X
(or character value) in your array, when you want to insert a character and move the existing column values to the right, you must move the column values by 2 instead of just shifting by 1
to account for the space
that is stored before the value, e.g. (to insert the letter 'c'
as the new first value in the array at boardOfGame[0][0]
, you could do:
memmove (&boardOfGame[0][2], &boardOfGame[0][0], BRDSZ - 2);
boardOfGame[0][0] = 'c';
boardOfGame[0][1] = ' ';
Putting that altogether in an example (and printing with an additional space between columns), you could do:
#include <iostream>
#include <fstream>
#include <cctype>
#include <cstring>
using namespace std;
#define BRDSZ 7 /* if you need constants, #define them */
#define MAXFN 1024
void initializeBoardGame (char (*boardOfGame)[BRDSZ]);
int main (void) {
char boardOfGame[BRDSZ][BRDSZ] = {{0}};
initializeBoardGame (boardOfGame);
for (int i = 0; i < BRDSZ; i++) { /* output original values */
for (int j = 0; j < BRDSZ; j++)
cout << " " << boardOfGame[i][j];
cout << 'n';
}
cout << 'n';
/* insert 'c' at boardOfGame[0][0] - shif existing right */
memmove (&boardOfGame[0][2], &boardOfGame[0][0], BRDSZ - 2);
boardOfGame[0][0] = 'c';
boardOfGame[0][1] = ' ';
for (int i = 0; i < BRDSZ; i++) { /* output with new value */
for (int j = 0; j < BRDSZ; j++)
cout << " " << boardOfGame[i][j];
cout << 'n';
}
}
void initializeBoardGame (char (*boardOfGame)[BRDSZ])
{
char nameOfFile[MAXFN],
c;
int row = 0,
col = 0;
ifstream inFS;
cout << "Please enter the name of the input file: ";
if (!(cin >> nameOfFile)) {
cerr << "error: invalid filename entryn";
exit (EXIT_FAILURE);
}
inFS.open (nameOfFile);
if (!(inFS.is_open())) {
cerr << "error: file open failed '" << nameOfFile << "'.n";
exit (EXIT_FAILURE);
}
while (row < BRDSZ && inFS.get(c)) {
if (c == ',')
boardOfGame[row][col++] = ' ';
else if (!isspace(c))
boardOfGame[row][col++] = c;
if (col == BRDSZ) {
col = 0;
row++;
}
}
inFS.close();
if (row != BRDSZ) {
cerr << "error: insufficient values read from file.n";
exit (EXIT_FAILURE);
}
}
Example Input File
$ cat dat/board_7x7-2.txt
5,9,3,7
2,6,2,1
1,9,0,9
2,1,7,3
6,1,6,3
1,7,3,8
3,0,6,4
Example Use/Output
$ ./bin/readboard2
Please enter the name of the input file: dat/board_7x7-2.txt
5 9 3 7
2 6 2 1
1 9 0 9
2 1 7 3
6 1 6 3
1 7 3 8
3 0 6 4
c 5 9 3
2 6 2 1
1 9 0 9
2 1 7 3
6 1 6 3
1 7 3 8
3 0 6 4
Reading from File with Unequal Rows
If I understand now and your data file looks similar to:
Example Input File
$ cat dat/board_7x7-3.txt
X, ,X, ,X, ,X
, , , , , , ,
X, ,X, ,X, ,X
, , , , , , ,
X, ,X, ,X, ,X
, , , , , , ,
X, ,X, ,X, ,X
And, your job is to read the X
values storing them in a 2D array with spaces stored between the X
values, then you will need to pass a pointer to either int
or size_t
as a parameter to your function so that it can be updated with the number of rows actually stored (since the rows containing all commas contain no values). The approach to reading is essentially the same, accept this time you will determine when valid data is read and if it is not the 1st column, you will add a space before it in your array, e.g.
while (row < BRDSZ && inFS.get(c)) {
if ((!isspace(c) && c != ',')) { /* read store only values */
if (col) /* if not 1st, store ' ' */
boardOfGame[row][col++] = ' ';
boardOfGame[row][col++] = c;
}
if (col == BRDSZ) {
col = 0;
row++;
}
}
The complete example with the additional pointer parameter added and the number of rows filled updated within the function is:
#include <iostream>
#include <fstream>
#include <cctype>
#include <cstring>
using namespace std;
#define BRDSZ 7 /* if you need constants, #define them */
#define MAXFN 1024
void initializeBoardGame (char (*boardOfGame)[BRDSZ], int *nrows);
int main (void) {
char boardOfGame[BRDSZ][BRDSZ] = {{0}};
int nrows = BRDSZ;
initializeBoardGame (boardOfGame, &nrows);
for (int i = 0; i < nrows; i++) { /* output original values */
for (int j = 0; j < BRDSZ; j++)
cout << boardOfGame[i][j];
cout << 'n';
}
cout << 'n';
/* insert 'c' at boardOfGame[0][0] - shif existing right */
memmove (&boardOfGame[0][2], &boardOfGame[0][0], BRDSZ - 2);
boardOfGame[0][0] = 'c';
boardOfGame[0][1] = ' ';
for (int i = 0; i < nrows; i++) { /* output with new value */
for (int j = 0; j < BRDSZ; j++)
cout << boardOfGame[i][j];
cout << 'n';
}
}
void initializeBoardGame (char (*boardOfGame)[BRDSZ], int *nrows)
{
char nameOfFile[MAXFN],
c;
int row = 0,
col = 0;
ifstream inFS;
cout << "Please enter the name of the input file: ";
if (!(cin >> nameOfFile)) {
cerr << "error: invalid filename entryn";
exit (EXIT_FAILURE);
}
inFS.open (nameOfFile);
if (!(inFS.is_open())) {
cerr << "error: file open failed '" << nameOfFile << "'.n";
exit (EXIT_FAILURE);
}
while (row < BRDSZ && inFS.get(c)) {
if ((!isspace(c) && c != ',')) { /* read store only values */
if (col) /* if not 1st, store ' ' */
boardOfGame[row][col++] = ' ';
boardOfGame[row][col++] = c;
}
if (col == BRDSZ) {
col = 0;
row++;
}
}
inFS.close();
if (row != BRDSZ)
*nrows = row;
}
Example Use/Output
$ ./bin/readboard3
Please enter the name of the input file: dat/board_7x7-3.txt
X X X X
X X X X
X X X X
X X X X
c X X X
X X X X
X X X X
X X X X
If this is not what you intend, the post the exact output you expect so I will know what your intent is regarding input lines that are all commas.
Last But Not Least
What this all boils down to is that your separators change between odd and even rows. This is a fairly ridiculous case, but it has educational value in helping you think through reading data with varying states of input.
When your rows are odd, your file is a comma-separated file. When you rows are even your file is a space-separated file. The simplest and most efficient test of whether an integer value (like row
in the code) is odd or even is simply to test if the 1-bit
is set (e.g. row & 1 == 0
is row is even and row & 1 == 1
row is odd)
So you simply swap which separator you are looking for based on whether your row
is odd or even, e.g.
while (row < BRDSZ && inFS.get(c)) { /* protect row bounds, read c */
if (col < BRDSZ) { /* protect col bounds */
if ((row & 1) == 0) { /* even no. row */
if (c != ',' && c != 'n') /* separator is ',' */
boardOfGame[row][col++] = c; /* assign c */
}
else { /* odd no. row */
if (!isspace(c) && c != 'n') { /* seperator is ' ' */
if (c == ',') /* if c ',' save ' ' */
boardOfGame[row][col++] = ' ';
else /* otherwise, use c */
boardOfGame[row][col++] = c;
}
}
}
if (c == 'n') { /* when newline reached */
col = 0; /* reset values, increment row */
row++;
}
}
inFS.close();
When you substitute this read into the last example, you end up with:
Example Use/Output
$ ./bin/readboard4
Please enter the name of the input file: dat/board_7x7-3.txt
X X X X
X X X X
X X X X
X X X X
c X X X
X X X X
X X X X
X X X X
Now having gone though this multiple ways, you should be picking up on the fact that reading data character by character is a simple matter of:
- testing the character "What do I have?";
- handling the character based on your needs, e.g. "What do I do with it?"; and
never forget to account for your line-ending characters (e.g.
'n'
) also being read as part of your read loop.
If you think of it that way, you should be able to sort it all out.
Thank you so much for your help! I'm be able to control the array right now. However, it will not display the same in the terminal as in the original file. It will print 7 rows, but only 5 columns for each row instead of 7, it not display like your example. Do you perhaps know how to fix it ? What does it mean when you use the if(!isspace(c)) to check whether it is a space or not? In my case, I must include the space. For example my file is: X, ,X, ,X, ,X - It prints: X, ,X, ,X
– Dat To
Nov 21 at 2:09
You don't read the space into your array. You only store characters. You handle the space in the output by including one in the output, e.g. as incout << " " << boardOfGame[i][j];
. I suspect that is where your column problem is partially coming from. Edit your question and add (but do not delete your original code) your new code to your question and I'll take a look.
– David C. Rankin
Nov 21 at 2:20
Dear David, I just add my new code in the original post, can you please take a look again? Thanks.
– Dat To
Nov 21 at 4:43
Your new code looks fine, but using the pointersizeOfBoardGame
is a bit "weird". For inserting'c'
in your array and pushing the other values one to the right in a row, since you are effectively using a 2D array, you will simply want tomemmove
the values to the right. Example to insert'c'
atboardOfGame[0][0]
you wouldmemmove (&boardOfGame[0][1], &boardOfGame[0][0], 6); boardOfGame[0][0] = 'c';
(you can also do the same thing with a simplefor
loop beginning atcol = 1
and settingcurrent column = column - 1
)
– David C. Rankin
Nov 21 at 4:52
Dear David, If i change the condition of if(isspace) to if(c != ',') then it will print only X X X X with proper space. However, it stop at the fourth row first column. For example, I will have a total of 7 row, in each row there will be an X for each column with space between each X for a total of 4 X and 3 spaces. Then if I run the code, it only display until reach boardOfGame[6][0] and stop, missing total 6 elements for the last row.
– Dat To
Nov 21 at 5:28
|
show 10 more comments
There are a number of ways to control the read loop -- however, the control must be based upon a successful read from the file. You can either use your nested loops and read, e.g.
for (int i = 0; i < *sizeOfBoardGame; i++) {
for (int j = 0; j < *sizeOfBoardGame; j++) {
if (!(inFS.get(c)))
goto readdone;
boardOfGame[i][j] = c;
}
}
readdone:;
(note: using fixed for
loops -- you cannot account for additional characters like spaces or the terminating 'n'
. for
loops will only execute that specific number of times regardless what the character read is. Better to use while
loops and counter-variables to ensure you fill each row and column with a valid character)
Or, preferably, just control the read itself, e.g.
while (row < BRDSZ && inFS.get(c)) {
if (!isspace (c)) {
boardOfGame[row][col++] = c;
if (col == BRDSZ) {
col = 0;
row++;
}
}
}
inFS.close();
Putting it into a short example you could do:
#include <iostream>
#include <fstream>
#include <cctype>
using namespace std;
#define BRDSZ 7 /* if you need constants, #define them */
#define MAXFN 1024
void initializeBoardGame (char (*boardOfGame)[BRDSZ]);
int main (void) {
char boardOfGame[BRDSZ][BRDSZ] = {{0}};
initializeBoardGame (boardOfGame);
for (int i = 0; i < BRDSZ; i++) {
for (int j = 0; j < BRDSZ; j++)
cout << " " << boardOfGame[i][j];
cout << 'n';
}
}
void initializeBoardGame (char (*boardOfGame)[BRDSZ])
{
char nameOfFile[MAXFN],
c;
int row = 0,
col = 0;
ifstream inFS;
cout << "Please enter the name of the input file: ";
if (!(cin >> nameOfFile)) {
cerr << "error: invalid filename entryn";
exit (EXIT_FAILURE);
}
inFS.open (nameOfFile);
if (!(inFS.is_open())) {
cerr << "error: file open failed '" << nameOfFile << "'.n";
exit (EXIT_FAILURE);
}
while (row < BRDSZ && inFS.get(c)) {
if (!isspace (c)) {
boardOfGame[row][col++] = c;
if (col == BRDSZ) {
col = 0;
row++;
}
}
}
inFS.close();
if (row != BRDSZ) {
cerr << "error: insufficient values read from file.n";
exit (EXIT_FAILURE);
}
}
Example Input File
$ cat dat/board_7x7.txt
1 6 7 0 4 2 1
2 1 1 2 4 4 9
5 7 9 4 1 5 1
1 6 8 1 1 4 4
2 7 0 7 0 2 9
6 5 8 3 0 0 1
2 5 6 7 4 1 3
Example Use/Output
$ ./bin/readboard
Please enter the name of the input file: dat/board_7x7.txt
1 6 7 0 4 2 1
2 1 1 2 4 4 9
5 7 9 4 1 5 1
1 6 8 1 1 4 4
2 7 0 7 0 2 9
6 5 8 3 0 0 1
2 5 6 7 4 1 3
Look things over and let me know if you need further help.
Update To Read X,X,X,X
Now that I understand you want to read 4 values and replace the ','
in the input file with an actual ' '
(space
character) in your array, you can tweak the read loop to read each character, if the character is !isspace(c)
then store the character, if c == ','
then store a space, e.g.
while (row < BRDSZ && inFS.get(c)) {
if (c == ',')
boardOfGame[row][col++] = ' ';
else if (!isspace(c))
boardOfGame[row][col++] = c;
if (col == BRDSZ) {
col = 0;
row++;
}
}
Since you are storing a space between each X
(or character value) in your array, when you want to insert a character and move the existing column values to the right, you must move the column values by 2 instead of just shifting by 1
to account for the space
that is stored before the value, e.g. (to insert the letter 'c'
as the new first value in the array at boardOfGame[0][0]
, you could do:
memmove (&boardOfGame[0][2], &boardOfGame[0][0], BRDSZ - 2);
boardOfGame[0][0] = 'c';
boardOfGame[0][1] = ' ';
Putting that altogether in an example (and printing with an additional space between columns), you could do:
#include <iostream>
#include <fstream>
#include <cctype>
#include <cstring>
using namespace std;
#define BRDSZ 7 /* if you need constants, #define them */
#define MAXFN 1024
void initializeBoardGame (char (*boardOfGame)[BRDSZ]);
int main (void) {
char boardOfGame[BRDSZ][BRDSZ] = {{0}};
initializeBoardGame (boardOfGame);
for (int i = 0; i < BRDSZ; i++) { /* output original values */
for (int j = 0; j < BRDSZ; j++)
cout << " " << boardOfGame[i][j];
cout << 'n';
}
cout << 'n';
/* insert 'c' at boardOfGame[0][0] - shif existing right */
memmove (&boardOfGame[0][2], &boardOfGame[0][0], BRDSZ - 2);
boardOfGame[0][0] = 'c';
boardOfGame[0][1] = ' ';
for (int i = 0; i < BRDSZ; i++) { /* output with new value */
for (int j = 0; j < BRDSZ; j++)
cout << " " << boardOfGame[i][j];
cout << 'n';
}
}
void initializeBoardGame (char (*boardOfGame)[BRDSZ])
{
char nameOfFile[MAXFN],
c;
int row = 0,
col = 0;
ifstream inFS;
cout << "Please enter the name of the input file: ";
if (!(cin >> nameOfFile)) {
cerr << "error: invalid filename entryn";
exit (EXIT_FAILURE);
}
inFS.open (nameOfFile);
if (!(inFS.is_open())) {
cerr << "error: file open failed '" << nameOfFile << "'.n";
exit (EXIT_FAILURE);
}
while (row < BRDSZ && inFS.get(c)) {
if (c == ',')
boardOfGame[row][col++] = ' ';
else if (!isspace(c))
boardOfGame[row][col++] = c;
if (col == BRDSZ) {
col = 0;
row++;
}
}
inFS.close();
if (row != BRDSZ) {
cerr << "error: insufficient values read from file.n";
exit (EXIT_FAILURE);
}
}
Example Input File
$ cat dat/board_7x7-2.txt
5,9,3,7
2,6,2,1
1,9,0,9
2,1,7,3
6,1,6,3
1,7,3,8
3,0,6,4
Example Use/Output
$ ./bin/readboard2
Please enter the name of the input file: dat/board_7x7-2.txt
5 9 3 7
2 6 2 1
1 9 0 9
2 1 7 3
6 1 6 3
1 7 3 8
3 0 6 4
c 5 9 3
2 6 2 1
1 9 0 9
2 1 7 3
6 1 6 3
1 7 3 8
3 0 6 4
Reading from File with Unequal Rows
If I understand now and your data file looks similar to:
Example Input File
$ cat dat/board_7x7-3.txt
X, ,X, ,X, ,X
, , , , , , ,
X, ,X, ,X, ,X
, , , , , , ,
X, ,X, ,X, ,X
, , , , , , ,
X, ,X, ,X, ,X
And, your job is to read the X
values storing them in a 2D array with spaces stored between the X
values, then you will need to pass a pointer to either int
or size_t
as a parameter to your function so that it can be updated with the number of rows actually stored (since the rows containing all commas contain no values). The approach to reading is essentially the same, accept this time you will determine when valid data is read and if it is not the 1st column, you will add a space before it in your array, e.g.
while (row < BRDSZ && inFS.get(c)) {
if ((!isspace(c) && c != ',')) { /* read store only values */
if (col) /* if not 1st, store ' ' */
boardOfGame[row][col++] = ' ';
boardOfGame[row][col++] = c;
}
if (col == BRDSZ) {
col = 0;
row++;
}
}
The complete example with the additional pointer parameter added and the number of rows filled updated within the function is:
#include <iostream>
#include <fstream>
#include <cctype>
#include <cstring>
using namespace std;
#define BRDSZ 7 /* if you need constants, #define them */
#define MAXFN 1024
void initializeBoardGame (char (*boardOfGame)[BRDSZ], int *nrows);
int main (void) {
char boardOfGame[BRDSZ][BRDSZ] = {{0}};
int nrows = BRDSZ;
initializeBoardGame (boardOfGame, &nrows);
for (int i = 0; i < nrows; i++) { /* output original values */
for (int j = 0; j < BRDSZ; j++)
cout << boardOfGame[i][j];
cout << 'n';
}
cout << 'n';
/* insert 'c' at boardOfGame[0][0] - shif existing right */
memmove (&boardOfGame[0][2], &boardOfGame[0][0], BRDSZ - 2);
boardOfGame[0][0] = 'c';
boardOfGame[0][1] = ' ';
for (int i = 0; i < nrows; i++) { /* output with new value */
for (int j = 0; j < BRDSZ; j++)
cout << boardOfGame[i][j];
cout << 'n';
}
}
void initializeBoardGame (char (*boardOfGame)[BRDSZ], int *nrows)
{
char nameOfFile[MAXFN],
c;
int row = 0,
col = 0;
ifstream inFS;
cout << "Please enter the name of the input file: ";
if (!(cin >> nameOfFile)) {
cerr << "error: invalid filename entryn";
exit (EXIT_FAILURE);
}
inFS.open (nameOfFile);
if (!(inFS.is_open())) {
cerr << "error: file open failed '" << nameOfFile << "'.n";
exit (EXIT_FAILURE);
}
while (row < BRDSZ && inFS.get(c)) {
if ((!isspace(c) && c != ',')) { /* read store only values */
if (col) /* if not 1st, store ' ' */
boardOfGame[row][col++] = ' ';
boardOfGame[row][col++] = c;
}
if (col == BRDSZ) {
col = 0;
row++;
}
}
inFS.close();
if (row != BRDSZ)
*nrows = row;
}
Example Use/Output
$ ./bin/readboard3
Please enter the name of the input file: dat/board_7x7-3.txt
X X X X
X X X X
X X X X
X X X X
c X X X
X X X X
X X X X
X X X X
If this is not what you intend, the post the exact output you expect so I will know what your intent is regarding input lines that are all commas.
Last But Not Least
What this all boils down to is that your separators change between odd and even rows. This is a fairly ridiculous case, but it has educational value in helping you think through reading data with varying states of input.
When your rows are odd, your file is a comma-separated file. When you rows are even your file is a space-separated file. The simplest and most efficient test of whether an integer value (like row
in the code) is odd or even is simply to test if the 1-bit
is set (e.g. row & 1 == 0
is row is even and row & 1 == 1
row is odd)
So you simply swap which separator you are looking for based on whether your row
is odd or even, e.g.
while (row < BRDSZ && inFS.get(c)) { /* protect row bounds, read c */
if (col < BRDSZ) { /* protect col bounds */
if ((row & 1) == 0) { /* even no. row */
if (c != ',' && c != 'n') /* separator is ',' */
boardOfGame[row][col++] = c; /* assign c */
}
else { /* odd no. row */
if (!isspace(c) && c != 'n') { /* seperator is ' ' */
if (c == ',') /* if c ',' save ' ' */
boardOfGame[row][col++] = ' ';
else /* otherwise, use c */
boardOfGame[row][col++] = c;
}
}
}
if (c == 'n') { /* when newline reached */
col = 0; /* reset values, increment row */
row++;
}
}
inFS.close();
When you substitute this read into the last example, you end up with:
Example Use/Output
$ ./bin/readboard4
Please enter the name of the input file: dat/board_7x7-3.txt
X X X X
X X X X
X X X X
X X X X
c X X X
X X X X
X X X X
X X X X
Now having gone though this multiple ways, you should be picking up on the fact that reading data character by character is a simple matter of:
- testing the character "What do I have?";
- handling the character based on your needs, e.g. "What do I do with it?"; and
never forget to account for your line-ending characters (e.g.
'n'
) also being read as part of your read loop.
If you think of it that way, you should be able to sort it all out.
There are a number of ways to control the read loop -- however, the control must be based upon a successful read from the file. You can either use your nested loops and read, e.g.
for (int i = 0; i < *sizeOfBoardGame; i++) {
for (int j = 0; j < *sizeOfBoardGame; j++) {
if (!(inFS.get(c)))
goto readdone;
boardOfGame[i][j] = c;
}
}
readdone:;
(note: using fixed for
loops -- you cannot account for additional characters like spaces or the terminating 'n'
. for
loops will only execute that specific number of times regardless what the character read is. Better to use while
loops and counter-variables to ensure you fill each row and column with a valid character)
Or, preferably, just control the read itself, e.g.
while (row < BRDSZ && inFS.get(c)) {
if (!isspace (c)) {
boardOfGame[row][col++] = c;
if (col == BRDSZ) {
col = 0;
row++;
}
}
}
inFS.close();
Putting it into a short example you could do:
#include <iostream>
#include <fstream>
#include <cctype>
using namespace std;
#define BRDSZ 7 /* if you need constants, #define them */
#define MAXFN 1024
void initializeBoardGame (char (*boardOfGame)[BRDSZ]);
int main (void) {
char boardOfGame[BRDSZ][BRDSZ] = {{0}};
initializeBoardGame (boardOfGame);
for (int i = 0; i < BRDSZ; i++) {
for (int j = 0; j < BRDSZ; j++)
cout << " " << boardOfGame[i][j];
cout << 'n';
}
}
void initializeBoardGame (char (*boardOfGame)[BRDSZ])
{
char nameOfFile[MAXFN],
c;
int row = 0,
col = 0;
ifstream inFS;
cout << "Please enter the name of the input file: ";
if (!(cin >> nameOfFile)) {
cerr << "error: invalid filename entryn";
exit (EXIT_FAILURE);
}
inFS.open (nameOfFile);
if (!(inFS.is_open())) {
cerr << "error: file open failed '" << nameOfFile << "'.n";
exit (EXIT_FAILURE);
}
while (row < BRDSZ && inFS.get(c)) {
if (!isspace (c)) {
boardOfGame[row][col++] = c;
if (col == BRDSZ) {
col = 0;
row++;
}
}
}
inFS.close();
if (row != BRDSZ) {
cerr << "error: insufficient values read from file.n";
exit (EXIT_FAILURE);
}
}
Example Input File
$ cat dat/board_7x7.txt
1 6 7 0 4 2 1
2 1 1 2 4 4 9
5 7 9 4 1 5 1
1 6 8 1 1 4 4
2 7 0 7 0 2 9
6 5 8 3 0 0 1
2 5 6 7 4 1 3
Example Use/Output
$ ./bin/readboard
Please enter the name of the input file: dat/board_7x7.txt
1 6 7 0 4 2 1
2 1 1 2 4 4 9
5 7 9 4 1 5 1
1 6 8 1 1 4 4
2 7 0 7 0 2 9
6 5 8 3 0 0 1
2 5 6 7 4 1 3
Look things over and let me know if you need further help.
Update To Read X,X,X,X
Now that I understand you want to read 4 values and replace the ','
in the input file with an actual ' '
(space
character) in your array, you can tweak the read loop to read each character, if the character is !isspace(c)
then store the character, if c == ','
then store a space, e.g.
while (row < BRDSZ && inFS.get(c)) {
if (c == ',')
boardOfGame[row][col++] = ' ';
else if (!isspace(c))
boardOfGame[row][col++] = c;
if (col == BRDSZ) {
col = 0;
row++;
}
}
Since you are storing a space between each X
(or character value) in your array, when you want to insert a character and move the existing column values to the right, you must move the column values by 2 instead of just shifting by 1
to account for the space
that is stored before the value, e.g. (to insert the letter 'c'
as the new first value in the array at boardOfGame[0][0]
, you could do:
memmove (&boardOfGame[0][2], &boardOfGame[0][0], BRDSZ - 2);
boardOfGame[0][0] = 'c';
boardOfGame[0][1] = ' ';
Putting that altogether in an example (and printing with an additional space between columns), you could do:
#include <iostream>
#include <fstream>
#include <cctype>
#include <cstring>
using namespace std;
#define BRDSZ 7 /* if you need constants, #define them */
#define MAXFN 1024
void initializeBoardGame (char (*boardOfGame)[BRDSZ]);
int main (void) {
char boardOfGame[BRDSZ][BRDSZ] = {{0}};
initializeBoardGame (boardOfGame);
for (int i = 0; i < BRDSZ; i++) { /* output original values */
for (int j = 0; j < BRDSZ; j++)
cout << " " << boardOfGame[i][j];
cout << 'n';
}
cout << 'n';
/* insert 'c' at boardOfGame[0][0] - shif existing right */
memmove (&boardOfGame[0][2], &boardOfGame[0][0], BRDSZ - 2);
boardOfGame[0][0] = 'c';
boardOfGame[0][1] = ' ';
for (int i = 0; i < BRDSZ; i++) { /* output with new value */
for (int j = 0; j < BRDSZ; j++)
cout << " " << boardOfGame[i][j];
cout << 'n';
}
}
void initializeBoardGame (char (*boardOfGame)[BRDSZ])
{
char nameOfFile[MAXFN],
c;
int row = 0,
col = 0;
ifstream inFS;
cout << "Please enter the name of the input file: ";
if (!(cin >> nameOfFile)) {
cerr << "error: invalid filename entryn";
exit (EXIT_FAILURE);
}
inFS.open (nameOfFile);
if (!(inFS.is_open())) {
cerr << "error: file open failed '" << nameOfFile << "'.n";
exit (EXIT_FAILURE);
}
while (row < BRDSZ && inFS.get(c)) {
if (c == ',')
boardOfGame[row][col++] = ' ';
else if (!isspace(c))
boardOfGame[row][col++] = c;
if (col == BRDSZ) {
col = 0;
row++;
}
}
inFS.close();
if (row != BRDSZ) {
cerr << "error: insufficient values read from file.n";
exit (EXIT_FAILURE);
}
}
Example Input File
$ cat dat/board_7x7-2.txt
5,9,3,7
2,6,2,1
1,9,0,9
2,1,7,3
6,1,6,3
1,7,3,8
3,0,6,4
Example Use/Output
$ ./bin/readboard2
Please enter the name of the input file: dat/board_7x7-2.txt
5 9 3 7
2 6 2 1
1 9 0 9
2 1 7 3
6 1 6 3
1 7 3 8
3 0 6 4
c 5 9 3
2 6 2 1
1 9 0 9
2 1 7 3
6 1 6 3
1 7 3 8
3 0 6 4
Reading from File with Unequal Rows
If I understand now and your data file looks similar to:
Example Input File
$ cat dat/board_7x7-3.txt
X, ,X, ,X, ,X
, , , , , , ,
X, ,X, ,X, ,X
, , , , , , ,
X, ,X, ,X, ,X
, , , , , , ,
X, ,X, ,X, ,X
And, your job is to read the X
values storing them in a 2D array with spaces stored between the X
values, then you will need to pass a pointer to either int
or size_t
as a parameter to your function so that it can be updated with the number of rows actually stored (since the rows containing all commas contain no values). The approach to reading is essentially the same, accept this time you will determine when valid data is read and if it is not the 1st column, you will add a space before it in your array, e.g.
while (row < BRDSZ && inFS.get(c)) {
if ((!isspace(c) && c != ',')) { /* read store only values */
if (col) /* if not 1st, store ' ' */
boardOfGame[row][col++] = ' ';
boardOfGame[row][col++] = c;
}
if (col == BRDSZ) {
col = 0;
row++;
}
}
The complete example with the additional pointer parameter added and the number of rows filled updated within the function is:
#include <iostream>
#include <fstream>
#include <cctype>
#include <cstring>
using namespace std;
#define BRDSZ 7 /* if you need constants, #define them */
#define MAXFN 1024
void initializeBoardGame (char (*boardOfGame)[BRDSZ], int *nrows);
int main (void) {
char boardOfGame[BRDSZ][BRDSZ] = {{0}};
int nrows = BRDSZ;
initializeBoardGame (boardOfGame, &nrows);
for (int i = 0; i < nrows; i++) { /* output original values */
for (int j = 0; j < BRDSZ; j++)
cout << boardOfGame[i][j];
cout << 'n';
}
cout << 'n';
/* insert 'c' at boardOfGame[0][0] - shif existing right */
memmove (&boardOfGame[0][2], &boardOfGame[0][0], BRDSZ - 2);
boardOfGame[0][0] = 'c';
boardOfGame[0][1] = ' ';
for (int i = 0; i < nrows; i++) { /* output with new value */
for (int j = 0; j < BRDSZ; j++)
cout << boardOfGame[i][j];
cout << 'n';
}
}
void initializeBoardGame (char (*boardOfGame)[BRDSZ], int *nrows)
{
char nameOfFile[MAXFN],
c;
int row = 0,
col = 0;
ifstream inFS;
cout << "Please enter the name of the input file: ";
if (!(cin >> nameOfFile)) {
cerr << "error: invalid filename entryn";
exit (EXIT_FAILURE);
}
inFS.open (nameOfFile);
if (!(inFS.is_open())) {
cerr << "error: file open failed '" << nameOfFile << "'.n";
exit (EXIT_FAILURE);
}
while (row < BRDSZ && inFS.get(c)) {
if ((!isspace(c) && c != ',')) { /* read store only values */
if (col) /* if not 1st, store ' ' */
boardOfGame[row][col++] = ' ';
boardOfGame[row][col++] = c;
}
if (col == BRDSZ) {
col = 0;
row++;
}
}
inFS.close();
if (row != BRDSZ)
*nrows = row;
}
Example Use/Output
$ ./bin/readboard3
Please enter the name of the input file: dat/board_7x7-3.txt
X X X X
X X X X
X X X X
X X X X
c X X X
X X X X
X X X X
X X X X
If this is not what you intend, the post the exact output you expect so I will know what your intent is regarding input lines that are all commas.
Last But Not Least
What this all boils down to is that your separators change between odd and even rows. This is a fairly ridiculous case, but it has educational value in helping you think through reading data with varying states of input.
When your rows are odd, your file is a comma-separated file. When you rows are even your file is a space-separated file. The simplest and most efficient test of whether an integer value (like row
in the code) is odd or even is simply to test if the 1-bit
is set (e.g. row & 1 == 0
is row is even and row & 1 == 1
row is odd)
So you simply swap which separator you are looking for based on whether your row
is odd or even, e.g.
while (row < BRDSZ && inFS.get(c)) { /* protect row bounds, read c */
if (col < BRDSZ) { /* protect col bounds */
if ((row & 1) == 0) { /* even no. row */
if (c != ',' && c != 'n') /* separator is ',' */
boardOfGame[row][col++] = c; /* assign c */
}
else { /* odd no. row */
if (!isspace(c) && c != 'n') { /* seperator is ' ' */
if (c == ',') /* if c ',' save ' ' */
boardOfGame[row][col++] = ' ';
else /* otherwise, use c */
boardOfGame[row][col++] = c;
}
}
}
if (c == 'n') { /* when newline reached */
col = 0; /* reset values, increment row */
row++;
}
}
inFS.close();
When you substitute this read into the last example, you end up with:
Example Use/Output
$ ./bin/readboard4
Please enter the name of the input file: dat/board_7x7-3.txt
X X X X
X X X X
X X X X
X X X X
c X X X
X X X X
X X X X
X X X X
Now having gone though this multiple ways, you should be picking up on the fact that reading data character by character is a simple matter of:
- testing the character "What do I have?";
- handling the character based on your needs, e.g. "What do I do with it?"; and
never forget to account for your line-ending characters (e.g.
'n'
) also being read as part of your read loop.
If you think of it that way, you should be able to sort it all out.
edited Nov 22 at 1:53
answered Nov 21 at 1:44
David C. Rankin
40.1k32647
40.1k32647
Thank you so much for your help! I'm be able to control the array right now. However, it will not display the same in the terminal as in the original file. It will print 7 rows, but only 5 columns for each row instead of 7, it not display like your example. Do you perhaps know how to fix it ? What does it mean when you use the if(!isspace(c)) to check whether it is a space or not? In my case, I must include the space. For example my file is: X, ,X, ,X, ,X - It prints: X, ,X, ,X
– Dat To
Nov 21 at 2:09
You don't read the space into your array. You only store characters. You handle the space in the output by including one in the output, e.g. as incout << " " << boardOfGame[i][j];
. I suspect that is where your column problem is partially coming from. Edit your question and add (but do not delete your original code) your new code to your question and I'll take a look.
– David C. Rankin
Nov 21 at 2:20
Dear David, I just add my new code in the original post, can you please take a look again? Thanks.
– Dat To
Nov 21 at 4:43
Your new code looks fine, but using the pointersizeOfBoardGame
is a bit "weird". For inserting'c'
in your array and pushing the other values one to the right in a row, since you are effectively using a 2D array, you will simply want tomemmove
the values to the right. Example to insert'c'
atboardOfGame[0][0]
you wouldmemmove (&boardOfGame[0][1], &boardOfGame[0][0], 6); boardOfGame[0][0] = 'c';
(you can also do the same thing with a simplefor
loop beginning atcol = 1
and settingcurrent column = column - 1
)
– David C. Rankin
Nov 21 at 4:52
Dear David, If i change the condition of if(isspace) to if(c != ',') then it will print only X X X X with proper space. However, it stop at the fourth row first column. For example, I will have a total of 7 row, in each row there will be an X for each column with space between each X for a total of 4 X and 3 spaces. Then if I run the code, it only display until reach boardOfGame[6][0] and stop, missing total 6 elements for the last row.
– Dat To
Nov 21 at 5:28
|
show 10 more comments
Thank you so much for your help! I'm be able to control the array right now. However, it will not display the same in the terminal as in the original file. It will print 7 rows, but only 5 columns for each row instead of 7, it not display like your example. Do you perhaps know how to fix it ? What does it mean when you use the if(!isspace(c)) to check whether it is a space or not? In my case, I must include the space. For example my file is: X, ,X, ,X, ,X - It prints: X, ,X, ,X
– Dat To
Nov 21 at 2:09
You don't read the space into your array. You only store characters. You handle the space in the output by including one in the output, e.g. as incout << " " << boardOfGame[i][j];
. I suspect that is where your column problem is partially coming from. Edit your question and add (but do not delete your original code) your new code to your question and I'll take a look.
– David C. Rankin
Nov 21 at 2:20
Dear David, I just add my new code in the original post, can you please take a look again? Thanks.
– Dat To
Nov 21 at 4:43
Your new code looks fine, but using the pointersizeOfBoardGame
is a bit "weird". For inserting'c'
in your array and pushing the other values one to the right in a row, since you are effectively using a 2D array, you will simply want tomemmove
the values to the right. Example to insert'c'
atboardOfGame[0][0]
you wouldmemmove (&boardOfGame[0][1], &boardOfGame[0][0], 6); boardOfGame[0][0] = 'c';
(you can also do the same thing with a simplefor
loop beginning atcol = 1
and settingcurrent column = column - 1
)
– David C. Rankin
Nov 21 at 4:52
Dear David, If i change the condition of if(isspace) to if(c != ',') then it will print only X X X X with proper space. However, it stop at the fourth row first column. For example, I will have a total of 7 row, in each row there will be an X for each column with space between each X for a total of 4 X and 3 spaces. Then if I run the code, it only display until reach boardOfGame[6][0] and stop, missing total 6 elements for the last row.
– Dat To
Nov 21 at 5:28
Thank you so much for your help! I'm be able to control the array right now. However, it will not display the same in the terminal as in the original file. It will print 7 rows, but only 5 columns for each row instead of 7, it not display like your example. Do you perhaps know how to fix it ? What does it mean when you use the if(!isspace(c)) to check whether it is a space or not? In my case, I must include the space. For example my file is: X, ,X, ,X, ,X - It prints: X, ,X, ,X
– Dat To
Nov 21 at 2:09
Thank you so much for your help! I'm be able to control the array right now. However, it will not display the same in the terminal as in the original file. It will print 7 rows, but only 5 columns for each row instead of 7, it not display like your example. Do you perhaps know how to fix it ? What does it mean when you use the if(!isspace(c)) to check whether it is a space or not? In my case, I must include the space. For example my file is: X, ,X, ,X, ,X - It prints: X, ,X, ,X
– Dat To
Nov 21 at 2:09
You don't read the space into your array. You only store characters. You handle the space in the output by including one in the output, e.g. as in
cout << " " << boardOfGame[i][j];
. I suspect that is where your column problem is partially coming from. Edit your question and add (but do not delete your original code) your new code to your question and I'll take a look.– David C. Rankin
Nov 21 at 2:20
You don't read the space into your array. You only store characters. You handle the space in the output by including one in the output, e.g. as in
cout << " " << boardOfGame[i][j];
. I suspect that is where your column problem is partially coming from. Edit your question and add (but do not delete your original code) your new code to your question and I'll take a look.– David C. Rankin
Nov 21 at 2:20
Dear David, I just add my new code in the original post, can you please take a look again? Thanks.
– Dat To
Nov 21 at 4:43
Dear David, I just add my new code in the original post, can you please take a look again? Thanks.
– Dat To
Nov 21 at 4:43
Your new code looks fine, but using the pointer
sizeOfBoardGame
is a bit "weird". For inserting 'c'
in your array and pushing the other values one to the right in a row, since you are effectively using a 2D array, you will simply want to memmove
the values to the right. Example to insert 'c'
at boardOfGame[0][0]
you would memmove (&boardOfGame[0][1], &boardOfGame[0][0], 6); boardOfGame[0][0] = 'c';
(you can also do the same thing with a simple for
loop beginning at col = 1
and setting current column = column - 1
)– David C. Rankin
Nov 21 at 4:52
Your new code looks fine, but using the pointer
sizeOfBoardGame
is a bit "weird". For inserting 'c'
in your array and pushing the other values one to the right in a row, since you are effectively using a 2D array, you will simply want to memmove
the values to the right. Example to insert 'c'
at boardOfGame[0][0]
you would memmove (&boardOfGame[0][1], &boardOfGame[0][0], 6); boardOfGame[0][0] = 'c';
(you can also do the same thing with a simple for
loop beginning at col = 1
and setting current column = column - 1
)– David C. Rankin
Nov 21 at 4:52
Dear David, If i change the condition of if(isspace) to if(c != ',') then it will print only X X X X with proper space. However, it stop at the fourth row first column. For example, I will have a total of 7 row, in each row there will be an X for each column with space between each X for a total of 4 X and 3 spaces. Then if I run the code, it only display until reach boardOfGame[6][0] and stop, missing total 6 elements for the last row.
– Dat To
Nov 21 at 5:28
Dear David, If i change the condition of if(isspace) to if(c != ',') then it will print only X X X X with proper space. However, it stop at the fourth row first column. For example, I will have a total of 7 row, in each row there will be an X for each column with space between each X for a total of 4 X and 3 spaces. Then if I run the code, it only display until reach boardOfGame[6][0] and stop, missing total 6 elements for the last row.
– Dat To
Nov 21 at 5:28
|
show 10 more comments
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53403718%2f2d-pointer-array-does-not-cointain-value-in-element-after-initialization%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Why !.eof() inside a loop condition is always wrong. You will want to review Why is iostream::eof inside a loop condition considered wrong?
– David C. Rankin
Nov 21 at 0:42
Thank you sir, I try to fix and now my array has value in its elements. I just still dont understand the part that If i can display my array to the terminal by assigning c to the element, why cant my array keep that value to element?
– Dat To
Nov 21 at 0:55
What happens is
EOF
isn't set until you attempt to read after reading the final character in the file. Your read of the final character does Not setEOF
(as it was a good read). However, on your next read, you encounterEOF
-- but in your loop, it's to late, you hitEOF
withinFS.get(c);
, then you attempt to assign an unknown value forc
toboardOfGame[i][j] = c;
invoking Undefined Behavior - so all bets are off at that point.– David C. Rankin
Nov 21 at 0:59
Instead, control your entire read loop with
while ((inFS.get(c))) { /* now use c */ }
– David C. Rankin
Nov 21 at 1:02
I have tried three different ways to control the read loop like this: while (inFS >> c); while (inFS.get(c)); while(!(inFS >> c).eof()); These three works properly, which i means it does read a character from my file then assign that character to boardOfGame[i][j]. However, it displays terribly with a weird pattern in the terminal as one character will be displayed 49 times (my 2D array is 7 * 7). I do not know what causes this?
– Dat To
Nov 21 at 1:15