Explanation of this C++ code I learned in college - c++

I'm a newbie here and I just started college. We are learning C++ and I find it a little bit difficult, because of the way the teachers explain.
Yesterday we did a task that says to create a program, which finds greatest common divisor of 2 numbers. So, the teacher started writing the code, but the explanation wasn't enough for me and I really need some help right now.
(I putted comments on the things I don't understand.)
Here is the code:
#include <iostream>
#include <cmath>
using namespace std;
int main(){
int a, b;
cout << "a = ";
cin >> a;
cout << "b = ";
cin >> b;
cout << "GCD (" << a << ", " << b << ") is ";
if (a != 0 && b != 0){
size_t min = abs(a) < abs(b) ? abs(a) : abs(b); //What's that after (?)?
size_t max = abs(a) > abs(b) ? abs(a) : abs(b);
size_t diff = max - min; //What is that variable used for?
while (diff > 0)
{
min = diff < min ? diff : min;
max = diff > min ? diff : min;
diff = max - min;
}
cout << min << endl;
}
else{
if (a != 0 || b != 0)
cout << (a>b ? a : b) << endl;
else
cout << "not possible!!!\n";
}
system("pause");
return 0;
}
QUESTION: When should I put {} on if's, while's etc.?

This is the syntax for an if-statement
if ( condition ) statement-true else statement-false
statement-true is either one statement or a block of statements in {...}
So you can use if without {...} if there is only one line. But it is better to always use {...}.

It is necessary when you need more that one line/statement to be executed by the if/else/while. Valid examples:
if (a != 0 || b != 0)
cout << (a>b ? a : b) << endl;
if (a != 0 || b != 0) cout << (a>b ? a : b) << endl;
if (a != 0 || b != 0) {
cout << (a>b ? a : b) << endl;
a++; }
If you did:
if (a != 0 || b != 0)
cout << (a>b ? a : b) << endl;
a++;
The the a++; would be executed regardless of the if condition.
Some programmers like to use {} even for single statements because they believe it leads to more usable and maintainable code. I do not belong to that group but I can see the arguments on either side.

size_t min = abs(a) < abs(b) ? abs(a) : abs(b); //What's that after (?)?
C and C++ have a construct that is similar to an if-else statement. This line basically says that if abs(a) is smaller than abs(b), then min should take the value of abs(a); otherwise, it should take the value of abs(b).
size_t diff = max - min; //What is that variable used for?
It's not clear what you mean here. If you mean diff, the code essentially uses it in the subsequent while loop to perform division by repeated subtraction. This is a very strange thing to do, especially because it is so inefficient, and division would have been more compact and efficient in the loop. It's even stranger given that earlier the author uses ?: (which you asked about); that construction is used mainly because it's more compact and efficient than an if-else statement, but this is rather strange code, anyway.
When should I put {} on if's, while's etc.?
You should do it by default. You don't have to do it if only one statement is to be performed when the condition is true (resp. false) but people usually do as a matter of good style and to assist readability. For instance, this code
if (a != 0 || b != 0)
cout << (a>b ? a : b) << endl;
else
cout << "not possible!!!\n";
could just as easily be
if (a != 0 || b != 0) {
cout << (a>b ? a : b) << endl;
} else {
cout << "not possible!!!\n";
}
...and a lot of instructors would actually require the latter from learners.

In addition to the other answers:
//What's that after (?)?
foo ? bar : qux;
Is the use of the ternary operator.
If foo is true the expression evaluates to bar else it evaluates to qux.

Just adding my two cents...
This
if (a != 0 || b != 0)
cout << (a>b ? a : b) << endl;
is equivalent to
if (a != 0 || b != 0) {
cout << (a>b ? a : b) << endl;
}
The big difference comes when you realize that code is not something static that you write once and then never change again. Lets change the example a little bit (intentially weird intendation)
if ( x ) // (I)
y = a;
z = b;
is not the same as
if ( x ) { // (II)
y = a;
z = b;
}
Using brackets allows you to focus on only the part you care about. Consider that you later decide to swap the two lines, then
if ( x ) {
z = b;
y = a;
}
is still ok (its the same as (II), apart from swapping the two instructions), while
if ( x )
z = b;
y = a;
is doing something completely different as the version above (I). If you use the brackets you dont need to care whether those two lines are inside a if block. To decide if you can swap them you need to look at nothing more than those two lines. This is not the case if you do not use the brackets. This may seem like a minor thing, though I have seen countless bugs caused by not putting brackets where there could be some.

For 1 line of code following if, else, else if, while, etc
if (<some condition>)
//1 line of code`
and
if (<some condition>)
{
//1 line of code
}
...are equivalent and it is up to you (personal style,developer choice,readability etc.) to make that decision.
For > 1 line of code following if, else, else if, while, etc
{} is required if you want code completely scoped to the condition statement. It is up to you the developer to make sure to scope these lines of code (i.e. the compiler will not warn you about this.. it will not know if the intent was 1 line or multiple lines).
So an example
if(<some condition>)
{
//line of code 1
//line of code 2
}
the compiler will let you do this...
if(<some condition>)
// line of code 1
// line of code 2
but //line of code 2 has no relation to the if condition since it was not scoped with {} and will be executed regardless of the if statement condition.

Related

If statement giving parenthesis error in my triangle exercise

Learning C++ and doing a basic triangle exercise.
Can anyone check my code if I done everything right and explain why I am getting this error: suggest parenthesis around ‘&&’ within ‘||’
#include <iostream>
int main()
{
// enter 3 numbers for sides of triangle
int a, b, c;
std::cout << "Input three numbers: " << std::endl;
std::cin >> a;
std::cin >> b;
std::cin >> c;
// check what kind of traingle it is and output result
if(a == b && b == c){
std::cout << "You have an equalateral triangle." << std::endl;
}else if(a == b && b !=c || a!=b && b==c || a==c && b!=c){
std::cout << "You have an iso triangle." << std::endl;
}else{
std::cout << "You have an scalene triangle." << std::endl;
}
}
The Error Messages you're receiving are a diagnostic that Clang can generate
If these are showing up as errors, you likely have -Werror enabled in your compiler options. You can remove that flag to stop promoting Warnings to Errors. Or, if you don't want it to issue warnings (promoted to errors) for what is (let's be honest) a pretty spurious diagnostic, you can add -Wno-logical-op-parentheses to the compiler options.
As to why this diagnostic is being generated in the first place: The Operator Precedence between && and || is not always obvious, especially to newer programmers, and Clang is suggesting you expressly specify the operator precendence to make sure that what you've written is what you intend. So it's asking you to rewrite these lines like this:
if(a == b && b == c) {
std::cout << "You have an equalateral triangle." << std::endl;
} else if((a == b && b != c) || (a != b && b == c) || (a == c && b != c)) {
std::cout << "You have an iso triangle." << std::endl;
} else {
std::cout << "You have an scalene triangle." << std::endl;
}
The extra parenthesis make the warning go away.
As far as I can tell there isn't actually a logical error in your code (the boolean logic behaves as you expect it to), and indeed, if you were to send this code to a different compiler, they compile it without issue. So this is really just a particular quirk of Clang.
The compiler is suggesting that you use parentheses to make your second if statement clearer/easier to parse.
In particular, you should group the && statements within the || statement using parentheses. That is, change this code
(a == b && b !=c || a != b && b == c || a == c && b != c)
to
((a == b && b != c) || (a != b && b == c) || (a == c && b != c))
It's worth noting that this is a "style error"; the first form is not strictly incorrect code (indeed I was able to compile and run it just fine in the absence of compiler flags), but it's good practice to write it the second way.
If you pass the -Wall flag to your compiler (or more specifically in this case, the -Wlogical-op-parentheses flag) this will show up as a warning. Passing -Werror changes these warnings to errors, which seems to be the case here. It's good practice to use both -Wall and -Werror, since the compiler will then point out potential clarity problems like this and force you to fix them before continuing the compilation.
This is sure to divide opinion, but I am of the ilk that you need to know the C++ grammar well before you attempt to push any code in production.
The fact remains that || has lower precedence than &&. And that should be as second nature to you as the precedence of the binary operators + and * ought to be. Emphasising the obvious with parentheses introduces noise and makes your code harder to read. I'd advise you to switch off that specific warning, and press on.
Note in your particular case though the second conditional simplifies to
else if (a == b || a == c || b == c)
as you have already eliminated the equilateral possibility. Again, some software houses insist that if statements are all mutually excusive in the sense that they can be arbitrarily reordered without the code breaking. Yet more opinion I'm afraid.

