how can I add error checking for empty string case - c++

There is error checking for a missing file or incorrectly typed file name...but for no file_name i.e. the string file_name is empty I get the error
terminate called after throwing an instance of 'std::logic_error'
and then windows throw an error at me as well.
My guess would be to add a check for the empty string... at file_name.str() before creating an instance of type ifstream...but just wanted to check.
void file_to_string(string file_name)
{
string line;
ifstream myfile(file_name.c_str());
if (myfile.is_open())
{
while (myfile.good())
{
getline(myfile, line);
cout << line;
}
myfile.close();
}
else
{
cout << "File : " << file_name << " : did not open";
}
}
int main(int argc, char* argv[])
{
file_to_string(argv[1]);
}

If you don't provide an argument at all, then argv will only contain one string, and argv[1] will be invalid. You'll have to check that before you even try to access it:
int main(int argc, char* argv[])
{
if (argc != 2) {
std::cerr << "Usage: " << argv[0] << " filename\n";
return EXIT_FAILURE;
}
file_to_string(argv[1]);
}
There's no particular need to check whether the string is empty; if it is, then the file will fail to open as it would for any other invalid filename, and your code already handles that.

EDIT: ouch - more coffee required. As was clearly stated, this is a string object not a pointer. So, use the string's provided members to verify it has content. In practice, at the top of the file, use string.empty ala:
if (file_name.empty())
{
// bug out
cout << "Invalid filename" ;
return;
}
EDIT2: As Nim correctly points out, this is not bulletproof as there could be no params supplied (and hence your reference to argv[1] will crater). So, check these cases in main() or in another function to verify the params.
You could do something like:
if (argc < 2)
{
// complain about lack of proper arguments
}
else
{
file_to_string(argv[1]);
}
All that said, in a slightly-more involved case you may face the need to add multiple different command line arguments, or for the arguments to be supplied in an arbitrary order (and so you can't rely on the index of '1' like you are here).
Handling all that properly can get fairly complicated quickly, so take a look at the approaches others have already implemented to handle this (and more - what if your options come from a config file instead of the command line?). One such option is Boost's support for program options; see http://www.boost.org/doc/libs/1%5F39%5F0/doc/html/program%5Foptions.html

the error occurs higher than that - what if an argument (i.e. what is in argv[1] is crap!) is not provided? This is why you should look at proper program options utilities...

Related

How to take characters in a text file as arguments

I'm fairly new to C++, I'm trying to figure out how to take in arguments from a text file and use them in my program.
So if I wanted to include a text file whatever.txt in a command, it would use specified lines as arguments.
Like if the text file looked like this:
1 2
and I wanted to use 1 and 2 from it, as arguments in my program.
So far from what I've gathered, I need something akin to this:
int main (int argc, char const *argv[]) {
to start, but not sure where to go from here.
I'm trying to mess around with certain stuff, but I'm still pretty new and outside of loops and things I can't do much with the language yet!
Short of giving you the code that will do this for you (which would ruin the fun of learning how to do these things), the steps I would follow would be:
Take one argument from the command line as the file name you want to read the information from. Think of running your script like this:
$ ./myscript whatever.txt
Then, argv[0]="./myscript" and argv[1]="whatever.txt".
Open the file (perhaps ifstream would be good for this).
Loop through each line of the file (maybe using getline to put each line into a string)
Parse each line of the file (I've seen stringstream used for filling variables from a string).
Hopefully that will help you along your way.
int main(int argc, char *argv[])
after retrieving files names in the main function you should open each file and retrieve its contents
Sample code
int main(int argc, char* argv[])
{
for(int i=1; i <= argc; i++) // i=1, assuming files arguments are right after the executable
{
string fn = argv[i]; //filename
cout << fn;
fstream f;
f.open(fn);
//your logic here
f.close();
}
return 0;
}
https://stackoverflow.com/a/30141375/3323444
argc is the number of arguments passed in to your program, argv is an array of character strings holding the names of arguments passed in.
at least there's one parameter passed in which is argv[0] which is name of program.
after building this code run it form a command prompt as:
main.exe data.txt
or simply DRAG AND DROP file "data.txt" on your main.exe
main.exe is your program, data.txt is text file containing data you want to use
#include<iostream>
#include<fstream>
int main(int argc, char* argv[])
{
char c;
if(argc < 2)
{
std::cout << "No file passed to program!" << std::endl;
return 1;
}
std::ifstream in (argv[1] , std::ios::in);
if(!in)
std::cout << "Unable to read file: " << argv[1] << std::endl;
while(in >> c)
std::cout << c << std::endl;
in.close();
std::cin.get();
std::cout << std::endl;
return 0;
}

How to check program start parameters from Windows Console?

At the start of my program, it should get path to the input file and path to the output file from the console.
But if user give not required number of parameters or wrong parameters (with spaces for example, or without ".txt") it should give the user second chance to enter those parameters without exiting the program. Is it possible?
int main(int argc, char* argv[])
{ //and here should be something to check if the user entered parameters correctly
//(number and if they look like a path) and give a user another try if this is wrong
//(so that user enter them from console again)
string path_open(argv[1]);
strin path_out(argv[2]);
Yes it's possible, but... weird. If you are going to have your program ask for input, why not just put that in a loop until you get proper input? Ultimately, I'd do one or the other:
Get command line input (and, as #IInspectable suggests in the comments, if it's not valid, exit the program); OR
Have program ask for input recursively until the user gives valid input.
Input from command line:
int main(int argc, char* argv[])
{
// sanity check to see if the right amount of arguments were provided:
if (argc < 3)
return 1;
// process arguments:
if (!path_open(argv[1]))
return 1;
if (!path_out(argv[2]))
return 1;
}
bool path_open(const std::string& path)
{
// verify path is correct...
}
Program asks for input:
int main()
{
std::string inputPath, outputPath;
do
{
std::cout << "Insert input path: ";
std::getline(std::cin, inputPath);
std::cout << std::endl;
std::cout << "Insert output path ";
std::getline(std::cin, outputPath);
} while (!(path_open(inputPath) && path_out(outputPath)));
}
Of course you'd validate input separately in case they were entering a valid input path but invalid output path, but you get the gist.

Checking if one document has the contents of the other c++

I am writing a code to check to see if one document (text1.txt) contains a list of banned words (bannedwords.txt) in it.
For example, the text1 document contains lyrics to a song and i want to check whether the word pig from the banned document is included in it. I then want the out put to be similar to:
"pig" found 0 times
"ant" found 3 times
This is what I have come up with so far but cannot seem to put the array of banned words into the search. Any help would be amazing :D
Thanks Fitz
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
bool CheckWord(char* filename, char* search)
{
int offset;
string line;
ifstream Myfile;
Myfile.open(filename);
if (Myfile.is_open())
{
while (!Myfile.eof())
{
getline(Myfile, line);
if ((offset = line.find(search, 0)) != string::npos)
{
cout << "The Word " << search<< " was found" << endl;
return true;
}
else
{
cout << "Not found";
}
}
Myfile.close();
}
else
cout << "Unable to open this file." << endl;
return false;
}
int main()
{
ifstream file("banned.txt");
if (file.is_open())//file is opened
{
string bannedWords[8];//array is created
for (int i = 0; i < 8; ++i)
{
file >> bannedWords[i];
}
}
else //file could not be opened
{
cout << "File could not be opened." << endl;
}
ifstream text1;//file is opened
text1.open("text1.txt");
if (!text1)//if file could not be opened
{
cout << "Unable to open file" << endl;
}
CheckWord("text1.txt", "cat");
system("pause");
}
Your main() function is reading the contents of banned.txt into an array of 8 std::string named bannedWords.
The array bannedWords is not being used anywhere after that. C++ doesn't work by magic, and compilers are not psychic so cannot read your mind in order to understand what you want your code to do. If an array (or its elements) are not accessed anywhere, they will not be used to do what you want with them.
You need to pass strings from the bannedWords array to CheckWord(). For example;
CheckWord("text1.txt", bannedWords[0].c_str());
will attempt to pass the contents of the first string in bannedWords to CheckWord().
However, that will not compile either unless you make the second parameter of CheckWord() (named search) be const qualified.
Or, better yet, change the type of the second argument to be of type std::string. If you do that, you can eliminate the usage of c_str() in the above.
I don't claim that is a complete solution to your problem - because there are numerous problems in your code, some related to what you've asked about, and some not. However, my advice here will get you started.
Your question is really vague; it looks like you need to spend some time to pin down your program structure before you could ask for help here.
However, since we were all new once, here's a suggestion for a suitable structure:
(I'm leaving out the file handling bits because they're irrelevant to the essential structure)
//Populate your array of banned words
std::string bannedWords[8];
int i;
for (int i = 0; i < 8; ++i)
{
file >> bannedWords[i];
}
//Load the entire file content into memory
std::ifstream in("text1.txt");
std::string fileContents((std::istreambuf_iterator<char>(in)), std::istreambuf_iterator<char>());
So now the entire file content is in the string "fileContents", and the 8 banned words are in "bannedWords". I suggest this approach because otherwise you're opening, reading, and closing the file for every word. Hardly a good design.
Now you've got to check each word against the file content. There's some more sophisticated ways to do this, but your simplest option is a loop.
//Loop through each banned word, and check if it's in the file
for (int i = 0; i < 8; i++)
{
if (fileContents.find(bannedwords[i]) != std::string::npos)
{
//Do whatever
}
}
Obviously you'll need to do the find a little differently if you want to count the number of occurrences, but that's another question.

File Input in C++

I've been searching the internet for a while, but all I can find for file input in C++ is when you know the filename.
I'm trying to write a program to perform an addition of 2 numbers that are greater than 0 from a file, but without using scanf or cin. I want to load the file into memory, but all of the code I can find in regards to this situation requires knowledge of the filename. The file is formatted with 2 integers on a single line, separated by a space, and there are multiple lines of integers. The program will output the sum of the two numbers. I can easily do this with scanf, but if I were given a massive file, I would want to load it into memory (save mapping for later).
Loading the file into memory is giving me trouble, because I do not know the filename, nor how to find out, unless the user inputs the name of the file (not going to happen). I want the program to be executed like so, but using the most raw, and basic forms of C++ IO:
./myprog < boatloadofnumbers
How would I start my program to take the whole "boatloadofnumbers" as a file, so I can use more basic functions like read()? (also, what is the above method called? passing input?)
int main(){
int a,b;
while (scanf("%i,%i",&a,&b)>-1){
printf("%i\n",(a+b));
} //endwhile
return 0;
} //endmain
When the program is called as you state, then the content of boatloadofnumbers can be read from std::cin.
This method is called input redirection and is done by the shell, not your program.
Wiht input redirection the shell usually buffers the content of the file. That's a quite fast way to stream a file a single time through a computation.
It's not entirely clear how you're going to read a file when you don't know the filename. Presumably you don't know the filename at compile-time. That's okay, you can get this from the command-line at runtime, like this:
./myprog boatloadofnumbers
Then your filename is in argv[1] and you can access it using a std::ifstream.
If you're being given the input directly on stdin via redirection (such as ./myprog < boatloadofnumbers) you don't need a filename at all, you can just use std::cin.
The following main() will deal with both of these situations:
int main(int argc, char* argv[])
{
if (argc == 2)
{
std::cerr << "Reading from file" << argv[1] << std::endl;
std::ifstream ifs(argv[1]);
if (ifs)
{
sum_lines(ifs);
}
else
{
std::cerr << "Could not read from " << argv[1] << std::endl;
}
}
else
{
std::cerr << "Reading from stdin" << std::endl;
sum_lines(std::cin);
}
}
A sample sum_lines() may look a bit like this:
void sum_lines(std::istream& is)
{
int first = 0, second = 0;
std::string line = "";
while (std::getline(is, line))
{
std::istringstream iss(line);
if (is >> first >> second)
{
std::cout << first << " + " << second << " = " << first + second << std::endl;
}
else
{
std::cerr << "Could not parse [" << line << "]" << std::endl;
}
}
}
This doesn't care from where the input comes, so you can easily inject a std::istringstream for unit-testing. Also, this doesn't read the whole file into memory, just one line at a time, so it should deal with averybigboatloadofnumbers.
With shell redirection, your program can read from the standard input, which may be desirable. However, it may also be desirable to read from a file. It's easy to support both:
cat data > ./prog
./prog < data
./prog -f data
The first two are similar, and the contents of the file data are available from the program's standard input; the third line simply passes a command-line argument. Here's how we support this:
#include <cstdio>
#include <cstring>
void process_input(std::FILE * fp)
{
char buf[4];
std::fread(buf, 4, 1, fp);
// ...
}
int main(int argc, char * argv[])
{
std::FILE * fp = stdin; // already open!
if (argc >= 3 && 0 == std::strcmp(argv[1]. "-f"))
{
fp = std::fopen(argv[2], "rb");
if (!fp)
{
std::fprintf(stderr, "Could not open file %s.\n", argv[2]);
return 1;
}
}
process_input(fp);
if (fp != stdin) { std::fclose(fp); }
}
Equivalently, you can achieve something similar with iostreams, though it's a bit more roundabout to have a nice, universal reference:
#include <fstream>
int main()
{
std::ifstream ifp;
if ( /* as before */ )
{
ifp.open(argv[2], std::ios::binary);
if (!ifp) { /* error and die */ }
}
std::ifstream & infile = ifp ? ifp : std::cin;
process_input(infile);
}

C++ - Convert FILE* to CHAR*

I found a C++ source file which calculates expressions from a command line argument (argv[1]), however I now want to change it to read a file.
double Utvardering(char* s) {
srcPos = s;
searchToken();
return PlusMinus();
}
int main(int argc, char* argv[]) {
if (argc > 1) {
FILE* fFile = fopen(argv[1], "r");
double Value = Utvardering(fopen(argv[1], "r"));
cout << Value << endl;
}else{
cout << "Usage: " << argv[0] << " FILE" << endl;
}
cin.get();
return 0;
}
However the Utvardering function requires a char* parameter. How can I convert the data read from a file, fopen to a char*?
The function fopen just opens a file. To get a string from there, you need to read the file. There are different ways to to this. If you know the max size of your string in advance, this would do:
const int MAX_SIZE = 1024;
char buf[MAX_SIZE];
if (!fgets(buf, MAX_SIZE, fFile) {
cerr << "Read error";
exit(1);
}
double Value = Utvardering(buf);
Note: this method is typical for C, not for C++. If you want more idiomatic C++ code, you can use something like this (instead of FILE and fopen):
ifstream in;
in.open(argv[1]);
if (!in) { /* report an error */ }
string str;
in >> str;
Use the fread() function to read data from the FILE* into a buffer. Send that buffer into Utvardering().
I have no idea what "Utvardering" expects, or how it's using the information.
There are two possibilities -
1) Utvardering may be defined using char*, but expecting a FILE* (in effect, treating char* like void*). I've seen this before, even though it's pretty awful practice. In that case, just cast fFile to char* and pass it in.
2) Utvardering may be expecting a null terminated string (char*) as input. If you're using fopen like this, you can use fread to read the file contents into a buffer (char[]), and pass it to your function that takes a char*.
It looks like you need to write code to read the file into a character array and pass that to Utvardering.
Just passing the return value of fopen will cause the address of the opaque data structure pointed to by that pointer to be passed to Utvardering. Utvardering will happily treat those bytes as character data when they are not. Not good.
Good example of reading data from a file here:
http://www.cplusplus.com/reference/clibrary/cstdio/fread/
then pass the buffer to your function