2

I want to copy contents in a text file to a string or a *char. It would be better if I can copy the file content to an array of strings (each line an element of that array). This is my code:

int main() {
   ifstream inFile;
   inFile.open("index.in.txt"); //index.in has in each line a name and at the end there is a "."
   char ab[11];
   int q=0;
   char *a[111];
   if (inFile.is_open()) {
      while (!inFile.eof()) {
         inFile >> ab; //i think i don't understand this line correctly
         a[q]=ab;
         cout<<a[q]<<endl;
         q++;
      }
   }
   else{ 
     cout<<"couldnt read file";
   }
   inFile.close();
   cout<<"\n"<<ab<<endl; //it shoud be "." and it is
   cout<<"\n"<<a[0]<<endl; //it should be "ion" but it gives me "."
   return 0;
}

All values in the a array are equal to the last line which is dot

Martin G
  • 14,280
  • 9
  • 69
  • 82
Fanckush
  • 133
  • 3
  • 10
  • check [this](http://stackoverflow.com/questions/13035674/how-to-read-line-by-line-or-a-whole-text-file-at-once) – Mohit Jain Apr 25 '14 at 11:42
  • You should be using `std::vector` instead of an array of character pointers. Also, do you want each line in its own string, or each word? – crashmstr Apr 25 '14 at 11:42
  • each line has only one word so it makes no difference for me – Fanckush Apr 25 '14 at 11:42
  • @MohitJain thanks i'll check that – Fanckush Apr 25 '14 at 11:44
  • Don't do `while (!inFile.eof())`, it will not work as you expect and will cause you to iterate once to many. Instead do `while (inFile >> ab)`. The reason is that the `eofbit` flag is not set until *after* you try to read from beyond end of the file. – Some programmer dude Apr 25 '14 at 11:47
  • +1 for proper formatting, and you have tried some debug prints and your suspection. – Mohit Jain Apr 25 '14 at 11:54
  • possible duplicate of [What is the best way to slurp a file into a std::string in c++?](http://stackoverflow.com/questions/116038/what-is-the-best-way-to-slurp-a-file-into-a-stdstring-in-c) – Konrad Rudolph Apr 25 '14 at 12:19

4 Answers4

4
int main() {
   ifstream inFile;
   inFile.open("index.in.txt"); //index.in has in each line a name and at the end there is a "."
   std::vector< std::string > lines;
   std::string line;
   if (inFile.is_open()) {
      while ( getline( inFile, line ) ) {
         lines.push_back( line );
      }
   }
...

now lines is a vector of string, each is a line from file

borisbn
  • 4,704
  • 20
  • 38
2

You are overwriting your only buffer everytime in inFile >> ab; You read a line in buffer and save the address of buffer somewhere. Next time you read next line in the same buffer and save the exact same address as second line. If you read back your first line you will end up reading updated buffer i.e. last line.

You can change your code to

#include <vector>
#include <string>
#include <fstream>

using namespace std;
int main() {
   ifstream inFile;
   inFile.open("index.in.txt"); //index.in has in each line a name and at the end there is a "."
   string ab; //char ab[11];
   int q=0;
   vector< string > a(111); //char *a[111];
   if (inFile.is_open()) {
      while (!inFile.eof()) {
         inFile >> ab;
         a[q]=ab;
         cout<<a[q]<<endl;
         q++;
      }
    }
    else cout<<"couldnt read file";
    inFile.close();
    cout<<"\n"<<ab<<endl; //it shoud be "." and it is
    cout<<"\n"<<a[0]<<endl; //it should be "ion" but it gives me "."
    return 0;
}

Better use std::string and std::vector instead of arrays.

Mohit Jain
  • 29,414
  • 8
  • 65
  • 93
  • std::string and std::vectors are smart containers that take care of memory management. So each time you assign a string to vector[idx], a new buffer would be created for vector[idx]. For more details you can read about [c-dynamic memory management](http://en.wikipedia.org/wiki/C_dynamic_memory_allocation) malloc etc, C++ dynamic memory i.e. new/delete and then basic STL (std::string, std::vector, std::list, std::set, std::map etc. – Mohit Jain Apr 25 '14 at 12:16
  • 1
    Note: [`while (!inFile.eof())` is a *bad idea*](http://stackoverflow.com/questions/5605125/why-is-iostreameof-inside-a-loop-condition-considered-wrong) – WhozCraig Apr 25 '14 at 12:48
  • @WhozCraig i copied the code from a site, then made it for and array of chars instead of *char – Fanckush Apr 26 '14 at 14:21
  • @MohitJain so i suppose if want to do it with arrays and *chars then i have to manually take care of the memory allocation, hmm... – Fanckush Apr 26 '14 at 17:30
  • You need to use malloc/new and free/delete in your code to take care of memory allocation. Or char *a[111]; needs to be replaced with a[111][11] and you need to read directly into a. – Mohit Jain Apr 27 '14 at 05:51
2
#include <iostream>
#include <fstream>
#include <vector>
#include <string>

bool ReadFile(const std::string &sFileName, 
              std::vector<std::string> &vLines)
{
    std::ifstream ifs(sFileName);
    if (!ifs)
        return false;
    std::string sLine;
    while (std::getline(ifs, sLine))
        vLines.push_back(sLine);
    return !ifs.bad();
}

int main() 
{
    const std::string sFileName("Test.dat");
    std::vector<std::string> vData;
    if (ReadFile(sFileName, vData))
        for (std::string &s : vData)
            std::cout << s << std::endl;
    return 0;
}
Michael J
  • 6,879
  • 1
  • 21
  • 28
1

In order to read a line you MUST use std::getline. The >> operator will only read a word, that is a sequence of characters ended by a whitespace.

See: http://en.cppreference.com/w/cpp/string/basic_string/getline

fjardon
  • 7,510
  • 19
  • 29