I'm using the book "Programming Principles and Practice using C++" to learn programming and one of the exercises is looping through the characters a-z using a while-loop.
Now, I have programmed with C++ and other languages before, so I decided to try to use as few lines as possible (while still using a while-loop). However, this came with the cost of my output being kind of messed up.
Code:
#include <iostream>
int main(){
char ch = 'a';
while(ch <= 'z')
std::cout << ch << '\t' << (int) ch++ << std::endl;
return 0;
}
Output:
b 97
c 98
d 99
e 100
...
x 119
y 120
z 121
{ 122
Now I do realize that this could've been done with a for-loop instead, and I did that as well (it worked). But I still don't get what's wrong with this code, and it's really annoying me.
It appears as if I've told it to output "ch+1", since it prints out 'b' where it should print 'a'. The incrementing isn't done until after the integer value of ch has been put into the out-stream (post-increment). And even if I had incremented it earlier, at least the printed characters and their integer values should correspond.
Any ideas of why this code isn't working?
The order of the operator<< calls is well-specified, but the order in which their operands is evaluated is not.
The increment of ch may happen before or after you output ch "the first time", and merely running this program is Undefined anyway because of the interleaved read/write operations:
[2003: 1.9/12]: A full-expression is an expression that is not a
subexpression of another expression. [..]
[2003: 1.9/16]: There is a sequence point at the completion of
evaluation of each full-expression.
[2003: 5/4]: Except where noted, the order of evaluation of operands
of individual operators and subexpressions of individual expressions,
and the order in which side effects take place, is unspecified.
Between the previous and next sequence point a scalar object shall
have its stored value modified at most once by the evaluation of an
expression. Furthermore, the prior value shall be accessed only to
determine the value to be stored. The requirements of this paragraph
shall be met for each allowable ordering of the subexpressions of a
full expression; otherwise the behavior is undefined.
Instead, be explicit:
std::cout << ch << '\t' << int(ch) << std::endl;
++ch;
Your compiler should have warned you about your code. That it didn't indicates that you do not have your diagnostics set at a useful level.
With GCC, use -Wall -Wextra -std=c++98 -pedantic (or -Wall -Wextra -std=c++0x -pedantic for C++0x).
Short answer is that you have a bit of Undefined Behavior because you're both modifying and using the value of the variable ch, via separate sub-expressions, in the same expression.
The Right Thing(TM) to do here is to use the most practical loop for the task at hand:
#include <iostream>
int main(){
for(char ch = 'a'; ch <= 'z'; ++a){
std::cout << ch << '\t' << ch+0 << std::endl;
}
}
The ch++ in your code gets evaluated first. A more readable and correct version would be:
#include <iostream>
int main(){
char ch = 'a';
while(ch <= 'z') {
std::cout << ch << '\t' << int(ch) << std::endl;
++ch;
}
return 0;
}
When you use one variable twice in one command or expression, once with ++ (or --) and once without, you get undefined behavour.
Instead use:
while(ch <= 'z')
{
std::cout << ch << '\t' << (int) ch << std::endl;
ch++;
}
Related
#include<iostream>
using namespace std;
int main(){
char c = 'a';
int numb;
for (int i = 1; i <= 25 ; i++){
cout << c << "," << c++ << endl;
}
}
Why is it that when I print the output above, the following will get printed:
b,a
c,b
d,c
But I was expecting:
a,b
b,c
c,d
If you are not compiling to the C++17 Standard revision or more recent you have encountered undefined behaviour. The older C++ Standards do not specify the sequencing of
cout << c << "," << c++ << endl;
so there are no guarantees on when that c++ will occur. The only thing you can count on is the c++ term will be the initial value because ++ increments after the value is collected.
a,a
or
b,a
are valid outputs.
As of C++17 the Standard guarantees that all side effects will be resolved before proceeding to the next <<. << c will be resolved, not that there is much to resolve, before << "," starts. << c++ comes even later in the chain. This means you should always see
a,a
b,b
c,c
See the notes on Undefined Behaviour at the bottom of Order of evaluation
I believe that it has to do with the order of operations here. The stream operator (<<) operates from right to left. Meaning that in the first run, c++ evaluates to "a", but causes c to be iterated up to "b".
I wrote the following program to search of a particular string in a given array of string. I made an error in the search function and wrote i-- instead of i++.
#include <iostream>
#include <string>
using namespace std;
int search(string S[], int pos, string s)
{
for(int i=0; i<pos; i--) {
cout << i << " : " << S[i] << "\n";
if (S[i] == s) {
cout << "Inside Return ->\n";
cout << i << " / " << S[i] << " / " << s << "\n";
return i;
}
}
return -1;
}
int main()
{
string S[] = {"abc", "def", "pqr", "xyz"};
string s = "def";
cout << search(S,2,s) << "\n";
return 0;
}
Logically the loop is an infinite loop and should not stop but what I observed was that the if condition was true for each search and the function returned -1.
I printed the values and noticed that the value of S[-1] is always same as the third argument passed to the function (the string to be searched) due to which the loop was returning -1 every time.
Is this something that g++ is doing or is it related to the way memory is allocated for the formal arguments of the function?
Output of the above code -
0 : abc
-1 : def
Inside Return ->
-1 / def / def
PS - I am using g++ (Ubuntu 7.3.0-27ubuntu1~18.04) 7.3.0
Edit -I understand that g++ doesn't check for bounds but I was intrigued by the fact that the values of S[-1] was always the same as s. I was wondering if there are any possible theories for this
Access out of bounds is undefined behaviour.
Undefined behaviour reads is not "garbage" or "segfault", it is literally anything. The read could time travel and make code earlier in the program behave differently. The behaviour of the program, from start to finish, it completely unspecified by the C++ standard whenever any undefined behaviour happens anywhere.
In this case, naive assembly and the ABI tells you that arguments on the "stack" at run time are located adjacent to things like the arguments to the function.
So a naive rewriting of your code into assembly results in negative indexes reading from the arguments to the function.
But, a whole myriad of completely innocuous, common and safe alternative interpretations of your program as machine code, starting with inline and going far away from there, make this not happen.
When compiling without LTO or over dynamic library boundaries, you can have some small amount of confidence that the compiler's published ABI will be used to make the call; any assumption elsewhere is dangerously bad. And if you are compiling without LTO and relying on it, it now means that you have to audit every build of your code from now until eternity or risk a bug showing up with no apparent cause long from now.
This question already has answers here:
Undefined behavior and sequence points
(5 answers)
Closed 6 years ago.
I want to write several lines to a file. Each line has an index (running index).
My code is:
ofstream outputFile;
int index = 0;
outputFile << ++index << ") FirstLine" <<endl
<< ++index << ") SecondLine" <<endl
...
<< ++index << ") LastLine" <<endl;
Problem is that I get no running index. That is, all lines has the same index (which is the total lines number). So my questions are firstly, how does ofstream work (meaning why do I get the described result). Secondly, what should I do to get it work?
Firstly, how does ofstream work (meaning why do I get the described result)?
According to the C++ standard (section 1.9, clause 15):
Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced.
If a side effect on a scalar object is unsequenced relative to either another side effect on the same scalar object or a value computation using the value of the same scalar object, and they are not potentially concurrent, the behavior is undefined.
Applied to your case:
The evaluation of the ++index statements (which are operands to the << operator) is unsequenced.
++index modifies the value of index, and therefore has a side effect on a scalar object.
As such, the behavior is undefined.
Secondly, what should I do to get it work?
One simple option would be to split the single large output expression into multiple lines, such that each ++index statement is on a separate line.
Alternatively, you could both solve the problem and reduce repetition by using a loop.
For example:
#include <array>
#include <iostream>
#include <string>
int main () {
static const std::array<std::string, 3> lines = {
"First line",
"Second line",
"Last line",
};
for (int i = 0; i < lines.size(); ++i) {
std::cout << i + 1 << ") " << lines[i] << std::endl;
}
}
Save this as example.cc, and compile using:
clang++ -std=c++14 example.cc -o example
Then run the example:
$ ./example
1) First line
2) Second line
3) Last line
Note that this prints to standard output to simplify the example, but std::cout can be easily replaced with an instance of std::ofstream depending on your use case.
Suppose I have a file which is consists of a single string
a1
If I write this:
char ch = getchar();
char ch1 = getchar();
cout << ch - 'a' << " " << ch1 - '0' << endl;
I have 0 1 in output. But if I write this:
cout << getchar() - 'a' << " " << getchar() - '0' << endl;
I have -48 49.
Doesnt getchar() return a normal char? Why the result isn't the same?
You're getting the issue because the two calls to getchar() are evaluated in unspecified order, and your compiler happens to evaluate the rightmost one first.
C++ has rather loose rules regarding order of evaluation of subexpressions in an expression, to allow for more optimisation opportunities. The cout line is one expression, where the following is guaranteed:
the first getchar() will be evaluated before the first -
the second getchar() will be evaluated before the second -
the first - will be evaluated before the first <<
the second - will be evaluated before the third <<
the <<s will be evaluated in order from the left.
Note that there are no other ordering restrictions. For example, the compiler is free to evaluate both getchar() calls and both -s before the first <<. Most importantly, there is no rule forcing the first getchar() to be evaluated before the second one.
>The character 'b' is char('a'+1),'c' is char('a'+2),etc. Use a loop to write out a table of characters with their corresponding integer values.
I cannot finish this exercise because of this error.
error: lvalue required as increment operand
for(char a='a'; a<24; ++a)
{
cout<<char('a'++);
}
The loop body will never execute with the controlling expression a < 24 because you have initialized variable a with character a and all printable characters are not less than ASCII value 32.
Try this:
for(char a='a'; a < 'a' + 24; ++a)
{
cout << a;
}
I think you would be less confused if you named your variable letter instead of a, because it only represents the letter 'a' at the very beginning.
for(char letter='a'; letter<24; ++letter)
{
cout<<char('a'++);
}
I'm going to assume you actually want to print out the entire alphabet, not just the first 24 letters.
It looks from here like you tried to do a mix of two possible approaches. In the first approach, you increment a char from a to z with each iteration of the for loop and print it out each time. In the second approach, you increment some offset from 0 to 25 and print out 'a' + offset.
You mix these two approaches up in the first line. You're starting the loop with letter set to 'a', which you do not know the numerical value of. You then compare letter to see if it is less than 24. Well in any ASCII-compatible character set, the character 'a' has value 97, so this condition will never pass.
You then misuse ++ on the cout line. The ++ operator attempts to modify its operand, yet 'a' is a literal and so cannot be modified. Have a look at what your assignment told you. You can do 'a' + 1 to get 'b', for example, so this assumes you have an offset (which you don't with your current approach).
So to repeat, you have two options. First: keep letter as a char starting at 'a' and fix the condition so that it checks if letter is less than or equal to the value of 'z' and then just print out letter. Second: change letter to offset and start it off at 0 and increment it while it is less than 26, and then print out 'a' + offset.
Note, however, that both of these approaches assume that the letters have consecutive values in the execution character set. This is not necessarily true.
The ++ operator is a "hidden assignment" (the operand's value is changed by it). But you can only assign to variables, which 'a' is not.
I know this has been closed for a while but since the exercise was about while loops and not for loops, I thought I would offer my solution. I'm just going through the book myself and someone in the future might stumble over this.
int i = 0;
char n = 'a'; // this will list the alphabet
int conv = 0;
conv = n; // this converts the alphabet into integer
while (i < 26) { // starts from 0 and goes to 25
cout << char(n + i) << '\t' << conv + i << '\n';
++i;
}
You may use the following: (http://ideone.com/akwGhl)
#include <iostream>
int main()
{
for (char c = 'a'; c <= 'z'; ++c) {
std::cout << "letter " << c << " has value " << int(c) << std::endl;
}
return 0;
}
hey through troubleshooting i obtained a sample that worked , i have yet to perfectly understand how my code works but as the solutions that were proposed to me here seemed too technical for my level i figured that i should publish mine
#include"header files . h"//i use the libraries given in the book
int main () {
char a ='a';
int i = 0 ;
while (i <= 25)//for (i = 0 ; i <= 25 ; i++)
//for those who used for
{
cout << a << '\t' << 'a' + i << endl;
a += 1; // augments the character value of a to b ... then to z
i++; // augments the value of i allowing us thus to make the augmentation,if you are using the for structure do not put I in your code
}
}