Copying from txt file to parallel arrays using pointer

I am trying to use parallel arrays to store cards information . Firstly use a function that reads all cards information from a text file and insert them to parallel arrays in the main program using a pointer.

My code compiles, but the output is just blank. I am also confused how do I put the names of the respective card into one parallel array when some cards have more than one words. I have searched online for similar solutions but no one had to use pointers to insert them, and no one had a name more than 2 words. Hopefully someone can point me in the right direction with simple stuff (cannot use vector) that an intro to C++ person would be able to use.

my text file looks like this ( I have aligned them so that it is easier to see the information needed to be put into 5 parallel arrays):
eg:(Array1 Array2 Array3 Array4 Array5)
1
2
3
4
Abyss Devolos      F0647 Balance   NA  SpeedStorm 
Ace Dragon         E7609 Attack    NA  HyperSphere 
Anubion A2         E1057 Defense   NA  Dual-Layer 
Vatryek Wing Accel B9492 Attack    NA  Burst 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <iostream>
#include <fstream>
using namespace std;

//for parallel arrays' size
const int size = 4;

//prototype for function
void readCards();

//main program
int main()
{
	readCards(); //calling function
	
	return 0;
}

//function
void readCards()
{

	string name[size];
	string ID[size];
	string type[size];
	string plusmode[size];
	string precedence[size];
	int x=0;
	
	ifstream readFile; // to read from file
	readFile.open("fakecards.txt");
	
	// to check if file can be opened
	if(!readFile)
		cout << "Game database missing"<< endl;
	
	// trying to read the files and store them in the parallel arrays using pointers
	while(readFile >> *(name+x) >> *(ID+x) >> *(type+x) >> *(plusmode+x) >> *(precedence+x) )
	{
		if(x<size)
			x++;
	}
	readFile.close();
	
	//checking output
	for(int y=0;y<size;y++)
	{
		cout << *(name+y) << " " <<	*(ID+y) << " " <<	*(type+y)  <<	*(plusmode+y) << " " <<	*(precedence+y) << endl;
	}
}

Last edited on
verify that you are actually accessing the file by just printing its contents to the screen as you read it in that while loop. If you can't do that, you can't do anything else.

is your file data accurate? It appears to be fixed width fields, in that case: you can read a line of the file (instead of using >> use getline) and slice it up (string substring function) at the correct offsets. String has a substring function, you can slice it with that.

that looks roughly (pseudocode) like this
1
2
3
4
5
6
while (.. getline into somestring)
{
      *(name+x) = somestring.substring(offset, width)
      *(ID+x) = ... etc
      ... etc 
}


consider a return statement if the file was not read
if(!readFile)
{
cout << "Game database missing"<< endl;
return;
}

file.close() will happen for you when the file object is destroyed (the function ends). I don't think you need it (but its ok to have it).

little stuff:
prefer {} to initialize.
const int size {4};

if you put main at the bottom, you don't need the headers for the functions. Saves a little aggravation.
Last edited on
1. Are you using C++ std::string as your array type? You should #include <string> then.

Hint: it's kinda hard to tell when using namespace std; infests the code.
https://stackoverflow.com/questions/1452721/why-is-using-namespace-std-considered-bad-practice

2. Using regular arrays is not good C++, use std::vectors (or another C++ container) instead.
https://www.learncpp.com/cpp-tutorial/an-introduction-to-stdvector/

Using pointer math is really error prone.
Last edited on
I suspect the pointer junk is a derpy classroom requirement as are the arrays.
Why professors waste 2 - 3 weeks teaching how not to do things remains a mystery.
@jonnin, it never ceases to amaze and frustrate me to see people just starting out learning C++ being subjected to such unnecessary torture.

I know learning how to use pointers is an essential task for a programmer, but ignoring what C++ has in its toolbox is something the Spanish Inquisition would do if it were teaching C++ to noobs.

C ways of doing things is not something a "just rolled off the rutabaga lorry" student should be subjected to.

When someone is an intermediate student, with a lot of C++ knowledge under their belt, getting exposed to the challenges of what legacy code might present then becomes an easier task.

Learning good, modern C++ will make a programmer less likely to use "doing it the C way" as the default way to solve a problem.
The name field in the file contains white spaces.
May be, have a delimiter to signal end of name and then use std::getline to read the name.

Instead of having five parallel arrays of strings, it may be simpler to use a two dimensional array with five columns.

For example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include <iostream>
#include <string>
#include <fstream>
#include <iomanip>

const std::size_t NUM_ITEMS = 4 ;
enum columns { NAME, ID, TYPE, PLUSMODE, PRECEDENCE, NUM_ARRAYS };
using array2d = std::string[NUM_ITEMS][NUM_ARRAYS] ;

