HW Help: get char instead of get line C++ - c++

I wrote the code below that successfully gets a random line from a file; however, I need to be able to modify one of the lines, so I need to be able to get the line character by character.
How can I change my code to do this?

Use std::istream::get instead of std::getline. Just read your string character by character until you reach \n, EOF or other errors. I also recommend you read the full std::istream reference.
Good luck with your homework!
UPDATE:
OK, I don't think an example will hurt. Here is how I'd do it if I were you:
#include <string>
#include <iostream>
#include <fstream>
#include <cstdlib>
using namespace std;
static std::string
answer (const string & question)
{
std::string answer;
const string filename = "answerfile.txt";
ifstream file (filename.c_str ());
if (!file)
{
cerr << "Can't open '" << filename << "' file.\n";
exit (1);
}
for (int i = 0, r = rand () % 5; i <= r; ++i)
{
answer.clear ();
char c;
while (file.get (c).good () && c != '\n')
{
if (c == 'i') c = 'I'; // Replace character? :)
answer.append (1, c);
}
}
return answer;
}
int
main ()
{
srand (time (NULL));
string question;
cout << "Please enter a question: " << flush;
cin >> question;
cout << answer (question) << endl;
}
... the only thing is that I have no idea why do you need to read string char by char in order to modify it. You can modify std::string object, which is even easier. Let's say you want to replace "I think" with "what if"? You might be better off reading more about
std::string and using find, erase, replace etc.
UPDATE 2:
What happens with your latest code is simply this - you open a file, then you get its content character by character until you reach newline (\n). So in either case you will end up reading the first line and then your do-while loop will terminate. If you look into my example, I did while loop that reads line until \n inside a for loop. So that is basically what you should do - repeat your do-while loop for as many times as many lines you want/can get from that file. For example, something like this will read you two lines:
for (int i = 1; i <= 2; ++i)
{
do
{
answerfile.get (answer);
cout << answer << " (from line " << i << ")\n";
}
while (answer != '\n');
}

Related

While loop will only terminate if I use CTRL + C on the terminal

The prompt of the question is:
Write a program that prompts the user to input the name of a text file and then outputs the number of words in the file. You can consider a “word” to be any text that is surrounded by whitespace (for example, a space, carriage return, newline) or borders the beginning or end of the file.
I have successfully gotten the program to count how many words are in a file; no issues there.
#include <fstream>
#include <iostream>
#include <cstdlib>
#include <string>
int main()
{
char file_name[16];
std::ifstream in_stream;
int count = 0;
char ch;
bool lastWasWhite = true;
std::string next;
// Ask the user for the file name
std::cout << "What is the name of the file? ";
std::cin >> file_name;
in_stream.open(file_name);
// See if we can open the file
if (!in_stream.is_open()) {
std::cout << "Something went wrong when opening your file.";
exit(1);
}
// Read the file, one character at a time
while (in_stream >> next) {
do {
std::cin.get(ch);
}
while (ch != ' ' && ch != '\n' && ch != '\t');
++count;
}
in_stream.close();
std::cout << "The file " << file_name << " contains " << count << " words." << std::endl;
return 0;
}
The only problem is that the only way for the program, or I think the "while loop" to finish, is for me to hit CTRL + C on the terminal so it force stops. Then I get the result I want.
This is my first post, so please let me know if there is any other information you would like to see.
Your outer loop is reading words from the file and counting them just fine (operator>> handles the whitespace for you).
However, your outer loop is also running an inner loop that is reading user input from stdin (ie, the terminal). That is where your real problem is. You are waiting on user input where you should not be doing so. So, simply get rid of the inner loop altogether:
while (in_stream >> next) {
++count;
}
That is all you need.

Input Numbers from txt file to array

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.

While Loop contines forever to get end of input string