Cannot understand error: "warning: control reaches end of non-void function [-Wreturn-type]"

I have been learning c++ recently. When I tried to run the following lines...
#include <iostream>
short a = 0;
short b = 1;
short c, i;
void Fibonacci(){
std::cout << a;
std::cout << b;
while (a <= 100){
c = a + b;
a = b;
b = c;
std::cout << c;
}
}
int prime_number(short a){
if (a == 1){
std::cout << "It's a prime number\n";
} else{
for (i = 2; i < a; i++){
if ((a%i) == 0){
std::cout << "It's a prime number\n";
std::cout << "The given number is divisible by " << i << "\n";
return 0;
}
}
std::cout << "It's not an prime number";
}
}
int main(){
short user_input;
std::cout << "Press 1 for Fibonacci and 2 for prime number";
std::cin >> user_input;
if (user_input == 1){
Fibonacci();
}
if (user_input == 2){
std::cout << "Type the number to check whether it's prime";
std::cin >> a ;
prime_number(a);
}
}
...I get an error saying:
In function ‘int prime_number(short int)’:
Function.cpp:37:1: warning: control reaches end of non-void function [-Wreturn-type]
37 | }
I searched various platforms for the answers, but I couldn't understand what really happens here. It's an error because the compiler cannot find whether the function has an end or not. Can someone help me understand the error and solve it?
Warnings aren't errors. When you compile a program and only get warnings (ie. no errors) then this means your program has successfully compiled (an executable has been made). When you get errors, this means that compilation was aborted (so no executable output - if you already had one, it won't have been updated).
It's warning you that when the integer input is 1 that you aren't specifying a return — which is invalid. Also, if it's not 1, then the the else statement still doesn't guarantee a returned value:
for (i = 2; i < a; i++){
if ((a%i) == 0){
std::cout << "it's a prime number\n";
std::cout << "The given number is divisible by " << i << "\n";
return 0;
}
}
The compiler can't know that return 0 will always be executed here - and even if it could, the compiler isn't designed to always understand the logic of your code. Even knowing your logic, return 0 will only be executed if a is greater than 2 and non-prime.
You could fix this by putting return statements in both of your if statements, or even at the end of your function. But notice that you never use the return value? This implies that your prime_number() function should be void prime_number(), then you won't need return values at all, and can just use break; in your loop - or return; if you prefer (here's an example of how to resolve this particular issue - there's still other bugs though, discussed below).
This is probably confusing to a beginner: Why doesn't it warn you when the function int main() contains no return value? This is because main is special: If no return value is given, it implies return 0.
Another thing that may confuse you here is if you ever compile with the flag -Werror. If you do, then the original code will give you an error, because the Werror flag turns all warnings into errors (to force programmers to pay attention to the warnings).
The logic of your code isn't right - it's actually the opposite: 1 is defined as not a prime number (this is because of the value we get from unique prime decomposition, so mathematicians chose to exclude 1 as prime). Also, ((a%i) == 0) means that when a is divided by i that it has 0 remainder, ie. i divides a, so a is not prime.
Finally, avoid using global variables. Keep all your variables local so that the logic of your code is simpler (easier to read / less bug-prone).
Here's an example of how you could rewrite your code that resolves all the above issues.
As Elliott in the comments has said the warning you are getting is not going to affect your program at all. It's recommend that you return something since you function has a return type of integer.
Below is a easy fix to get rid of the warning. :)
Old Code:
if (a == 1)
{
std::cout << "Its a prime number\n";
}
New Code without the Warning:
if (a == 1)
{
std::cout << "Its a prime number\n";
return 0;
}

