-1

Hi I am trying to fill a vector with the information from a text file. The text file looks something like this:

10  8
5  6
15  4

I wrote some code in C++ trying to do this and it is not being filled. Here is my code:

#include <iostream>
#include <fstream>
#include <vector>
void duplicate() {
  ifstream in("Measured-Isotopes.txt");
  std::vector<std::pair<int, int>> vec;
  int A, Z;
  while(in >> A && in >> Z){
    vec.push_back((std::make_pair(A, Z)));
  }
  if(vec.empty()){
    cout<<"oops"<<endl;
  }

}
David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
  • 2
    What proof can you show that proves that there's a file named "Measured-Isotopes.txt" in the current directory of the process that's executing the compiled code? – Sam Varshavchik Aug 09 '21 at 01:09
  • 4
    Why do you not have `if (!in.good()) { std::cerr << "error: file open failed.\n"; return; }` to validate the file opening? (PS -- not use *MagicNumbers* or hardcode filenames in your code) ... you're good on the *MagicNumbers*, but not so on the hardcoded filename... – David C. Rankin Aug 09 '21 at 01:10
  • 2
    Unrelated: Instead of `vec.push_back((std::make_pair(A, Z)));` you could simply do `vec.emplace_back(A, Z);` – Ted Lyngmo Aug 09 '21 at 01:23
  • 1
    @Zach Finger verify that the file is being opened. Otherwise your code looks correct. – Zois Tasoulas Aug 09 '21 at 01:28

3 Answers3

2

Your code has no problem in my environment. I'm using Visual Studio 2017.
Please check that the file exists in the same folder with your program.

std::ifstream in("Measured-Isotopes.txt");
if (!in.is_open())
{
    std::cout << "File is not exist" << std::endl;
    return;
}
secuman
  • 539
  • 4
  • 12
  • This is very strange. I put that if statement in and it did not print FIle does not exist so the file is definitely there and opening. Is it possible it is not corresponding A and Z to the first and second column? – Zach Finger Aug 09 '21 at 01:39
  • I am trying something. I am recreating the text file because I realized that the first row of the text file is the labels which are strings so that may be messing it up – Zach Finger Aug 09 '21 at 01:42
  • What is the txt file's encoding? If it encoded by Unicode, you will see "oops" message. Please confirm txt file encoding is UTF8 or ANSI. – secuman Aug 09 '21 at 01:44
2

The most likely cause of the failure is "Measured-Isotopes.txt" isn't in the current working directory when you run your program leading to ifstream in("Measured-Isotopes.txt"); failing.

For any I/O operation, including file opening, you must always validate the stream state after each operation. In your case, you would want at minimum to validate the open succeeds, e.g.

  if (!in.good()) { 
    std::cerr << "error: file open failed.\n"; 
    return; 
  }

You may want to reconsider refactoring your code to provide the filename to read as the first argument to the program (that's what int main (int argc, char **argv) are for), or prompting the user to enter a filename and read the filename as input. You should not need to recompile your code simply to read from a different filename.

Further, consider opening the file stream in the calling function (main() here) and passing a reference to the open file stream as an argument to the function. If the file open fails, there is no need to make the function call to begin with.

Taking that approach, you could write your duplicate() function as:

#include <iostream>
#include <fstream>
#include <vector>

/* since I/O is performed in function, providing a return type that can
 * indicate success/failure is useful.
 */
bool duplicate (std::ifstream& in, std::vector<std::pair<int, int>>& vec)
{
  int A, Z;
  
  while (in >> A && in >> Z){
    vec.push_back((std::make_pair(A, Z)));
  }
  
  if(vec.empty()){
    return false;
  }
  
  return true;
}

(note: the return type is changed to bool so success/failure of the read is indicated through the return)

You can then write your main() as

int main (int argc, char **argv) {
  
  if (argc < 2) { /* validate at least 1 argument given */
    std::cerr << std::string {"error: insufficient arguments\n"
                              "usage: "} + argv[0] + " filename\n";
    return 1;
  }
  
  std::vector<std::pair<int, int>> vec;
  std::ifstream in (argv[1]);             /* open file */
  
  if (!in.good()) { /* validate open succeeds */
    std::cerr << "error: file open failed.\n";
    return 1;
  }
  
  if (duplicate (in, vec)) {    /* pass open stream, reference to vec, validate return */
    for (const auto p : vec) {  /* output vec contents on success */
      std::cout << p.first << ", " << p.second << '\n';
    }
  }
  else {  /* handle error on failure */
    std::cout << "oops - vector empty\n";
  }
}

(note: the use of '\n' instead of std::endl, see C++: “std::endl” vs “\n” for the differences (among other things std::endl causes the output buffer to be flushed))

Example Use/Output

With your data in the file dat/vectpairs.txt you would have:

./bin/vect_read_pairs dat/vectpairs.txt
10, 8
5, 6
15, 4

Look things over and let me know if you have questions.

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
0

So it turns out the problem was that my first row in the text file was a label that was a string so because I made my vector 2 ints it was getting messed up and not filling. I deleted the label and now it fills fine.