How do I run the while loop until the end of line or null character reached.
Here is my code
#include<iostream>
using namespace std;
main()
{
char input[20];
cout<<"Enter a line: ";
cin>>input;
while(input!='\0')
{
cout<<"This is a text";
}
system("pause");
}
If you want to read until either a newline or a NUL, read one character at a time inside the loop.
#include<iostream>
int main()
{
char input;
std::cout << "Enter a line: " << std::flush;
while(std::cin >> input && input != '\n' && input != 0) {
std::cout << "This is a test\n";
}
}
Notes:
main requires a return type
Never, ever, say "using namespace std;"
Don't forget to flush if you want cout to appear immediately.
Notice the compound test in the while condition:
First, did the read succeed?
Next, is it not '\n' (one of your conditions).
Next, is it not NUL (the other of your conditions).
The body of the loop will be executed once per input character -- is that what you wanted?
But, consider if you have correctly specified your requirement. It is an unusual requirement -- why would there be a NUL in a text file, and why would you want to process each character individually?
In idiomatic C++, you can read the input file in a line at a time using std::getline:
std::string myString;
while(std::getline(std::cin, myString)) {
// process myString
}
If you just want to read in a single line:
std::string myString;
if(std::getline(std::cin, myString)) {
// process myString
}
Finally, if you want to read a line, and ignore its contents:
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
try something like:
i = 0;
while ((input[i] != '\0') && i < 20)
{
cout<<"This is a text";
i++;
}
Like this:
std::string line;
if (std::getline(std::cin, line))
{
std::cout << "Thank you, you said, \"" << line << "\".\n";
}
else
{
// error, e.g. EOF
}
If you want to read multiple lines, use a while loop instead:
while (std::getline(std::cin, line))
{
std::cout << "Thank you, you said, \"" << line << "\".\n";
}
The issue is that you're reading an entire chunk of text at once and then printing it until the input is '\0'. However, you're never actually updating this inside the loop. You can either use cin inside the loop to get the input, OR if you're trying to output each character, you can index the char array.

Why is this word sorting program only looping once?

I'm trying to create a word sorting program that will read the words in a .txt file and then write them to a new file in order from shortest words to longest words. So, for instance, if the first file contains:
elephant
dog
mouse
Once the program has executed, I want the second file (which is initially blank) to contain:
dog
mouse
elephant
Here's the code:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
string word;
ifstream readFrom;
ofstream writeTo;
readFrom.open("C:\\Users\\owner\\Desktop\\wordlist.txt");
writeTo.open("C:\\Users\\owner\\Desktop\\newwordlist.txt");
if (readFrom && writeTo)
{
cout << "Both files opened successfully.";
for (int lettercount = 1; lettercount < 20; lettercount++)
{
while (readFrom >> word)
{
if (word.length() == lettercount)
{
cout << "Writing " << word << " to file\n";
writeTo << word << endl;
}
}
readFrom.seekg(0, ios::beg); //resets read pos to beginning of file
}
}
else
cout << "Could not open one or both of files.";
return 0;
}
For the first iteration of the for loop, the nested while loop seems to work just fine, writing the correct values to the second file. However, something goes wrong in all the next iterations of the for loop, because no further words are written to the file. Why is that?
Thank you so much.
while (readFrom >> word)
{
}
readFrom.seekg(0, ios::beg); //resets read pos to begin
The while loop will continue until special flags are set on readFrom, namely, the EOF flag. Seeking to the beginning does not clear any flags, including EOF. Add the following line right before the seek to clear the flags and your code should work fine.
readFrom.clear();
After seek, clear the EOF flag.
readFrom.clear();

Counting occurrences of letter in a file

