The first character of cstring keeps being removed upon the second execution of getline in ifstream:
#include <iostream>
#include <fstream>
using namespace std;
int main(){
char input[102];
ifstream keyTextFile("key.txt");
while (keyTextFile.getline(input, 102, '\n')) {
cout << input[0] << input[1] << endl;
cout << input << endl;
}
cout << input[0] << input[1] << endl;
keyTextFile.close();
return 0;
}
Currently, key.txt is one line:
0x0ffa331cc8765ddd
The code outputs:
0x
0x0ffa331cc8765ddd
x
The debugger shows input[0] changing from '0' to '\0' on the second execution of getline. How can I avoid this while allowing getline to scan a potentially large document?
please keep the answer to c-string implementation.
Related
My goal is to prompt user to enter a message / sentence and then print it out on the screen, using getline(). The following is two different attempts I have tried out.
First Attempt:
#include <iostream>
#include <iomanip>
#include <cstring>
using namespace std;
int main(){
chat message[80];
cout << "\n what is your message today?" << endl;
cin.getline( message, 80); // Enter a line with a max of 79 characters.
if( strlen( message) > 0) // If string length is longer than 0.
{
for( int i=0; message[i] != '\0'; ++i)
cout << message[i] << ' ';
cout << endl;
}
}
Second Attempt:
#include <iostream>
#include <iomanip>
#include <cstring>
using namespace std;
int main(){
string a = "a string";
cout << "\n what is your message today?" << endl;
while(getline(cin,a))
cout << a;
cout<<endl
}
}
For the fist attempt, the code simply print out "what is your message today?" and quit. I do not have a chance to enter any string at all. For the second attempt, it keeps asking me enter the message. Each time, when I enter something with the "\n", it would display what I entered on the screen. I use control + c to interrupt the running process to make it stop.
EDIT: To clarify and explain on my side, I extract the first attempt from a longer code, which is as the following.
#include <iostream>
#include <iomanip>
#include <cstring>
using namespace std;
char header[] = "\n *** C Strings ***\n\n"; // define a c string
int main()
{
char hello[30] = "Hello ", name[20], message[80]; // define a c string hello, declare two other c strings name and message
string a="fivelength";
cout << header << "Your first name: ";
cin >> setw(20) >> name; // Enter a word.
strcat( hello, name); // Append the name.
cout << hello << endl;
cin.sync(); // No previous input.
cout << "\nWhat is the message for today?"
<< endl;
cin.getline( message, 80); // Enter a line with a max of 79 characters.
if( strlen( message) > 0) // If string length is longer than 0.
{
for( int i=0; message[i] != '\0'; ++i)
cout << message[i] << ' ';
cout << endl;
}
return 0;
}
For the above code, it does not give me a chance to enter a message on the screen. I will put it as another question.
You are overcomplicating this, you can simply use std::string, which is the de-facto C++ string, and call the method, without using a loop.
You don't need a loop, since you are not going to repeatedly read lines, but only want to read one line, so no loop is needed.
#include <iostream>
#include <string> // not cstring, which is the C string library
using namespace std;
int main(void)
{
string message; // it can be an empty string, no need to initialize it
cout << "What is your message today?" << endl;
getline(cin, message);
cout << message;
cout<<endl;
return 0;
}
Output (Input: "Hello Stack Overflow!"):
What is your message today?
Message: Hello Stack Overflow!
PS: As #fredLarson commented, if you change chat to char in your first example, it should work. However, that code has a lot of commonalities with C.
The purpose of the program is to read a phrase from a file into a vector and convert the phrase into Pig Latin. When the translated phrase is outputted in Pig Latin, an additional "ay" is added after the phrase (which is not supposed to happen). Can anyone spot why this is happening? It is important that I fix this because it affects the total letters and total characters of the Pig Latin phrase that I need to output. Also, I'm not asking anyone to write any code for me, but any tips on how to make my code less redundant. A portion of my grade for programs is efficiency, which I usually lose points on.
Here's the code:
#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
#include <sstream>
#include <cctype>
#include <stdio.h>
#include <ctype.h>
using namespace std;
int main()
{
ifstream in;
string word, fileName;
vector <string> phrase;
int length = 0, index = 0;
int totalWords = -1, totalLetters = -3, totalChars;
cout << "PIG LATIN PROGRAM" << endl;
cout << "Which file are you accessing? : ";
cin >> fileName;
fileName += ".txt";
in.open(fileName);
if (in.fail()) cout << "\nFile not found!" << endl;
while(getline(in, word)) phrase.push_back(word);
cout << "Original Phrase: " << phrase[0] << endl;
istringstream iss(phrase[0]);
cout << "Pig Latin phrase: ";
do {
string OGword;
string PLword;
for (int i=0; i < phrase.size(); i++){
iss >> OGword;
totalWords++;
}
if (OGword[0]=='a' || OGword[0]=='A' || OGword[0]=='e' || OGword[0]=='E' || OGword[0]=='i' || OGword[0]=='I' || OGword[0]=='o' || OGword[0]=='O' || OGword[0]=='u' || OGword[0]=='U'){
cout << OGword << "way" << " ";
totalLetters += (OGword.size() + 3);
}
else {
PLword = OGword.substr(index);
length = PLword.length();
PLword.insert(length, "ay");
PLword.insert(length, 1, OGword[index]);
PLword.erase(0, 1);
if (isupper(OGword[0])){
transform(PLword.begin(), PLword.end(), PLword.begin(), ::tolower);
(toupper(PLword[1]));
char upper;
upper = toupper(PLword[0]);
PLword.erase(0, 1);
cout << upper;
}
cout << PLword << " ";
totalLetters += PLword.size();
}
} while (iss);
totalChars = totalLetters + 1;
cout << "\n\nTotal words: " << totalWords << endl;
cout << "Total Letters: " << totalLetters << endl;
cout << "Total Characters: "<< totalChars << endl;
}
Problem
The core loop of the program looks like this (in pseudocode):
istringstream iss; // Contains line of text.
do {
string OGword;
get_OGword_and_count_totalWords(iss, OGword);
print_pig_latin_of_word(OGword);
} while (iss);
The loop runs as long as iss has not experienced an error. And in particular, iss does not experience an error until an extraction operation fails. So things happen in the loop like this:
OGword contains the last legitimate word on the line.
Print the last word.
The while clause is tested. iss is still good at this point because no error has occurred, even if iss is at the end of string.
Attempt to extract a word into OGword. This fails, and leaves OGword empty ("").
Print the Pig Latin version of "", which is "ay".
The while clause is tested. iss is in an error state, and the loop ends.
Fix
One possible fix out of many is to test iss for an error immediately after extracting a word.
std::istringstream iss; // Contains line of text
std::string OGword;
while (iss >> OGword) {
increment_word_total();
print_pig_latin_of_word(OGword);
}
In this version, the operation iss >> OGword returns iss, which is converted to bool. If there was an error during the immediately preceeding extraction, the loop ends without printing anything.
Other Advice
I think the best way to improve readability is to break the code up into smaller functions. For instance, take the if / else block that formats and prints the Pig Latin, and actually put it in a function:
int print_pig_latin_of_word_and_return_total_letters(string_view word);
Then, the code in that function can be further subdivided:
bool starts_with_vowel(std::string_view word);
int print_vowel_word_and_count_letters(std::string_view word);
int print_consonant_word_and_count_letters(std::string_view word);
int print_pig_latin_of_word_and_count_letters(std::string_view word) {
if (starts_with_vowel(word)) {
return print_vowel_word_and_count_letters(word);
} else {
return print_consonant_word_and_count_letters(word);
}
}
Odds and Ends
I would drop using namespace std and write all of the std library names as std::string, etc. This makes it clear which things are from the standard library.
The program has interesting behavior on input files that contain more than one line. There is a for loop that loops over phrase.size() which is number of input lines. This causes words to be skipped and totalWords to be incorrect.
This statement doesn't do anything, because the result of toupper is ignored:
(toupper(PLword[1]));
I was attempting to print the first letter of each words in a sentence in C++. My idea was to print the first letter of a string first , then print every letter after a space:
#include <string.h>
#include <stdio.h>
#include <iostream>
using namespace std;
string sentence;
int main(int argc, char const *argv[])
{
cout << "Input your name!" << endl;
cin >> sentence;
//output first character
cout << sentence[0] << endl;
//output the rest of first characters in words
for(int i = 0; i < sentence.length(); i++){
if (sentence[i] == ' ' && sentence[i+1]!= '\0'){
cout << sentence[i+1]<< endl;
}
}
return 0;
}
This solution only printed the very first letter of the string , and I was having trouble determining what went wrong with my code.
std::cin will stop reading into a string after the first whitespace. So, if you input hello world, it will only read "hello" into your string. Instead, you can read an entire line into your string using std::getline:
cout << "Input your name!" << endl;
getline(cin, sentence);
...
Also, the contents of a std::string won't have a nul character ('\0') in it whichever method you use, so your sentence[i+1] != '\0' check won't ever stop you from printing something.
I am trying to write a program that interacts with some instruments that require commands beginning with the escape character (ascii 27) but am having trouble testing as the program seems to hang the moment it attempts to print the escape character. This program is compiled with g++ in an Ubuntu machine and run from gnome-terminal:
#include <cstdlib>
#include <iostream>
#include <unistd.h>
#include <limits>
using namespace std;
int main()
{
string str;
const int numSamples=10;
const int escapeInt = 27;
const char escapeChar = escapeInt;
// sleep(30);
//Ask for the latest test results
cin.clear();
// cin.ignore(numeric_limits<streamsize>::max());
cout << "\n\n\n";
cout << escapeChar << "PF2 -" << numSamples;
cerr << "\n\n\n" << escapeChar << "PF2 -" << numSamples;
// cin.ignore(2,'\n');
getline( cin, str, '\n');
cerr << str;
int k=1;
while (k<=numSamples)//getline(cin, str))
{
getline( cin, str, '\n');
k++;
cerr << str << endl;
}
return 0;
}
The output is just three blank lines and then the program becomes unresponsive. It doesn't even respond to ctrl-c. Any suggestions as to how to get around this?
Oh, I can answer my own question. As was suggested by #Alf, (Thank you) it seems that I just shouldn't be trying to print the escape sequence to cerr as that winds up being interpreted by my terminal which, in my case with gnome-terminal, is a no-no.
Thanks for the useful insight folks!
I've been attempting to use the C++ stringstream class to do some relatively simple string manipulations, but I'm having a problem with the get() method. For some reason whenever I extract the output character by character it appends a second copy of the final letter.
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
int main() {
stringstream ss("hello");
char c;
while(!ss.eof()) {
ss.get(c);
cout << "char: " << c << endl;
}
return 0;
}
The output from the program is:
char: h
char: e
char: l
char: l
char: o
char: o
Any help you can give me on this would be appreciated.
At the end of the stream ss.eof() doesn't know yet that the end of the stream will be reached soon, but the following extraction of a character fails. Since the extraction failed because the end of the stream was reached, c is not changed. Your program doesn't recognize that ss.get(c) failed and prints that old value of c again.
A better way to check if there still is a character that can be read from the stream would be a loop like this:
while (ss.get(c)) {
cout << "char: " << c << endl;
}
its because of the order of the loop. Your reading the \0 and EOF.
reorder your code like this
int main() {
stringstream ss("hello");
char c;
ss.get(c);
while(!ss.eof()) {
cout << "char: " << c << endl;
ss.get(c);
}
return 0;
}
The EOF flag is only set if you attempt to read PAST the end of the file. The following code fixes the problem by testing for EOF after the get() instead of before it:
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
int main() {
stringstream ss("hello");
char c;
while(1) {
ss.get(c);
if(ss.eof())
break;
cout << "char: " << c << endl;
}
return 0;
}