First of all, I didn't code in C for more then 8 years, but there is a hobby project I would like to work on where I ran into this issue.
I checked a similar question: Only printing last line of txt file when reading into struct array in C but in my case I don't have a semicolon at the end of the while cycle.
Anyway, so I have a nicknames.txt
file where I store nicknames, one in each line.
Then I want to read these nicknames into an array and select one random element of it.
Example nicknames.txt
:
alpha
beta
random nickname
...
Pirate Scrub
Then I read the TXT file:
int nicknameCount = 0;
char *nicknames[2000];
std::string line;
std::ifstream file("nicknames.txt");
FILE *fileID = fopen("asd.txt", "w");
while (std::getline(file, line))
{
nicknames[nicknameCount ] = line.data();
// (1)
fprintf(fileID, "%i: %s\n", nicknameCount - 1, nicknames[nicknameCount - 1]);
}
int randomNickIndex = rand() % nicknameCount;
// (2)
for (int i = 0; i < nicknameCount; i )
fprintf(fileID, "%i: %s\n", i, nicknames[i]);
fprintf(fileID, "Result: %s\n", nicknames[randomNickIndex]);
fprintf(fileID, "Result: %i\n", randomNickIndex);
fclose(fileID);
exit(0);
What then I see at point (1) is what I expect; the nicknames. Then later at point (2) every single member of the array is "Pirate Scrub", which is the last element of the nicknames.txt
.
I think it must be something obvious, but I just can't figure it out. Any ideas?
CodePudding user response:
line.data()
returns a pointer to the sequence of characters. It is always the same pointer. Every time you read a new line, the contents of line
are overwritten. To fix this, you will need to copy the contents of line
.
Change:
char *nicknames[2000];
to
char nicknames[2000][256];
and
nicknames[nicknameCount ] = line.data();
to
strcpy(nicknames[nicknameCount ], line.data());
However, using a vector to store the lines is probably better, since this is C
CodePudding user response:
Your nicknames
array does not contain copies of the strings, all the nicknames are pointers to the same data owned by line
.
Instead of char* nicknames[2000]
i would recommend you use
std::vector<std::string> nicknames;
and then inside the loop:
nicknames.push_back(line);
CodePudding user response:
This:
char *nicknames[2000];
is an array of 2000 pointers to char
. Nowhere in your code you are actually storing the strings from the file. This
nicknames[nicknameCount ] = line.data();
merely stores pointers to the line
s internal buffer in the array. In the next iteration this buffer is overwritten with contents of the next line.
Forget about all the C i/o. Mixing C and C is advanced and you don't need it here. If you want to store a dynamically sized array of strings in C , that is a std::vector<std::string>
:
std::vector<std::string> lines;
std::string line;
while (std::getline(file, line))
{
lines.push_back(line);
}
Also for writing to the output file you should use an std::ofstream
.