Collatz Conjecture c++ weird output with big numbers

So, I was bored, and decided to make something completely random, then I came across the collatz conjecture: start with any positive number, and if it is even, devide by two. If it is odd, multiply by three and add one. When repeating this, you will end at the number one. So I made this code:
//Collatz Conjecture by Lucas Knook
#include <iostream>
#include <iomanip>
using namespace std;
int main() {
long long n;
cin >> n;
cout << setw(5) << n;
while(true){
if(n % 2 == 0 && n != 1){
//is even
cout << " E" << endl;
n /=2;
cout << setw(5) << n;
}
else if(n != 1){
//is odd
cout << " O" << endl;
n = n * 3 + 1;
cout << setw(5) << n;
}
else break;
}
cout << " O" << endl << endl << "end loop";
return 0;
}
I am still learning c++ (I just completed the sololearn course, and I am about to get the "C++ for dummies all-in-one" book), but I think this is a good start for me, and it works.
There is just one little problem: If I use big numbers, it does stop at one, and gets the odd and even right, but...
Look at this first part of the output when entering
"1000000000000000000000000" :
9223372036854775807 O
9223372036854775806 E
4611686018427387903 O
-4611686018427387906 E
-2305843009213693953 O
-6917529027641081858 E
-3458764513820540929 O
8070450532247928830 E
4035225266123964415 O
-6341068275337658370 E
-3170534137668829185 O
8935141660703064062 E
4467570830351532031 O
-5044031582654955522 E
-2522015791327477761 O
-7566047373982433282 E
-3783023686991216641 O
7097673012735901694 E
3548836506367950847 O
-7800234554605699074 E
Ehm, that's a bit weird, isn't it? (don't look at the line breaks, it is perfectly stacked, it just doesn't show here, because I copied the output)
Can someone please explain me why this is happening and how to fix it?
You've exceeded the limits of long long integer values. The first value in your output is truncated to be much smaller than your input, then when you get to 4611686018427387903 it's multiplied by 3, since it isn't even. That's when it overflows the type and wraps around into negative values. You'll need to use a BigInteger library, like TTMath.
Basically as other people pointed out you don't check for overflow. But I would like to point out different thing, your code is still not valid as you don't check if you got into endless loop, when multiplication and division sequence generates the same numbers, your while will never end.
This is correct code with simple overflow detection:
#include <iostream>
#include <unordered_set>
bool colatazConjecture(int n) {
std::unordered_set<int> localComputed;
int newN = 0;
while (n != 1) {
if (!localComputed.emplace(n).second) {
throw "Cycle detected";
}
newN = n;
if (n & 0x1) {
newN = 3*n + 1;
if (newN <= n) {
throw std::overflow_error("Overflow for " + std::to_string(newN));
}
} else {
newN >>= 1;
}
n = newN;
}
}

