Classes reading one word from file C++ - c++

This is my program and it supposed to get text word by word from file Team.txt but it says it can't open the file. I tried showing directory directly to the file still the same answers. I think I got something here:
class Team
{
public:
string name;
string dificulty;
string section;
};
void GetTeamInfo(class Team);
int main()
{
Team ko;
GetTeamInfo(ko);
cout << ko.name;
cout << ko.dificulty;
cout << ko.section;
system("PAUSE");
}
void GetTeamInfo(Team)
{
std::ifstream fd;
fd.open("Team.txt");
Team ko;
if (fd.is_open())
{
fd >> ko.name;
fd >> ko.dificulty;
fd >> ko.section;
}
else
{
std::cout << "Mistake can't open file 'Team.txt'\n";
}
}

It doesn't work because your argument handling is all wrong.
The declaration
void GetTeamInfo(Team)
tells the compiler that GetTeamInfo is a function which takes an argument of type Team, but you don't give it a name so you can't use the argument anywhere inside the function.
If you want to use the passed argument you should give it a name:
void GetTeamInfo(Team ko)
You then don't have to declare the variable ko inside the function.
However, this is not going to work anyway, because arguments are by default passed by value, that means arguments are copies of the values from the caller. And changing a copy will of course not change the original. So what you should do it pass the argument by reference:
void GetTeamInfo(Team& ko)
All of this is very basic C++ knowledge, and any good book or tutorial should have learned you this very early.
As for the problem of the program not being able to open your file, there are multiple possible causes for that problem:
Your IDE (Integrated Development Environment) is having one current directory for your program, and the file is not in that directory. This can be changed with project settings.
The file is actually not where you think it is.
The file simply doesn't exist.
On systems such as Linux and Mac OSX filenames are case sensitive, and the actual file doesn't have a capital 'T' in its name.

Related

Reading files when spawning a child process when the current directory is not the executable directory

