So Basically I am trying to "populate" a file with 10^3 completely random numbers, so I could add them later to a Binary search tree.
Here is the populate function I worked on so far:
void populateFile(BinarySearchTree b) {
int random_integer;
srand( time( NULL ) );
std::ofstream myfile;
string line;
myfile.open ("output.txt");
myfile << "Writing this to a file: ";
for(int index=0; index<1000; index++)
{
random_integer = (rand()%1000)+1;
cout << random_integer << endl;
myfile << random_integer;
}
myfile.close();
int value;
ifstream file ("output.txt");
if (file.is_open())
{
while ( getline (file,line) )
{
value = std::stoi(line);
b.insert(value);
}
myfile.close();
}
else cout << "Unable to open file";
}
But I cannot seem to write to a file, I can just see the numbers on the console then the program crashes.
My second concern is as follows:
I want to add those same numbers to a binary search tree. I already have a class and an dd function, but I have no idea how to continue. Then I want to be able to delete them from the BST completely at random.
I already have a remove function written. How is this possible?
Any ideas will be greatly appreciated.
P.S: I am fairly new to C++, I am sorry if my questions sounds silly for you.
I think the solution to your problem lies in the comment by #Praetorian:
You probably want myfile << random_integer << '\n';. Otherwise stoi will throw out_of_range, which is probably the cause of the crash.
I have a few generic suggestions regarding your function.
Separate your function into two
-- one for writing to the file
-- one for reading from the file and populating a BST.
Don't use hard coded names of files or global variables in the functions. Make them arguments to the function.
Always check for the status of IO operations. Deal with failures.
Seed the random number generator in main or a driver function. If you call the function that generates random numbers multiple times, you won't need to seed the random generator again.
void populateFile(int count,
std::string const& file)
{
std::ofstream myfile(file);
if (!myfile )
{
// Deal with error.
return;
}
for(int index=0; index<count; index++)
{
random_integer = (rand()%1000)+1;
myfile << random_integer << "\n";
}
}
void readFileAndBuildBST(std::string const& file,
BinarySearchTree& b)
{
std::ifstream myfile(file);
if (!myfile )
{
// Deal with error.
return;
}
int number;
while ( myfile >> number )
{
b.insert(number);
}
}
void driver()
{
// Seed the random number generator.
srand( time( NULL ) );
// Populate the file
std::string file("output.txt");
populateFile(1000, file);
// Read the data from the file and flesh out the BST.
BinarySearchTree b;
readFileAndBuildBST(file, b);
}
With the functions divided into two, you can test one function at a time. If there is a problem in one function, you can debug the problem and fix it before working on the other function.
Change
cout << random_integer << endl;
myfile << random_integer;
to:
myfile << random_integer << endl;
On a sidenote, if you need data only during the lifetime of the program, you might want to use a buffer or even add the numbers directly into your binary search tree.
Related
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.
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.
I'm pretty sure that this is a common question, but I can't find an example similar to mine, so..
I have a text file called input.txt that has: 0.0001234 1.0005434 0.0005678 1.0023423 0.00063452 1.0001546 0.00074321 1.00017654 in it.
Now I want to write a program to read that into an array, and then quickly check that it worked. So far, I've got:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main ()
{
double PA[8];
int n;
ifstream myfile ("input.txt");
if (myfile.is_open())
{
while (! myfile.eof() )
{
getline (myfile,line);
cout << PA[line]<< endl;
}
myfile.close();
}
else cout << "Unable to open file";
for (n=0; n<8; n++) // to print the array, to check my work
{
cout << " {" << PA[n] << "} ";
}
system("PAUSE");
return 0;
}
My problem so far is that I keep getting the error: line was not declared. And I want to use the array later with floats to calculate new data. I think I'm doing it wrong for that.. Any help? Thanks!
declare line variable
int n, line = 0;
std::string value;
proper load data:
getline (myfile,value);
PA[line] = atof(value.c_str());
cout << PA[line]<< endl;
line++;
the variable line here
cout << PA[line]<< endl;
is not declared. and if you declare it, you also have to give it a value, otherwise it's undefined and the PA[line] is undefined, in other words: will crash.
the entire while block seems suspicious:
while (! myfile.eof() )
{
getline (myfile,line);
cout << PA[line]<< endl;
}
are you sure about the getline call?
I know a getline with this signature:
ssize_t getline(char **lineptr, size_t *n, FILE *stream);
and that does not even match the number of arguments in your version.
if your input file has more than 8 lines on input, than the while loop will have that many interations - and your array has only space for 8 elements.
You need to declare the variable you called 'line' as follows:
int i=0;
while (! myfile.eof() && i<8)
{
std::string line; // this was the missing statement
getline (myfile,line);
double value = atof(line.c_str()); // convert line form char* to double
PA[i++] = value;
cout << value << endl;
}
Note that you need to convert line as double and use increment variable 'i' (for example, as I did. Make sure not overflowing PA capacity by checking i agains the size (currently 8, which should not hard coded, btw).
Also note that you shouldn't print the result if file access failed.
This seems like such an easy task, but everything I've tried hasn't worked so far.
I have a file foo.txt:
3
3 4 2
Now I want to read this file, read the first line and instantiate an int array with the size of the number it read on the first line.
Then it should populate that array with the elements in the second line, which has the exact same amount of elements and noted in line one.
If we're going to give you example code, might as well show you the best way to do it:
std::ifstream datafile("foo.txt");
if (!datafile) {
std::cerr << "Could not open \'foo.txt\', make sure it is in the correct directory." << std::endl;
exit(-1);
}
int num_entries;
// this tests whether the number was gotten successfully
if (!(datafile >> num_entries)) {
std::cerr << "The first item in the file must be the number of entries." << std::endl;
exit(-1);
}
// here we range check the input... never trust that information from the user is reasonable!
if (num_entries < 0) {
std::cerr << "Number of entries cannot be negative." << std::endl;
exit(-2);
}
// here we allocate an array of the requested size.
// vector will take care of freeing the memory when we're done with it (the vector goes out of scope)
std::vector<int> ints(num_entries);
for( int i = 0; i < num_entries; ++i )
// again, we'll check if there was any problem reading the numbers
if (!(datafile >> ints[i])) {
std::cerr << "Error reading entry #" << i << std::endl;
exit(-3);
}
}
Demo (with small changes because I can't provide a file with the right name on ideone): http://ideone.com/0vzPPN
You need to use ifstream object just like you use cin
ifstream fin("foo.txt"); //open the file
if(!fin.fail()){
int count;
fin>>count; //read the count
int *Arr = new int[count];
for(int i=0;i<count;i++){ //read numbers
fin>>Arr[i];
}
//... do what you need ...
//... and finally ...
delete [] Arr;
}
If you open a file using input filestream you can simply do that:
std::ifstream file_txt("file.txt");
int number_count = 0;
file_txt >> number_count; // read '3' from first line
for (int number, i = 0; i < number_count; ++i) {
file_txt >> number; // read other numbers
// process number
}
Filestreams just like other standard streams (std::cin, std::cout) can apply formatting depending on type supplied to operator>> (in this case an int).
This apply to both input and output.
Alternatively, you could avoid the entire need to read in the size beforehand by simply loading it into a std::vector:
std::ifstream fin("myfile.txt");
std::vector<int> vec{std::istream_iterator<int>(fin), std::istream_iterator<int>()};
fin.close();
or, if you cannot use C++11 syntax:
std::ifstream fin("myfile.txt");
std::vector<int> vec;
std::copy(std::istream_iterator<int>(fin), std::istream_iterator<int>(), std::back_inserter(vec));
fin.close();
I need to write just a function that counts the number of integers in an already opened and good text file.
a. Assume there is a text file with a large number of integers divided by spaces
b. Write a function called analyzeFile that accepts a previously opened ifstream
file object as a parameter, and counts the number of integers in the file.
c. It does not need to do anything with the integers, but it must count exactly the
correct number of integers in the file and return that number to the calling
function.
d. It also does not need to manipulate the file operations themselves, so it does not
need to close the file or conduct any other actions other than counting the integers
and returning the number of them.
Thank you for any help on my problem!
Edit:
Here is what I have as a function do far, is it right, I don't know:
int analizeFile (ifstream &inf, const string &fileName) {
int count = 1;
int num;
fin.open(fileName.c_str() );
fin >> num;
while (fin.good() ) {
fin>> num;
count ++;
}
return count;
}
Comments:
int analizeFile (ifstream &inf, const string &fileName) {
Since the count is always a non-negative quantity, I'd prefer to use size_t rather than int. Nit: You may want to change the name of the function to analyzeFile.
int count = 1;
Problem starts here: If your file does not have any integer then you return a wrong result.
int num;
fin.open(fileName.c_str() );
No need to call open. This would typically be called by the ifstream ctor.
fin >> num;
while (fin.good() ) {
Again, this is not required. You can extract from the stream and test in the while condition -- something which is more frequently used.
fin>> num;
count ++;
}
return count;
}
You can use a functional approach too
// it was previously opened, so you don't need a filename.
int analyzeFile (istream &inf) {
std::istream_iterator<int> b(inf), e;
return std::distance(b, e);
}
If the iterator cannot read an integer, it will set the fail state on the stream and will compare equal to the end iterator. distance then returns the number of iteration steps it took to reach the end iterator.
Many many years later, you could come up with a more modern solution.
You can simply use associative containers like std__map or std::unordered:map for counting. This is more ore less the standard approach.
Then there are many many new and powerful functions availbale.
Using those, you could come up with some like:
#include <iostream>
#include <fstream>
#include <string>
#include <iterator>
#include <map>
#include <cctype>
using Counter = std::map<char, std::size_t>;
const std::string fileName{"test.txt"};
int main() {
// Open file and check, if it could be opened
if (std::ifstream ifs{fileName}; ifs) {
// Read all data
std::string text{std::istream_iterator<char>(ifs),{}};
// Define the counters
Counter upperCaseLettterCount{},lowerCaseLettterCount{};
// Iterate over all characters in the string and count
for (const char c : text) {
if (std::isupper(c)) upperCaseLettterCount[c]++;
if (std::islower(c)) lowerCaseLettterCount[c]++;
}
// Show result
std::cout << "\nUppercase count:\n\n";
for (const auto& [letter,count] : upperCaseLettterCount) std::cout << letter << " -> " << count << '\n';
std::cout << "\nLowercase count:\n\n";
for (const auto& [letter,count] : lowerCaseLettterCount) std::cout << letter << " -> " << count << '\n';
}
else
// Error, file could not be opened
std::cerr << "\n\n*** Error: Text file '" << fileName << "' could not be opened\n\n";
}