Recursion and pre-decrement operator

I have this function:
void m(int n)
{
if(n > 0)
m(--n);
cout << n << " "; //for n = 5 --> output is: 0 0 1 2 3 4
}
I have a problem with understanding how it works.
For example:
n(input) = 5
output: 0 0 1 2 3 4
My question is: Why does it show zero twice?
When I add brackets like this:
void m(int n)
{
if(n > 0)
{
m(--n);
cout << n << " "; // now, it shows 0 1 2 3 4 (n = 5)
}
}
So, what brackets cause in this code, that "0" exists only once?
And when I change pre-decrement (--n) to post-decrement (n--) it shows nothing. Why?
Could somebody help me to understand how it works?
First thing to note is : in C++ if you don't put brackets after an if statement, only the next line will be in the statement.
Example :
if(x > 0)
cout << 1;
cout << 2;
Here cout << 2 will always be executed no matter the value of x
The correct way of writing this is
if(x > 0)
{
cout << 1;
cout << 2;
}
Same thing goes for else statements
So this was for the brackets.
My wild guess for the post decrement is the following :
if you do m(n--), the value passed will be 5, the value of n will only change after the function call and go out of scope (so it won't matter). So what will happen is an infinite number of m(5) calls and that's why nothing is appearing. (I'm not sure about that part so please tell me if wrong) !
Hope it helped !
Looks like you confused with Python syntax, where scope of if is determined by indent. In C (and C++, C#, Java an many other languages) the scope is one statement (which ends with ;) unless you use curly brackets { and }. In the 1st variant of your code cout << n << ... will be always performed, regardless of value of n. In second variant it will be performed only if(n > 0)

C++ Exam Grader [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions concerning problems with code you've written must describe the specific problem — and include valid code to reproduce it — in the question itself. See SSCCE.org for guidance.
Closed 9 years ago.
Improve this question
Alright, I've been able to simply the code. My current issue is dealing with the output. Looping structures to include 5 students but have the number elements reset like the percentages and answeredCorrectly. Also at the end of questions missed portion, I have to add in what the correct answer is. Our professor gave us 2 functions in order to accomplish this, I just do not understand how to implement them correctly. That code is not posted, but if anyone is interested in helping solve that problem, Ill be happy to post it.
#include <iostream>
#include <iomanip>
#include <string>
#include <fstream>
#include <sstream>
#include <cstdio>
using namespace std;
int main()
{
int z = 0;
const int WRONGQUESTIONS = 20;
int wrongCounter[WRONGQUESTIONS];
const int QUESTIONS = 20;
const int STUDENT_QUESTIONS = 100;
ifstream inputFile;
inputFile.open("CorrectAnswers.txt");
char correctAnswers[QUESTIONS];
for (int i=0; i<20; i++)
{
inputFile >> correctAnswers[i];
}
ifstream inputFile2;
inputFile2.open("StudentAnswers.txt");
char studentAnswers[STUDENT_QUESTIONS];
for (int t=0; t<STUDENT_QUESTIONS; t++)
{
inputFile2 >> studentAnswers[t];
}
int answeredCorrectly = 0;
for(int c = 0; c < 5; c++)
{
int z = 0;
//now we use a for loop to go through the questions and store whether the answer was right or wrong
for (int x = 0; x < QUESTIONS; x++)
{
if (studentAnswers[x] == correctAnswers[x])
answeredCorrectly++;
else
wrongCounter[z]++;
z++;
}
cout << "Report for Student " << c+1 << ":" << endl;
cout << "---------------------" << endl;
cout << "Missed " << 20 - answeredCorrectly << " out of 20 questions for " << (answeredCorrectly / 20) * 100 << "% correct." << endl;
cout << "Answered Correctly: " << answeredCorrectly << endl;
cout << "Questions missed:" << endl << endl;
}
}
I think I've found the a problem
while (badEntry = true)
use ==
while (badEntry == true)
There are other issues too
while (badEntry = true)
{
cout << "Invalid entry" << endl;// I GET AN INFINATE LOOP HERE????
if (studentAnswers[x] == A || B)
badEntry = false;
}
First off, what if none of the studentAnswers are equal to A or B?
Secondly, I think you want your if condition to be the following
if (studentAnswers[x] == A || studentAnswers[x] == B)
You miss one "=" in "while (badEntry = true)". Should be "while (badEntry == true)". And in fact, you can do "while (badEntry)".
Same mistake for "if (studentAnswers[y] = 'N')".
To avoid such problems, you should always put the constant first. For example, do "if ('N' == studentAnswers[y])".
This isn't the main issue, other people have already posted the real problem. However, this also happens to make your program not work properly.
if (studentAnswers[x] != A || B) is an interesting conditional.I imagine you were testing if studentAnswers[x] wasn't equal to either A or B. You can't say this in C++ or with (what I aware of) most languages. Your statement would parse to if((studentAnswers[x] != A) || B). ( != comes before || in binary operator precedence). To fix this, just create a != check for both A and B.
It should look like this: if (studentAnswers[x] != A || studentAnswers[x] != B).
The same goes for ==.
Just looked up to see that "Sam I am" put this in his answer already. Sorry about that.
Anyways, be wary of your boolean test, that seems to be what screwed up most of the program.
EDIT: Looks like "TonyArra" also said the same thing, oops. Well at least you'll remember now.
Couple of problems: while (badEntry = true) will set badEntry to true every time it checks the conditional. So it ends up checking while(true) (aka infinite loop). As others have said, use while(badEntry)instead.
Furthermore, if (studentAnswers[x] == A || B) is also incorrect. It should be: if ( (studentAnswers[x] == 'A') || (studentAnswers[x] == 'B') )
Furthermore, if (studentAnswers[x] == 'A' || 'B') is interpreted as:
if ( (studentAnswers[x] == 'A') || ('B') ) which will come out to true every time because 'B' is non-null. You were also missing the quotations around the letter to denote it as a character.
You may find this helpful: http://www.cplusplus.com/forum/articles/3483/