Edit 1: This is NOT a duplicate of this question because that person wants to know how to get the executable path. I can get the path just fine, I'm just wondering if there's a more convenient way of USING the path without modifying hundreds of calls to ifstream in my code.
Edit 2: First I'm moving Edit #1 to the top because people still think that the other question answers mine. It does not. I am NOT asking that question. Also I'm going to clarify that my initial question was probably phrased incorrectly. Someone posted in the comments a solution that works for me.
Here is how I would rephrase my question.
I have a program which spawns child processes, in other words it's a program that runs other programs. Program A spawns B, C, D, E, F, etc. My files are organized like so: Program A is at "dir/a/" and B is at "dir/a/b/" and C is at "dir/a/c/" etc.
Now assuming that Program B is written in C++ and it uses ifstream to deal with reading and writing files, my initial question was "is there a way to write Program B's code so that it can deal with reading in files from the executable directory and not from the directory it was spawned?" Because when A runs B, B thinks it's in "dir/a/" when the file is in "dir/a/b/file.txt". So calling ifstream("file.txt") goes to the wrong place. I would need to rewrite the code to ifstream(prefix + "file.txt") everywhere in Program B's code instead. This also needs to work such that I can run B directly rather than through A. Other programs like C, D, E, F, etc. may or may not be written in C++ and may or may not have implemented their own ways of handling this problem.
Many of the solutions posted are just different ways of doing the prefix + filename trick which I already knew about before I asked this question.
The solution posted below that I found which worked is to just change the directory before spawning the process. Thus when the process is spawned, it thinks it is in the new directory. This solves my problem because now it will work for any program, whether it is B, C, D, E, etc or whether it is in C++ or uses ifstream at all. This should have been really obvious in hindsight but for some reason I didn't realize I could run a command to change the directory before spawning the process. So this works for my case and so that's why it's the answer to my question.
Other people keep writing answers to the wrong question, though maybe that's my fault for not writing in the right way or understanding what my problem really was in the first place.
-- The original post --
I have two programs. Program A spawns the child process Program B. Program B uses std::ifstream("file.txt") to read in a file. However, Program A is located in /programs/a/ while Program B is in /programs/a/children/b/. Meaning that when I spawn B as a child process, Program B thinks its current directory is /programs/a and looks for file.txt there (but file.txt is actually in /programs/a/children/b).
I know that the first argument passed to Program B is always the executable path, so I can just take that and modify my calls to file I/O functions to prefix the path with that. But how do I do this in a good way? Is there a convenient way to get this to work without changing much code in Program B? I want to be able to run Program B on its own, as well as from Program A, and in both cases it should be able to read file.txt. That's why I can't just hardcode the filepath, I want it to work in both cases without changing any code between them.
For instance, I can think of making a wrapper class and then changing every call of std::ifstream so that it calls the wrapper instead, kind of like this:
std::ifstream Wrapper::ifstream(const std::string& path)
{
return std::ifstream(prefix + path); // prefix is member variable
}
But for a project with many calls to ifstream this is inconvenient and possibly inconsistent. Any accidental use of ifstream directly could cause a crash. I would also need to do the same thing for any output filestreams too. And I would really like to minimize any external dependencies, so I'd prefer if there was a built-in way to avoid this problem. It would be nice if I could just toggle some kind of option in the ifstream class so that any call to ifstream("file.txt") becomes ifstream("path/to/file.txt"). Is this the best I can do, or is there any better option out there?
There is a standard (since C++17) way to figure this out. It is important to notice that as this is standard, it should work with every platform where C++ is implemented: Windows, Linux, MacOS, etc. The standard will take care of handling idiosyncrasies as separators.
You can use std::filesystem::canonical to get the current executable's location. Then get the location of the parent directory and append the filename you want.
An example is:
namespace fs = std::filesystem;
int main( int argc, char* argv[] ) {
fs::path path( fs::canonical( argv[0] ) );
fs::path file = path.parent_path() / "file.txt";
std::cout << file << std::endl;
}
This should print /programs/a/children/b/file.txt on Linux or Mac and "c:\Programs\A\Children\b\file.txt" on Windows (if paths are like that).
Here is an illustration of using an environment variable as a common information that any program started from a shell in which it is defined can use. The writer writes a short text to a file, the reader reads it out. Both programs try to read the environment variable A_B_PROG_FILE which should contain the path to a file (which may not exist). This variable name is hard-coded common information; if we had the opportunity to use a common header (but not a duplicated one!) we could as well communicate the path itself that way; this is something to consider. But let's assume that the programs do not share a build environment.
First the writer.cpp:
#include <iostream>
#include <fstream>
#include <cstdlib>
/** #return -1 if file could not be opened, -2 if a write error occurred,
or 0 on success
*/
int main(int argc, char **argv)
{
const char *envPath = std::getenv("A_B_PROG_FILE");
const char *fpath = envPath ? envPath : "/tmp/defaultname.txt";
std::ofstream f(fpath);
if(!f)
{
std::cerr << "Couldn't open " << fpath << " for writing, exiting\n";
return -1;
}
f << "Hello, file ->" << fpath << "<- here!\n"
<< "This was written by ->" << (argc? argv[0] : "Unknown exe path") << "<-\n";
return f ? 0 : -2; // if f is not good exit with error code.
}
The reader is very similar:
#include <iostream>
#include <fstream>
#include <cstdlib> // getenv()
/** #return -1 if file could not be opened, -2 if a read error occurred,
or 0 on success
*/
int main()
{
const char *envPath = std::getenv("A_B_PROG_FILE");
const char *fpath = envPath ? envPath : "/tmp/defaultname.txt";
std::ifstream f(fpath);
if(!f)
{
std::cerr << "Couldn't open " << fpath << " for reading, exiting\n";
return -1;
}
std::cout << "file ->" << fpath << "<- contains: ->";
char c;
while(f.get(c))
{
std::cout << c;
}
std::cout << "<-";
if(!f.eof())
{
std::cerr << "Read error from ->" << fpath << "<-, exiting\n";
return -2;
}
}
Here is a sample session:
$ ls /tmp
$ unset A_B_PROG_FILE
$ ./reader
Couldn't open /tmp/defaultname.txt for reading, exiting
$ ./writer
$ ./reader
file ->/tmp/defaultname.txt<- contains: ->Hello, file ->/tmp/defaultname.txt<- here!
This was written by ->./writer<-
<-
$ export A_B_PROG_FILE=/tmp/ab
$ ./reader
Couldn't open /tmp/ab for reading, exiting
$ ./writer
$ ./reader
file ->/tmp/ab<- contains: ->Hello, file ->/tmp/ab<- here!
This was written by ->./writer<-
<-
$

