C++ Can't Print Values from Array of Strings - c++

I am having trouble with an assignment for my freshman Computer Science class.
I am trying to have PrintAllConcepts print each item of an array, once per line.
For some reason all I get is the last line printed from LIST.txt and a bunch of extra empty lines that usually end up nearly crashing the program. There appears to be no syntactical errors, so I'm afraid I am not reading the concepts into the array correctly. This is where I would like assistance.
Below is my code.
I also apologize if this seems like a noob question, as I am a beginner in C++.
Edit: Also, explaining why the Number parameter is so funky, my assignment seems to be requiring me to do it that way. That is also why PrintAllConcepts and ReadConcepts returns void.
#include <string>
#include <sstream>
#include <iostream>
#include <fstream>
#include <iomanip>
void ReadConcepts(std::string Concepts[100], int &Number) {
std::ifstream fin;
fin.open("LIST.txt");
if (!fin.is_open()) {
std::cerr << "error: file open failed.\n";
}
std::string theConcepts[100];
std::string line;
int i;
for (i = 0; i <= 99; i++) {
while (std::getline(fin, line)) {
theConcepts[i] = line;
Number++;
}
}
}
void PrintAllConcepts(std::string Concepts[100], int Number) {
int i;
std::string line;
for (i = 0; i < Number - 1; i++) {
line = Concepts[i];
std::cout << line << std::endl;
}
std::cout << i;
}
int main() {
// Initiate variables
std::string Concepts[100];
int Number = 100;
// Read concepts
ReadConcepts(Concepts, Number);
// Open file for void function PrintAllConcepts
std::ifstream fin;
fin.open("LIST.txt");
if (!fin.is_open()) {
std::cerr << "error: file open failed.\n";
}
int i;
std::string line;
for (i = 0; i < 99; i++) {
while (std::getline(fin, line)) {
Concepts[i] = line;
}
}
PrintAllConcepts(Concepts, Number);
}

As you commented, the errors are in the ReadConcepts function.
To begin with you should not increment Number in the loop, as it's already the number of elements in the array. Because you increment Number you will pass the value 200 to PrintAllConcepts which will make it go out of bounds of the array.
Secondly you put all strings into the local array theConcepts instead of the array Concepts passed to the function. This means none of the strings in Concepts will be set, giving you the "empty" output. Remove the theConcepts array and use Concepts instead.
Thirdly you should have either the for loop, or the while loop, but not both. Since you have both the first iteration of the for loop will read all lines from the file, putting all of it into theConcepts[0], and leave the rest of the array with empty strings. I recommend a combination of both loops, as in:
for (int i = 0; i < Number && std::getline(fin, line); ++i)
{
Concepts[i] = line;
}
There are also some other "problem" that aren't serious and won't cause any errors. One of them is passing the Number argument by reference. Since Number should not be modified you should pass it by value.

As a perfunctory node to your question, you may want to insert a condition for reading the file in its entirety, i.e., while (fin.good()), etc.
That said, the above hints and tips are second to none. Debugging programs can teach you a lot, and are as good a learning tool as writing the code yourself. I should know; I'm new at this too. Good luck.
p.s.: Don't forget the good practice of closing your file once finished with it.

Related

Passing a file via command arguement into an array

