- #281
jtbell
Staff Emeritus
Science Advisor
Homework Helper
- 15,942
- 5,858
Wouldn'tpbuk said:if (userSelection == EOL) continue;
break
instead of continue
also exit the loop cleanly in your example?Wouldn'tpbuk said:if (userSelection == EOL) continue;
break
instead of continue
also exit the loop cleanly in your example?cout << "the first key was: " << userSelection
<< ", the ASCII is " << int(userSelection) << endl;
int ascii = 97;
, then cout << char(ascii)
displays a
.Thanks for the program. I think I understand, I just want to confirm one thing.pbuk said:So here we go, you can also see this working at https://repl.it/repls/RealSubduedAtom. This code is missing comments of course, you might like to add them as you work through it.
C:#include <iostream> using namespace std; #define EOL '\n' int main() { int ascii = 0; char userSelection = 0; while (userSelection != EOL) { cout << "type a key and [enter]: "; cin.get(userSelection); ascii = userSelection; if (userSelection == EOL) continue; cin.ignore(255, EOL); cout << "the first key was: " << userSelection << ", the ASCII is " << ascii << endl; } return 0; }
No, that's not quite right. First of all the code you write does not read into a buffer, this part is done by the operating system. Also,yungman said:Thanks for the program. I think I understand, I just want to confirm one thing.
When cin.get(userSelection), it read two characters into the keyboard buffer: first character and the '\n' as last character. The userSelection contain the first character after the cin.get() line.
cin
is actually a line input buffer cin.get
which is why you have to hit enter, rather than a keyboard buffer which reads keys straight away.cin.get(userSelection)
waits for a character to appear in the keyboard line input buffer (which will only happen after return has been entered) and then reads one character from the buffer into userSelection
which is passed by reference.Does it look like this code reads anything from any input buffer?yungman said:Then in the line if (userSelection == EOL), This read out the next character from the keyboard buffer, which is '\n'.
Yes it would, but breaking out of ajtbell said:Wouldn'tbreak
instead ofcontinue
also exit the loop cleanly in your example?
while(true)
loop is not a very understandable way to write code. Putting the termination condition up front makes it much easier to see when you want the loop to terminate.Yes this is the way I would normally do it but the OP used two variables so I kept to that. Note that you can also cast usingjtbell said:You put the user's input in two variables, a char and an int, so you could display it in both formats. Instead, you can use just the char variable to get both formats:
We call this "casting" the char variable to int.Code:cout << "the first key was: " << userSelection << ", the ASCII is " << int(userSelection) << endl;
It works the other way, too. If you haveint ascii = 97;
, thencout << char(ascii)
displaysa
.
(int) userSelection
which the compiler treats exactly the same way; I prefer this because int(userSelection)
looks like a function call. Note also that when you do ascii = userSelection
the compiler is performing an implicit cast. With certain compiler settings, userSelection = ascii
will report a warning, @yungman can you think why?And of course yourpbuk said:Socin.get(userSelection)
waits for a character to appear in the keyboard line input buffer (which will only happen after return has been entered) and then reads one character from the buffer intouserSelection
which is passed by reference.
cin.ignore()
ensures that, if you enter more than one character before pressing 'return', the program processes only the first one and skips over the rest.cin.ignore()
, recompile, run, and then enter a word instead of a single character and see what happens.I am sorry, I can't really understand what you are saying. If you want to work out how it works the best thing is just to play with it.yungman said:I want to know how the keyboard buffer works when using cin, cin.get and cin.ignore.
I still want to confirm about how cin.get can make it jump out of the loop with just hitting ENTER where the rest of the character, you need to enter the character, then press ENTER. Please check what I said is correct or not.
Correct, you won't see anything from cin until you hit enter.yungman said:My understanding is when cin >>character, it needs to hit ENTER before it does anything.
As many characters as you have typed before hitting enter are in the buffer - it could be 0, 1 or many - as well as the \n (i.e. ENTER) character.yungman said:When hitting ENTER, two characters are stored in the keyboard buffer...the character and '\n'.
Only if it was there - if the first and only character was \n then the buffer is now empty.yungman said:cin read the first character, leaving the '\n' in the keyboard buffer.
Nowhere in either your code or mine is one cin.get() followed by another.yungman said:If cin.get() follows, it immediate read the '\n' from the last cin and treat it as a character and move on without reading the character supposed to be entered from the keyboard.
Not exactly. In order for the buffer to be read, two conditions must be satisfied:yungman said:I still don't get how C++ pick which character to read in the keyboard buffer, when is it start reading, is it only read when hitting the ENTER key?
char
type so it reads exactly one byte from the buffer. If you have only typed \n, that is what you will get and the buffer will be empty so if you immediately try to flush it your program will wait around for another character to flush. That's why I checked straight away to see if ENTER was the character received from the buffer.Yes, I wrote a program with words reading in last name and first, then print out, then as to hit ENTER to quit or any other character to do it again:jtbell said:And of course yourcin.ignore()
ensures that, if you enter more than one character before pressing 'return', the program processes only the first one and skips over the rest.
A useful exercise for yungman: "comment out" thecin.ignore()
, recompile, run, and then enter a word instead of a single character and see what happens.
// enter multiple data in one cin
#include <iostream>
using namespace std;
int main()
{
char LastName[21] = { '\n' }, FirstName[21] = { '\n' };
char userSelection = 'A';
do
{
cout << endl;
cout << "Enter LastName and FirstName with a space in between, then hit ENTER "<< "\n";
cin >> LastName >> FirstName;
cout << "\n";
cout << "You entered " << LastName << " " << FirstName << endl;
cout << "\n";
cin.ignore(255, '\n');// clear ENTER
cout << " Hit any character to repeat, hit ENTER to quit ";
cout << endl;
cin.get(userSelection);
} while (userSelection != '\n');
return 0;
}
std::string
. And insted of using cin >>
, you use the std::getline()
function, which reads from an input stream (e.g. cin) until it encounters a newline. The chars up to (but not including) the newline go into the string, and the newline is discarded. To test whether the user simply pressed <return>, you test the string to see if it's empty.#include <iostream>
#include <string>
int main ()
{
std::string choice = "go";
while (choice != "")
{
std::cout << "Enter a character, or <return> to exit: ";
std::getline (std::cin, choice);
std::cout << "You entered '" << choice << "'." << std::endl;
if (choice != "")
{
std::cout << "'" << choice[0] << "'"
<< " has the ASCII code " << int(choice[0]) << "."
<< std::endl;
}
}
return 0;
}
No, there is no problem with reading a newline character from an input stream as you can see from my code in #278(!). The problem with @yungman's code was that after reading one character (which could be a newline) he was callingjtbell said:It seems that in order to do exactly what you want (read a newline character from an input stream, just like any other char), C++ would have to allow for "unbuffered input streams." And C++ simply doesn't provide this capability. All I/O is via abstract streams, which could be connected to your keyboard and display, or to files, or to network sockets...
ignore()
which was waiting around for another newline.Yes,jtbell said:There's at least one way to accomplish your ultimate goal, which is to allow the user to terminate an input loop by simply pressing <return>. You don't read to a single char, but to anstd::string
. And insted of usingcin >>
, you use thestd::getline()
function, which reads from an input stream (e.g. cin) until it encounters a newline. The chars up to (but not including) the newline go into the string, and the newline is discarded. To test whether the user simply pressed <return>, you test the string to see if it's empty.
std::getline()
is generally more useful than cin >>
. But actually neither of these are very useful - interactive console programs aren't really a thing in C++; if I were @yungman I'd drop it and move on.// Read and write to file
#include<iostream>
#include<fstream>
using namespace std;
int main()
{
ofstream outputFile;
outputFile.open("demofile.txt");
cout << "Now writing data to the demofile.txt" << endl;
outputFile << "Bach\n";
outputFile << "Beethoven\n";
outputFile << "Mozart\n";
outputFile << "Schubert\n";
outputFile.close();
cout << "Done " << endl;
cout << endl;
return 0;
}
I don't understand, it is a new file as you see created by the program named "demofile.txt". It only contain 4 words( 4 names). It is less than 50 characters if you count them all including the name of the file.sysprog said:The error message says that your path name length plus the generated file name length exceeds the 250 character limit. You can reduce the length by reducing the number or lengths of the concatenated components. For example, the generated file name includes your project name, so using a shorter project name would contribute to staying within the limit.
https://stackoverflow.com/questions...-file-the-spcified-path-filename-are-too-long
Please look at the file name in the error message ##-## it's between quotation marks, and it's about 100 characters long. The file name that the message is reporting is the VS-generated name of a debug file. The fully-qualified name includes the path name, which includes everything in the directory structure from the drive letter to the most deeply nested current subdirectory. It also includes the whole of your project name, which lengthily describes the program, instead of just being something like P002. You can also rename directories to something shorter, e.g. abbreviate Microsoft to MS, and Visual Studio to VS. The full path character string from drive letter to current subdirectory doesn't appear in the message, so I can't see all the reductions you could do to reduce its length.yungman said:I don't understand, it is a new file as you see created by the program named "demofile.txt". It only contain 4 words( 4 names). It is less than 50 characters if you count them all including the name of the file.
thanks
I think I copied it correctly here:sysprog said:Please look at the file name in the error message it's between quotation marks, and it's about 100 characters long.
jtbell said:Debug\3.29 rea.63bf1643e.tlog\3.29 read write to file ifstream ofstream open close.lastbuildstate
The full path name is probably much longer, as sysprog described.
I agree with @jtbell and @sysprog that the filename of the source code is the problem.jtbell said:I'm just guessing here, because I've never used Visual Studio.
It's a good idea to create descriptive names for your projects, but not good to go overboard on the names. I have several hundred projects that I've created over the years, but they're short with no spaces, to remind me what the basic purpose of the program is. Instead of "3.29 read write to file ifstream ofstream open close," I would have called the project "FileOutput."yungman said:I solved the problem. It is the name of my whole project I created!
What you describe may or may not be strange. The only other C/C++ compiler I've used was Borland's product, close to 30 years ago.yungman said:VS has strange things, I found the demofile.txt that created by the program now. Also VS is strange, I before I end up deleting the whole project, I tried to change the name of EVERY file inside, it's like every time I navigate around, I see new names that I missed the first time! It just did not work trying to rename the files, finally, I had to take out the source.cpp, then try to delete. Then I had to close all the other projects ( I had the ifstream project opened in another VS program) in order to even create the new 3.29 ofstream.
Now my other ifstream doesn't read the demofile.txt. That's another story for another day. I want to work on that first.
{
ofstream outputFile;
outputFile.open( C:\Users\alanr\Desktop\Alan amp3\SS\OPS\MOSFET\demofile.txt);
}
You need double quotes around the path and filename string, and because characters preceded by a backslash (\) are escaped, you need to double them up.yungman said:I am actually very excited on this input and output file, this, is a real interface to the outside world rather than staying in it's little cocoon. So if I want to save and open a file anywhere in the computer I can put
in order to save demofile.txt into C:\Users\alanr\Desktop\Alan amp3\SS\OPS\MOSFET?C++:{ ofstream outputFile; outputFile.open( C:\Users\alanr\Desktop\Alan amp3\SS\OPS\MOSFET\demofile.txt); }
outputFile.open( "C:\\Users\\alanr\\Desktop\\Alan amp3\\SS\\OPS\\MOSFET\\demofile.txt");
outputFile.open( "C:/Users/alanr/Desktop/Alan amp3/SS/OPS/MOSFET/demofile.txt");
// Read and write to file
#include<iostream>
#include<fstream>
using namespace std;
int main()
{
ofstream outputFile;
outputFile.open("C:\Users\alanr\Desktop\C++ exercise\Gaddis\inout files\demofile.txt");
cout << "Now writing data to the demofile.txt" << endl;
outputFile << "Bach\n";
outputFile << "Beethoven\n";
outputFile << "Mozart\n";
outputFile << "Schubert\n";
outputFile.close();
cout << "Done " << endl;
cout << endl;
return 0;
}
I explained why it doesn't work in post #303. Please read more carefully the posts where members are trying to help you out.yungman said:It doesn't work, I can't find the file even though the program said it's done
Thanks, got it.Mark44 said:I explained why it doesn't work in post #303. Please read more carefully the posts where members are trying to help you out.
Here's a different version of what you were trying to do, written purely in C. It usesyungman said:I want the program to read in any character from the keyboard, display it and show the ASCII number. Then loop back to ask another character. I want it to exit when I hit ENTER ( ASCII = 10)
_getche()
, whose declaration is in conio.h. It gets a character from the keyboard, and echoes it to the screen. A slightly different function, _getch()
, doesn't echo the character.#include <cstdio> // for printf()
#include <conio.h> // for _getche()
#define CR 13 // <ENTER> key
int main()
{
int userEntry;
do
{
printf("Press any key: ");
userEntry = _getche();
printf("\nYou hit: ");
if (userEntry == CR) printf("<ENTER>\n");
else printf("%c\n", (char) userEntry);
printf("ASCII code: %d\n", userEntry);
} while (userEntry != CR);
}
Win uses CR and LF, while *n*x uses LF only, and assumes CR.Mark44 said:From post #277:
Here's a different version of what you were trying to do, written purely in C. It uses_getche()
, whose declaration is in conio.h. It gets a character from the keyboard, and echoes it to the screen. A slightly different function,_getch()
, doesn't echo the character.
BTW, the ASCII code for the Enter key is 13 (Carriage Return). On Windows machines, when you press <Enter>, the OS inserts two characters -- CR and LF (carriage return and line feed, ASCII codes 13 and 10, respectively). On Linux and Macs (I believe), only one of these is inserted, but I don't recall which one it is.C:#include <cstdio> // for printf() #include <conio.h> // for _getche() #define CR 13 // <ENTER> key int main() { int userEntry; do { printf("Press any key: "); userEntry = _getche(); printf("\nYou hit: "); if (userEntry == CR) printf("<ENTER>\n"); else printf("%c\n", (char) userEntry); printf("ASCII code: %d\n", userEntry); } while (userEntry != CR); }
Your string for the filename is broken. You have two options:yungman said:I was looking at the message after compile, I don't see where the demofile.txt saved.
View attachment 267210
The only thing I see in the program is the change of color as shown. It should all be RED, but the '\a' looks different. I googled, \a is alarm or alert. But alanr is the path in my computer, not much I can do.
View attachment 267211
thanks
Already stated in post #303.Timo said:1) Escape the backslashes: Since the \ has a special "escape" meaning to toggle special characters in a string (e.g. \n for a newline character) you need to have some encoding for a backslash. The encoding is \\ . So your filename string would be "C:\\Users\\alanr\\Desktop\\ ...". That's the ugly but for some weird reason the arguably more popular solution.
2) Use forward slashes for paths. Windows understands them perfectly, and everything else uses them anyways (see the address field of your browser). Your filename string then becomes "C:/Users/alanr/Desktop/...".
. I actually introduced a bug into our software yesterday that was totally avoidable if I had read the comment around line 4000 (of 27k) in the file I was editing.Mark44 said:Already stated in post #303.
// setw() setprecision() and fixed do while
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
double doubleValue = 91.0;
cout << "Enter a double number "; cin >> setw(2)>> doubleValue; cout << endl; cout << endl;
cout << "(" << setw(6)<< setprecision(4) << doubleValue << ")" << endl; cout << endl;
return 0;
}
Although the setw() and setprecision() manipulators work with both output streams and input streams, they are most often used to format output streams. This VS documentation -- https://docs.microsoft.com/en-us/cpp/standard-library/input-stream-manipulators?view=vs-2019 -- (with emphasis added) says this.yungman said:1) My question is whether cin >> setw() work on numbers? How do I limit say number <=1000? Is there even a way? I tried setprecision(), it won't do it.
Many manipulators, such as setprecision, are defined for the ios class and thus apply to input streams. Few manipulators, however, actually affect input stream objects. Of those that do, the most important are the radix manipulators, dec, oct, and hex, which determine the conversion base used with numbers from the input stream.
setw() specifies the width of the display field for the next element in the stream. The ios_base class has flags that can be used to left-justify the thing being displayed, or right-justify it, convert lowercase characters to uppercase, display the thing in decimal, hex, or octal, and some othersyungman said:2) Is setw() more for lining up the numbers to the right on display? eg.
cout << "(" << setw(6) << number << ")"; will give (____12) if number = 12.(I have to use____for empty space).