I'm trying to count the number of times each letter appears in a file. When I run the code below it counts "Z" twice. Can anyone explain why?
The test data is:
abcdefghijklmnopqrstuvwxyz
ABCDEFGHIJKLMNOPQRSTUVWXYZ
#include <iostream> //Required if your program does any I/O
#include <iomanip> //Required for output formatting
#include <fstream> //Required for file I/O
#include <string> //Required if your program uses C++ strings
#include <cmath> //Required for complex math functions
#include <cctype> //Required for letter case conversion
using namespace std; //Required for ANSI C++ 1998 standard.
int main ()
{
string reply;
string inputFileName;
ifstream inputFile;
char character;
int letterCount[127] = {};
cout << "Input file name: ";
getline(cin, inputFileName);
// Open the input file.
inputFile.open(inputFileName.c_str()); // Need .c_str() to convert a C++ string to a C-style string
// Check the file opened successfully.
if ( ! inputFile.is_open())
{
cout << "Unable to open input file." << endl;
cout << "Press enter to continue...";
getline(cin, reply);
exit(1);
}
while ( inputFile.peek() != EOF )
{
inputFile >> character;
//toupper(character);
letterCount[static_cast<int>(character)]++;
}
for (int iteration = 0; iteration <= 127; iteration++)
{
if ( letterCount[iteration] > 0 )
{
cout << static_cast<char>(iteration) << " " << letterCount[iteration] << endl;
}
}
system("pause");
exit(0);
}
As others have pointed out, you have two Qs in the input. The reason you have two Zs is that the last
inputFile >> character;
(probably when there's just a newline character left in the stream, hence not EOF) fails to convert anything, leaving a 'Z' in the global 'character' from the previous iteration. Try inspecting inputFile.fail() afterwards to see this:
while (inputFile.peek() != EOF)
{
inputFile >> character;
if (!inputFile.fail())
{
letterCount[static_cast<int>(character)]++;
}
}
The idiomatic way to write the loop, and which also fixes your 'Z' problem, is:
while (inputFile >> character)
{
letterCount[static_cast<int>(character)]++;
}
There are two Q's in your uppercase string. I believe the reason you get two counts for Z is that you should check for EOF after reading the character, not before, but I am not sure about that.
Well, others already have pointed out the error in your code.
But here is one elegant way you can read the file and count the letters in it:
struct letter_only: std::ctype<char>
{
letter_only(): std::ctype<char>(get_table()) {}
static std::ctype_base::mask const* get_table()
{
static std::vector<std::ctype_base::mask>
rc(std::ctype<char>::table_size,std::ctype_base::space);
std::fill(&rc['A'], &rc['z'+1], std::ctype_base::alpha);
return &rc[0];
}
};
struct Counter
{
std::map<char, int> letterCount;
void operator()(char item)
{
if ( item != std::ctype_base::space)
++letterCount[tolower(item)]; //remove tolower if you want case-sensitive solution!
}
operator std::map<char, int>() { return letterCount ; }
};
int main()
{
ifstream input;
input.imbue(std::locale(std::locale(), new letter_only())); //enable reading only leters only!
input.open("filename.txt");
istream_iterator<char> start(input);
istream_iterator<char> end;
std::map<char, int> letterCount = std::for_each(start, end, Counter());
for (std::map<char, int>::iterator it = letterCount.begin(); it != letterCount.end(); ++it)
{
cout << it->first <<" : "<< it->second << endl;
}
}
This is modified (untested) version of this solution:
Elegant ways to count the frequency of words in a file
For one thing, you do have two Q's in the input.
Regarding Z, #Jeremiah is probably right in that it is doubly counted due to it being the last character, and your code not detecting EOF properly. This can be easily verified by e.g. changing the order of input characters.
As a side note, here
for (int iteration = 0; iteration <= 127; iteration++)
your index goes out of bounds; either the loop condition should be iteration < 127, or your array declared as int letterCount[128].
Given that you apparently only want to count English letters, it seems like you should be able to simplify your code considerably:
int main(int argc, char **argv) {
std::ifstream infile(argv[1]);
char ch;
static int counts[26];
while (infile >> ch)
if (isalpha(ch))
++counts[tolower(ch)-'a'];
for (int i=0; i<26; i++)
std::cout << 'A' + i << ": " << counts[i] <<"\n";
return 0;
}
Of course, there are quite a few more possibilities. Compared to #Nawaz's code (for example), this is obviously quite a bit shorter and simpler -- but it's also more limited (e.g., as it stands, it only works with un-accented English characters). It's pretty much restricted to the basic ASCII letters -- EBCDIC encoding, ISO 8859-x, or Unicode will break it completely.
His also makes it easy to apply the "letters only" filtration to any file. Choosing between them depends on whether you want/need/can use that flexibility or not. If you only care about the letters mentioned in the question, and only on typical machines that use some superset of ASCII, this code will handle the job more easily -- but if you need more than that, it's not suitable at all.