Creating a CUSTOM exe file in C++

I'm working on a simple game engine just for the experience of it. I've realized, though, that I have no idea how to export the user's custom game as its own standalone executable. For example (this is not my actual game engine, it just provides an easy reference for discussion), suppose we had the following very simple code:
#include "stdafx.h"
#include <iostream>
#include <string>
using namespace std;
void RunGame(string question, string answer)
{
string submission;
cout << question << endl;
getline(cin, submission);
if (submission == answer)
cout << "Correct!";
else
cout << "Wrong!";
}
int main()
{
string question;
string answer;
cout << "Enter Question:" << endl;
getline(cin, question);
cout << "Enter Answer:" << endl;
getline(cin, answer);
RunGame(question, answer);
}
In this example the user gets to create their own customized bit of trivia, and then can test it immediately afterwards when RunGame is called. Now I want to be able to save their game with the trivia information they provided as its own .exe (basically it will perform from the call to RunGame onwards). How would I go about doing that?
To be clear, this isn't a question about what is the easiest/fastest way to make a game. It is looking for how to build a standalone, executable file from within code.
If you really want to store data inside the .exe itself:
An executable has a header that defines its size, boundaries and other useful stuff to the Operating System, so, essentially, the operating system knows where the code and data sections start and end, and it finally uses this information to load up the .exe to memory when it is asked to run.
Since the Operating System knows (besides the .exe's file size) where the executable actually ends, this also means that any data pasted after the .exe's "calculated" end (by headers) won't negatively effect the binary. It will still load and execute just fine.
You can abuse this property to concatenate data after the end of the executable.
I'll leave you with this test, using Windows' bundled WordPad application as a 'host' for some other data:
Go to C:\Windows and copy write.exe (WordPad) to another folder, so we can experiment without damaging anything.
Bring to that folder another file, any file will do. In my example, the data file will be a PDF called "myfancyfile.pdf"
Now, open a command prompt and use the COPY command to stitch both files together, making sure the .exe comes first:
copy /B write.exe+myfancyfile.pdf mynewprogram.exe
copy's /B flag means "binary copy", so essentially both files were pasted together without any kind of text or data conversion.
Try to run "mynewprogram.exe". Realize it runs just fine :-)
Self-modifying your .exe with data is not only feasible, it won't negatively effect functionality. Having that said, it is still a ugly way to persist data.
Have fun coding your solution.
You don't want to do this. A better way is to save the trivia in some custom format (for example, .txt, .dat, ..).
Then the game just handles this data.
So first think about the format inside of the .txt for example.
Lets say at first theres a number, indicating which entry this is. Second follows the question and after that the answer follows. This, you must decide for yourself.
Example trivia-data.txt
1
How old is actor X from show Y?
32 years
2
...
...
#include <iostream> // std::cout, std::endl
#include <fstream> // std::ifstream, std::ofstream
using namespace std;
int main()
{
// create file
ofstream ofile("trivia-data.txt");
// define your data
int num_of_question = 1;
string question, answer;
getline(cin, question);
getline(cin, answer);
// write your data to the file
ofile << num_of_question << '\n';
ofile << question << '\n';
ofile << answer << '\n';
// close the file
ofile.close();
return 0;
}
Now that you created your data you just have to build your program in a way you would like to present this. Instead of writing to a file, you should read from a file and print the questions out and compare answers and what not. Look up std::ifstream for reading your file.
At the start you could ask your user if he would like to create a quiz or play one that already exists.
Edit:
Since this sounds a lot like homework I just provide some pseudo code.
I'd go for an approach like this(pseudo code):
print "Would you like to create(c) or play(p) a quiz? Answer(c/p): "
input = get_input() // 'c' or 'p'
if input == 'c'
// now do what I posted with some loops to create a couple of questions
else
print "Please provide an URL to the quiz-data you would like to play: "
url = get_input() // C:/test.txt
// read in data, print out questions, do comparisons and print answers etc
This is infinitely easier than your approach and this also makes it possible for others to create quizzes not just you.
Building an executable is non-trivial. You will first need to comply with the target operating systems' ABI so that it can find your program's entry point. The next step will be deciding how your program is going to be able to access system resources: probably you'll want your executable to implement dynamic linking so it can access shared libraries, and you'll need to load the various .dll or .so files you're going to need. All the instructions you'll need to write for this will vary from OS to OS, you may need to introduce logic to detect the exact platform and make informed decisions, and you will need to vary for 32 vs 64 bit.
At this point you're about ready to start emitting the machine instructions for your game.
A reasonable alternative here is (as done by Unity) to provide a "blank" executable with your engine. Your engine itself would be a shared library (.dll or .so) and the blank executable would simply be a wrapper that loads the shared library and invokes a function in it with a pointer to something in it's data section.
Generating your user's executable would comprise loading the appropriate blank, making platform-specific modifications to it to tell it the size of the data section you're intended to provide it with and writing your data in the appropriate format. Or, you could simply have a blank that has an embedded copy of the raw structure into which you write values, just like populating a struct in memory:
struct GameDefinition {
constexpr size_t AuthorNameLen = 80;
char author_[AutherNameLen+1];
constexpr size_t PublisherNameLen = 80;
char publisher_[PublisherNameLen+1];
constexpr size_t GameNameLen = 80;
char name_[GameNameLen+1];
constexpr size_t QuestionLen = 80;
constexpr size_t AnswerLen = 80;
char question_[QuestionLen+1];
char answer_[AnswerLen+1];
};
static GameDefinition gameDef;
#include "engine_library.h" // for run_engine
int main() {
run_engine(&gameDef);
}
You'd compile this againsst the shared-library stub for your engine, and emit it as an executable, then you'd look up the platform-specific details of the executable format, locate the position of "gameDef" in it. The you'd read the blank into memory, and write it out with the definition of "gameDef" replaced with the one based on user input.
But what many engines do is simply ship or require the user to install a compiler (Unity relies on C#). So instead of having to tweak executables and do all this crazy platform-specific stuff, they simply output a C/C++ program and compile it.
// game-generator
bool make_game(std::string filename, std::string q, std::string a) {
std::ostream cpp(filename + ".cpp");
if (!cpp.is_open()) {
std::cerr << "open failed\n";
return false;
}
cpp << "#include <engine.h>\n";
cpp << "Gamedef gd(\"" << gameName << "\", \"" << authorName << \");\n";
cpp << "int main() {\n";
cpp << " gd.q = \"" << q << \"\n";
cpp << " gd.a = \"" << a << \"\n";
cpp << " RunGame(gd);\n";
cpp << "}\n";
cpp.close();
if (!invoke_compiler(filename, ".cpp")) {
std::cerr << "compile failed\n";
return false;
}
if (!invoke_linker(filename)) {
std::cerr << "link failed\n";
return false;
}
}
If "RunGame" is not part of your engine but user-supplied, then you could emit that as part of the cpp code. Otherwise, the intent here is that it's making a call into your library.
Under Linux you might compile this with
g++ -Wall -O3 -o ${filename}.o ${filename}.cpp
and then
g++ -Wall -O3 -o ${filename} ${filename}.o -lengine_library
to link it against your engine's library.

C++ create ifstream/ofstream in a class, associated with pre-made text file

I am having a problem associating an ifstream read and ofstream print to a pre-made text file called finances.txt. This is within a class called Data. So far, this is what I've tried:
I declared ifstream read and ofstream print in the class header file. Then, in the cpp file:
Data::Data(string n, string d)
:name(n),
date(d)
read(name)
print(name)
{
cout << "name = " << name << endl;
read.open(name);
print.open(name);
//...
}
I also tried this, without declaring anything in the header:
Data::Data(string n, string d)
:name(n),
date(d)
{
ifstream read(name);
ofstream print(name);
//...
And just different variations of this kind of thing. The syntax is always correct in the sense that I don't get any errors, but whenever it runs, it acts like the file doesn't exist and creates a new one named finances.txt, which in turn erases all of the text that was in the original. I have done this correctly before and just can't remember what I did and what I am doing incorrectly here.
I am a little confused as to what exactly you are trying to do?
Are you trying to append to the file? Because when you call
ofstream print(name) you are writing over the file that you are reading in.
So if you want to append to that same file you have to add.
fstream::app in the declaration of the ofstream

C++: Retrieving filename from istream

I have a function:
void read_file(istream &file);
In main(), I would pass in something like:
ifstream file;
file.open(argv[1]);
read_file(file);
Now, inside the read_file function, is there a way to get name of the file passed in?
For example, if argv[1] was "data1.txt", can we extract that string from inside read_file?
Thanks in advance.
By the way, I've tried:
cout << file << endl; // Doesn't work.
cout << &file << endl; // Same result.
They print an address.
File streams don't provide any way of retrieving the file name (or the open mode for that matter). What you can do is store it in the stream's cache using pword() and xalloc(). You would also need to register the necessary callbacks to resolve lifetime dependencies.
You could store the file name in a class level variable within main() so that it would be available for output within your read_file function:
const char* inFile = ""; // input file
int main(int argc, char* argv[])
{
// assign value from args to
// class level variable 'inFile'
inFile = argv[1];
}
Then you could output 'inFile' within your read_file function:
cout << inFile << endl;
The kind of thing you are asking for is normally done at the operating system level. That tends not to be portable and does not make it into standard libraries.
For example, supposed you opened the file with
"~/../something.txt"
What should the library return as the file name?
What if you opened a symbolic link?
What if the operating system permits multiple file names through directories for the same file?
The amount that the operating system can fill in depends upon the system itself. For example, if you've ever worked on a VMS system, it's system services do a lot of filling in that Unix and Dos systems do not.
Library designers avoid these system dependent problems by not including these features.

How to generate name of non-existent file and block its creation?

I want to test "No such file" behavior in my program. To do this (for sure) I need some file name, that will point to non-existent file.
What is a method to generate such file name and guarantee its non-existense til the test finishes? - I don't have any ideas, so I've tried actually nothing.
I want to implement it in C++, but, really, it's not a C++-specific question.
Update #1
It's acceptable to find solution at least for Linux.
There's probably no way of getting a 100% guarantee, but you can
easily protect against anything created by another user, by
first creating a directory in which only you have access rights,
and then creating the file there. After that, it's up to you to
ensure that you don't do anything you don't want. (As a general
rule, anytime you need temporary files, creating a directory
belonging to you, and to which only you have access, is a good
precautionary move.)
On Windows use _tempnam, on POSIX (e.g. Linux or OSX) use tempnam.
Actually it is impossible to create a file name which will not exist (race conditions). You can get a name with the stdio function 'char *tmpnam(char *s);' which generate a name that are difficult to guess.
You can make up a stream to avoid the unlikely case the name will be guessed:
class NoFStream : public std::fstream
{
public:
NoFStream(const char*, ios_base::openmode = ios_base::in | ios_base::out) {
setstate(ios_base::failbit);
}
void open(const char*, ios_base::openmode = ios_base::in | ios_base::out) {
setstate(ios_base::failbit);
}
};
int main()
{
NoFStream f("/tmp/file");
if(f >> std::ws) std::cout << "This will not succeed" << std::endl;
else std::cout << "Ok - it fails" << std::endl;
return 0;
}