bool read_cards( array2d& array, const std::string& file_name )
{
    if( std::ifstream file{file_name} )
    {
        std::size_t nread = 0 ;
        for( auto& row : array )
        {
            // note: name (which may contain spaces) is separated from id by the delimiter '|'
            // other fields have no white space in them (we use std::ws to skip over the new line at the end)
            if( std::getline( file, row[NAME], '|' ) &&
                file >> row[ID] >> row[TYPE] >> row[PLUSMODE] >> row[PRECEDENCE] >> std::ws ) ++nread ;
            else break ;
        }

        return nread == NUM_ITEMS ;
    }

    else return false ; // failed to open file
}

void print_cards( const array2d& array, std::ostream& stm = std::cout )
{
    stm << std::left ;

    for( const auto& row : array )
    {
        stm << std::setw(24) << row[NAME] << std::setw(8) << row[ID]
            << std::setw(10) << row[TYPE] << std::setw(4) << row[PLUSMODE]
            << "  " << row[PRECEDENCE] << '\n' ;
    }
}

bool create_test_file( const std::string& file_name )
{
    return bool ( std::ofstream{file_name} << "Abyss Devolos| F0647 Balance   NA  SpeedStorm\n"
                                              "Ace Dragon| E7609 Attack    NA  HyperSphere\n"
                                              "Anubion A2| E1057 Defense   NA  Dual-Layer\n"
                                              "Vatryek Wing Accel| B9492 Attack    NA  Burst\n" ) ;
}

int main()
{
    const std::string file_name = "fakecards.txt" ;

    if( create_test_file(file_name) )
    {
        array2d array ;
        if( read_cards( array, file_name ) )
        {
            print_cards(array) ;
            std::cout << "\nok.\n" ;
            // use info in array
        }
    }
}

http://coliru.stacked-crooked.com/a/154c80611f65a241
my text file looks like this ( I have aligned them so that it is easier to see the information needed to be put into 5 parallel arrays):


No. You should show exactly the content of the file. Not the file contents changed so that it 'looks pretty'. The layout matters especially when dealing with elements that may contain spaces.

If the file is actually as shown with each element starting at a specific column, then that can be dealt with fairly easy. If, however, the actual file is something like:


Abyss Devolos F0647 Balance NA SpeedStorm 
Ace Dragon E7609 Attack  NA HyperSphere 
Anubion A2 E1057 Defense  NA Dual-Layer 
Vatryek Wing Accel B9492 Attack  NA Burst 


then that is more difficult to parse.
Last edited on
if the fields are not fixed width and you are not in control of the file data, you have to get clever combined with an exact 'what can be where' description of the expected file format. For example if all the second column are hex numbers, and the first column can't contain hex numbers, you can figure that out, or you can find a reference point (eg if column 3 only has specific allowed words from a list, or whatever the N/A column can be when it is populated, or ???) to split from.

Text files that are not properly thought out when the format is designed absolutely suck, is what it comes down to. Text needs to be formatted with delimiters or fixed widths or something (eg xml tags) else that gives you what you need without having to exert tons of energy to handle it. But when the files lack these things, you do what you must or can with it.
Maybe something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <cctype>

constexpr size_t MaxElem { 100 };

int main() {
	std::ifstream ifs("fakecards.txt");

	if (!ifs)
		return (std::cout << "Cannot open file\n"), 1;

	std::string name[MaxElem];
	std::string ID[MaxElem];
	std::string type[MaxElem];
	std::string plusmode[MaxElem];
	std::string precedence[MaxElem];
	size_t noElems {};

	for (std::string line; noElems < MaxElem && std::getline(ifs, line); ++noElems) {
		std::istringstream iss(line);
		std::string word;

		for (; iss >> word && (word.size() != 5 || !(std::isdigit(static_cast<unsigned char>(word[3])) && std::isdigit(static_cast<unsigned char>(word[4])))); name[noElems] += word )
			if (!name[noElems].empty())
				name[noElems] += ' ';

		ID[noElems] = word;
		iss >> type[noElems] >> plusmode[noElems] >> precedence[noElems];
	}

	for (size_t i {}; i < noElems; ++i)
		std::cout << name[i] << " ! " << ID[i] << " ! " << type[i] << " ! " << plusmode[i] << " ! " << precedence[i] << '\n';
}



Abyss Devolos ! F0647 ! Balance ! NA ! SpeedStorm
Ace Dragon ! E7609 ! Attack ! NA ! HyperSphere
Anubion A2 ! E1057 ! Defense ! NA ! Dual-Layer
Vatryek Wing Accel ! B9492 ! Attack ! NA ! Burst

Last edited on
Topic archived. No new replies allowed.