So I'm trying to pass and command line argument into an array in my int main
like this $< .\program nums.txt 8 but I'm getting errors and hit a dead-end with my knowledge on C++ code. (I'm relatively a new coder). Any help is greatly appreciated.
int main(int argc,char *argv[])
{
string arg2=" ";
arg2 = argv[2];
int size;
size=stod(arg2);
string arr[size];
string file = argv[1];
ifstream infile;
if (getline infile.open(file))
{
int arr[size],val;
for(int i=0;i<size;i++)
{
getline(file, arr[i]);
}
}
int choice = 5,value,position,target ;
Her is a list of the errors you have (excluding a missing curly brace at the end, missing includes [you probably just didn't post them?] and missing std:: [the use of using namespace std; is considered bad practice ]) and mostly how to fix them:
std::stod parses and returns a dobule, but you assign the result to an int.
size = std::stod(arg2);
you probably meant to use stoi:
size = std::stoi(arg2);
VLAs (Variable length arrays) like
std::string arr[size];
are not part of the C++ standard. Instead use
std::vector<std::string> arr(size);
When opening the file stream, your inention is right, but the syntax is wrong
std::ifstream infile;
if (std::getline infile.open(file))
should be
std::ifstream infile(file);
if (infile)
Inside the if you have
int arr[size],val;
two unused variables, another VLA and most importantly int arr[size] will shadow string arr[size].
That's the reason for the next errors:
std::getline(file, arr[i]);
The first parameter file is a std::string, this should obviosly be infile. Because of the variable shadowing the second parameter arr[i] will refer to int arr[i]. Rename one of them or just remove the two unused variables (see last point).
Always check if reading was successfull. If you want to read a maximum of size lines use
for(int i = 0; i < size && std::getline(infile, arr[i]); i++);
It will terminate the loop, if getline fails for some reason, for example, when the file has less than size lines.
Lastly, you can think about some validation. For example check if there actually are two command line parameters given and add a try-catch-block around the stoi.
And just to mention it: Learning C++ by guessing is no fun. On https://en.cppreference.com/w/ you can find extensive information and many examples for the functions and classes you want to use.
There are lot of typos in your question. Still I think this code may help you:
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
int main(int argc, char *argv[]) {
int size = atoi(argv[2]);
std::vector<std::string> arr(size);
std::ifstream infile(argv[1]);
if (not infile) {
std::cerr << "File not found!" << std::endl;
return -1;
}
for (int i = 0; i < size; i++)
if (infile)
std::getline(infile, arr[i]);
else {
std::cerr << "Not enough lines in the file!" << std::endl;
return -2;
}
// do rest of your things here ...
return 0;
}

(C++) Learning vectors - problems with coding/input stream termination/comparing vectors

I'm beginner learning my first programming language - C++ - from Bjarne Stroustrup's book "Programming Principles and Practice Using C++". Chapter 4 talks about vectors. Everything explained before I would get easily and code would always work properly, until now.
The code I write doesn't function at all. The following code was made for little exercise, where the input is read in and prints the words out, bleeping out the disliked ones.
#include "std_lib_facilities.h"
int main() {
vector<string>text;
string disliked = "cat";
for (string word; cin >> word;) {
text.push_back(word);
}
for (int a = 0; a < text.size(); ++a) {
if (text[a] != disliked) {
cout << text[a] << endl;
}
else {
cout << "BLEEP\n";
}
}
keep_window_open();
}
My first idea was to create another vector, vector<string>disliked ={"cat", ...} , for disliked words, but then if (text[x] != disliked) didn't seem like a way of comparing elements from each vector (at least it was warning me about operator and operands mismatch). Is there a way for that?
But back to the code: with some modifications and without any disliked word in the input, the program would run sometimes. Still I can't manage to meet the main purpose. And perhaps, the actual mistake is in the input termination. Ctrl+Z doesn't work for me but just inputs a character. And somehow Ctrl+C happened to work properly (if there were no disliked words).
So here come the actual questions:
Is the code correct? (since I can't check it myself while I might have been terminating the input improperly entire time)
How can I terminate input any other way, considering that Ctrl+Z only adds a character to the input?
Is there a way of making this program work by comparing the "input" vector with the "disliked" vector?
Is the code correct? (since I can't check it myself while I might have been terminating the input improperly entire time)
Seems to work for me.
How can I terminate input any other way, considering that Ctrl+Z only adds a character to the input?
I use Ctrl-D to mark end of line.
Is there a way of making this program work by comparing the "input" vector with the "disliked" vector?
Usually when you compare types (with == and !=) they have the same type (or the compiler can convert one type to the same type as the other type (but that's for the pedantic here; for beginners its best to think of comparison comparing objects of the same type)).
vector<string> text;
string disliked = "cat";
// STUFF
if (text[x] != disliked) // disliked is a string
// text[x] is a string (because we are accessing the `x` element.
If we change disliked to a vector:
vector<string> text;
vector<string> disliked = "cat";
// STUFF
if (text[x] != disliked) // disliked is a vector<string>
// text[x] is a string
Since the types do not match they are hard to compare. So you need to loop over all the elements in disliked to see if you can find the word.
bool found = false;
for(std::size_t loop = 0; loop < disliked.size(); ++loop) {
if (text[x] == disliked[loop) { // Types are the same here.
found = true;
break;
}
}
if (!found) {
There are techniques to make the above compact. If you are just started this may be a bit early for this, but for completness I will add it here:
bool found = std::find(std::begin(disliked), std::end(disliked), text[x]) != std::end(disliked);
if (!found) {
I guess you have two options here:
1. Get the input from a text file.
In this case you have to place your data in a text file, in your project directory. For example, in the code posted below, "text.txt" is where the input should be stored (your words).
Minor remarks:
I'm not sure what "std_lib_facilities.h" contains so I added some of the standard headers to make the code compile for me.
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
int main()
{
std::vector<std::string> texts;
std::string dislikedWord = "cat";
std::ifstream fin("text.txt");
for (std::string word; fin >> word;)
texts.push_back(word);
unsigned textsCount = texts.size();
for (unsigned textIndex = 0; textIndex < textsCount; ++textIndex)
if (texts[textIndex] != dislikedWord)
std::cout << texts[textIndex] << '\n';
else
std::cout << "BLEEP\n";
return 0;
}
2. Keep reading words until a condition is finally met.
In this case (if you don't want to read from a text file) you should insert a condition that makes the program stop taking input, so you can preceed further. A condition can be something like maximum number of words that can be read or some 'special' word. In the example below, I chose to end reading at ten words.
Minor remarks: Maybe the chapter from where you got the exercise tells you what condition to insert. I doubt that you have to use CTRL+C or any other key combinations to solve the exercise.
#include <iostream>
#include <vector>
#include <string>
int main()
{
const unsigned totalWords = 10;
std::vector<std::string> texts;
std::string dislikedWord = "cat";
for (std::string word; std::cin >> word;) {
texts.push_back(word);
if (texts.size() == totalWords) // could've put it in the for condition
break; // terminates the for-loop
}
unsigned textsCount = texts.size();
for (unsigned textIndex = 0; textIndex < textsCount; ++textIndex)
if (texts[textIndex] != dislikedWord)
std::cout << texts[textIndex] << '\n';
else
std::cout << "BLEEP\n";
return 0;
}

Error Vector subscript out of range

I believe my error is within my writeline function, when I attempt to write the contents of the vector to the new file using a while loop.
//Read from txt file, write to new text file
#include<iostream>
#include<fstream>
#include<vector>
#include<string>
#include<algorithm>
using namespace std;
void readline();
void sortline(vector<string>& sortthis);
void writeline(vector<string>& list);
int main()
{
readline();
system("pause");
return 0;
};
void readline()
{
string line;
vector<string> lines;
ifstream myfile("classes.txt");
if (myfile.is_open())
{
while (myfile.good())
{
getline(myfile, line);
lines.push_back(line);
};
myfile.close();
}
cout << "readline() has run" << endl;
sortline(lines);
writeline(lines);
};
void sortline(vector<string>& sortthis)
{
sort(sortthis.begin(), sortthis.end());
};
void writeline(vector<string>& list)
{
ofstream myfile2("new.txt");
if (myfile2.is_open())
{
int i = 0;
while(i !=list.size()-1)
{
myfile2 << list[i] << endl;
i++;
};
myfile2.close();
};
cout << "writeline() has run" << endl;
};
this is a project from a semester ago that i'm revisiting. I wrote the program on my mac, now i'm trying to run it on my windows comp with visual studio. I'll describe what I'm attempting to do, I apologize if my choice of words is terrible in advance. anywhere I put a * is where I'm not sure what is happening, but I'll take a stab at it.. any explanations of my code is very appreciated!!
my readline() function does the following: creates a string called line, creates a vector of string type called lines, **input the file classes.txt and establish myfile as it's object, then open myfile for writing, **use the while loop to write the lines from the txt into the myfile object, then close myfile, print out a statement to let the user know readline() has run, then **pass the vector called lines into the sortline function, and then pass lines into the writeline function.
** sortline takes in a vector of strings as its arg, and assigns it the object sortthis?? then I'm not sure what happens, but it looks like i applied a sorting algorithm, anybody have any thoughts?
and finally we get to my writeline function which takes in a vector of strings as its arg and assigns them the name lines (is that correct?) i then want to establish a new out file stream to a new textfile called "new.txt" with an object name myfile2, if myfile2 is open, then i want to write all the lines from the vector of strings(which contain the contents of the original text file) into myfile2, which will write them to the new.txt file, then close myfile2, print a message stating the function has run, and that is all.
The way you loop through list in writeline is not safe. You should use a for loop or a while loop with iterator. As it is, your code probably doesn't do what you intend it to do even if there are several elements in list. Consider the following:
std::vector<std::string> vLines;
vLines.push_back("Hello");
vLines.push_back("File");
vLines.push_back("World");
std::ofstream of("file.txt");
int i = 0;
while (i != vLines.size() - 1)
{
of << vLines[i] << std::endl;
++i;
}
Even with several elements in vLines, this will only actually print output 2 elements into of.
i will be 0 which is not 2, so "Hello" will be output to of.
i will be 1 which is not 2, so "File" will be output to of.
i is now 2, which is equal to 2, so "World" will not be output to of.
That's with elements. If there are 0 elements in vLines, you will be indexing out of bounds (which I suspect is what you are doing, hence your error):
std::vector<std::string> vLines;
std::ofstream of("file.txt");
int i = 0;
while (i != vLines.size() - 1)
{
of << vLines[i] << std::endl;
++i;
}
i will be 0, which is not equal to -1, so the code will run and try to output vLines[0] to of, but there is no vLines[0]! I suspect this is what you are experiencing.
This will go away if you use a proper range-based loop instead (credit to #WhozCraig for C++11 solution):
for (auto const& s : vLines)
of << s;
Or if you don't have C++11 you can still mimic a proper range-based loop with the following:
for (int i = 0; i < vLines.size(); ++i)
of << vLines[i] << std::endl;
Or an iterator:
for (auto it = vLines.begin(); it != vLines.end(); ++it)
of << *it << std::endl;
You will now output all elements in your std::vector to your std::ofstream as well as properly handle situations where there are no elements.

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.

Why is the next line not executing C++

I have attached my full source code of my program that can open a .txt file. It doesn't execute after the cout << length. I am trying to store the .txt file information in memory by using an array.
#include <iostream>
#include <string.h>
#include <fstream>
using namespace std;
char filename[128];
char file[10][250];
int count;
int length;
string line;
int main ()
{
int count = 0;
int length = 0;
cout << "Filename: ";
cin.clear();
cin.getline(filename, sizeof(filename));
string new_inputfile(filename);
ifstream inputfiles (new_inputfile.c_str());
if(!inputfiles.is_open())
{
cout << "File could not be opened. \n ";
}
else
{
for (int i=0; getline(inputfiles,line); i++)
{
length++;
}
cout << length;
// char file[length][250]; <- How can I create the array based on the length variable?
// CODE DOES NOT EXECUTE AFTER THIS.
while(!inputfiles.eof() && (count<10))
{
inputfiles.getline(file[count],250);
count++;
}
for(int i=0; i < count; i++)
{
cout << file[i] << endl;
}
}
inputfiles.close();
return 0;
}
Also, since file[] is char, say for example file[1] contained the char Name=Mike, how do I strip off everything before the =. I want just Mike. I know with string, I can use substr() method, but I don't know for char.
This is horribly wasteful way to count number of lines in a file.
for (int i=0; getline(inputfiles,line); i++) // i is also completely useless here
{
length++;
}
You're reading the whole file only to throw everything away and start again! And after this loop is done, inputfiles.eof() will be true and you'll never enter neither the next while loop nor the last for loop (because i == count). Execution skips directly to inputfiles.close() and then you return from main.
I suggest you work on the line string as you go:
for ( ; getline(inputfiles, line); )
{
// do stuff with line and ditch the global char arrays
}
If you want store the lines for later, well, just save them :) The easiest thing to do is to use a vector:
std::vector<std::string> all_them_lines;
while (getline(file, line) all_them_lines.emplace_back(line);
There, the entire file is now saved in all_them_lines, line by line. You can access them just like you would in an array, like all_them_lines[0]. You also don't need to know the number of lines beforehand - vectors expand automatically when you add stuff to them.
Now to parse a line and extract formatted input from it, check out what stringstream class has to offer.
You asked:
// char file[length][250]; <- How can I create the array based on the length variable?
Declare file as:
char (*file)[250] = NULL;
and then,
file = new char[length][250];
Make sure you call delete [] file before the end of the function.
You said:
// CODE DOES NOT EXECUTE AFTER THIS.
You can rewind the stream and start reading from it again.
inputfiles.seekg(0);
count = 0;
while(!inputfiles.eof())
{
inputfiles.getline(file[count],250);
count++;
}