I am confused about variable scope and would like to better understand it.
Moved cout oddS and cout evenS to outside for loop. Code executes properly. If moved inside for loop, code executes with improper values for oddS and evenS.
#include <iostream>
#include <vector>
#include <cmath>
int main()
{
double evenS, oddS, pH = 0;
std::vector<double> v1 = {2, 4, 3, 6, 1, 9};
for(int i = 0; i < v1.size(); i++)
{
pH = v1[i];
if(fmod(pH, 2) == 0)
{
evenS = evenS + v1[i];
}
else if(fmod(pH, 2) == 1)
{
oddS = oddS + v1[i];
}
}
std::cout << evenS << "\n";
std::cout << oddS << "\n";
}
I was expecting the oddS and evenS to not hold the proper values if incremented outside of the for loop. However, the contrary is true, which produced my confusion.
Your code has Undefined Behaviour (it contains a bug), which means it can do literally anything. It makes little sense to try to analyse why moving statements around changes output, or how [counter-]intuitive they are.
The problem is in the fact that your variables evenS and oddS are not initialised, and you're reading their values before writing to them. Reading an uninitialised value is UB.
You probably meant to write this as the definition:
double evenS = 0, oddS = 0, pH = 0;
Each variable being declared in a declaration needs its own initialiser if it is to have one.
As #Angew mentioned, you have a bug in your code and he suggested a fix. The following topic is helpful to understand uninitalized values: What happens to a declared, uninitialized variable in C? Does it have a value?
As for variable scope, if you bring std::cout << evenS << "\n"; and std::cout << oddS << "\n"; into the loop, the values of evenS and oddS would be printed more frequently.
Here's an explanation of scope from Tutorials Point (annotations in square brackets):
A scope is a region of the program and broadly speaking there are three places, where variables can be declared −
Inside a function or a block which is called local variables. [Here block means a portion of code starting and ending on these brackets {}]
In the definition of function parameters which is called formal parameters.
Outside of all functions which is called global variables.
Local Variables
Variables that are declared inside a function or block are local variables. They can be used only by statements that are inside that function or block of code. [if you try to access outside either compiler will give you an error.]
Global Variables
Global variables are defined outside of all the functions, usually on top of the program. The global variables will hold their value throughout the life-time of your program.
Now in your case as you said
Moved cout oddS and cout evenS to outside for loop. Code executes
properly. If moved inside for loop, code executes with improper values
for oddS and evenS.
If you declare variable inside for loop, its scope will remain within that block (within that loop).
Related
Below is a code snipped with 3 nested loops. Variables curs and tempv are getting redeclared at each iteration of the outermost for-loop. This should have given me error but I am able to run it successfully without errors on gcc 4.8.4.
for(int i = 0; i<lend; i++)
{
string curs = vstring[digits[i]-'0'];
vector<string> tempv;
for(int j = 0; j<v.size(); j++)
{
for(int k = 0; k<curs.size(); k++)
{
tempv.push_back(v[j] + curs[k]);
}
}
v = tempv;
}
Is it fine to redeclare variables within for-loop? I have an understanding that in C++ a variable cannot be redeclared in the same scope.
Is it fine to redeclare variables within for-loop? I have an understanding that in C++ a variable cannot be redeclared in the same scope.
It's one single lexical scope, where these variables are declared once. The fact that the execution enters it repeatedly is irrelevant - it's not like you get duplicate definition errors for variables that are declared in a function that gets called many times. As always, each time you enter a scope you get a new instantiation of variables defined in it.
In other words: scoping rules are about the static, lexical structure of the program, which is unrelated to how the program flow of execution will actually happen; they act as a blueprint for its runtime behavior, in that they instruct the compiler about how to parse the rest of the block and what code to generate for each time the scope is entered.
” Variables curs and tempv are getting redeclared at each iteration of the outermost for-loop
No, they're getting instantiated at each iteration. Created, and at the end of the block, destroyed. Modulo optimization done by the compiler.
Scopes are a compile time notion. Something you see by inspection of the code. Instantiations are a run-time effect. The same variable declaration can be executed any number of times, instantiating the variable that number of times. Well, except if it's static, in which case it's instantiated once.
” I have an understanding that in C++ a variable cannot be redeclared in the same scope.
It cannot be redeclared directly in the same scope, but it can be redeclared in a nested scope. And you have a number of nested scopes. Let's consider them:
for(int i = 0; i<lend; i++) // ← For loop scope.
{ // ← Block scope.
string curs = vstring[digits[i]-'0'];
vector<string> tempv;
for(int j = 0; j<v.size(); j++) // ← For loop scope.
{ // ← Block scope.
for(int k = 0; k<curs.size(); k++) // ← For loop scope.
{ // ← Block scope.
tempv.push_back(v[j] + curs[k]);
}
}
v = tempv;
}
Formally the for loop is defined by an equivalence to a corresponding while loop placed in an outer block that contains the declaration of the loop variable, if any. However,
C++17 §6.3.3/1:
” Names declared in the init-statement, the for-range-declaration, and in the condition of if, while, for, and
switch statements are local to the if, while, for, or switch statement (including the controlled statement),
and shall not be redeclared in a subsequent condition of that statement nor in the outermost block (or, for
the if statement, any of the outermost blocks) of the controlled statement; see 9.4.
For example, in your code the outer for loop's i cannot be redeclared directly in the block that constitutes that loop's body, even though it's a nested scope, but can be redeclared in the inner nested loop.
This is perfectly legal, and in fact, it is used all the time. Each iteration can be viewed as a brand new scope in this context.
What would be the difference of declaring i at the beginning of the program
int a, b, c, i;
vs in the for loop
for (int i=0;i<=n;i++)?
I developed a habit to declare it in the for loop and I don't know if that's fine (I'm better at JS and I encountered many problem in my programs because of this, but in C++ I didn't.)
Thanks a lot.
It depends.
Most of the time it's OK to use
for (int i = 0; i <= n; i++) { ... }
However, sometimes you want to know the value of i when the loop ended. In that case, you would need to declare the variable before the for loop.
int i = 0;
for ( ; i <= n && (some other tests); i++ ) { ... }
// Do different things based on the value of i.
if ( i == n+1 )
{
dothis();
}
else
{
dothat();
}
This is a scope problem. If you define int a before the loop, you can use it in and outside the loop. When you define it inside the loop you can only use it inside the loop.
Here is a nice article about Scope in the MSDN
ps.: Your loop doesn't work, unless you define and initalize the n variable
It depends. If you don't need i after the loop (the scope will only be the for loop) then declare it in the for loop. If you need it after the loop (the scope is the block of code your in) then you must declare it outside and before the loop.
When int i is declared outside the for loop, it can be accessed outside the for loop and inside but when you define it inside the loop, it can only be used inside the loop. Usualy, if you need it for the for loop define it inside the loop.
I was always under the impression that a variable declared in any kind of loop statement is scoped to that statement alone. And a little poking around in similar questions seems to confirm this idea. So I am puzzled by the following excerpt from Stroustrup's A Tour of C++ (§4.2.3 Initializing Containers p. 38):
"The push_back() is useful for input of arbitrary numbers of elements. For example:
Vector read(istream& is) {
Vector v;
for (double d; is>>d;) // read floating-point values into d
v.push_back(d); // add d to v
return v;
}
The input loop is terminated by an end-of-file or a formatting error. Until that happens, each number
read is added to the Vector so that at the end, v’s size is the number of elements read. I used a for-statement rather than the more conventional while-statement to keep the scope of d limited to the loop."
This seems to imply that variables declared in the condition of a while statement persist outside the statement body.
Let's examine that loop:
for (double d; is>>d;) // read floating-point values into d
v.push_back(d); // add d to v
Here we have:
a declaration of d
a loop condition
an empty "do on each iteration" expression
And, yes, d is limited in scope to the for loop.
Now try writing a while loop to do the same job, keeping d limited in scope. You won't be able to, because there's no place to put a declaration in the preamble of a while. Only for has that feature. A while only has a condition.
That doesn't mean the scoping rules are different for while; it only means that it is not possible to write this code using while. There aren't any "variables declared in the condition of a while statement".
[..] that variables declared in the condition of a while statement [..]
That's not possible.
Using a for statement allows to declare a variable like this
for(int a = 0; a < 5; a++) {
// Use a
}
// a is not visible anymore
If you use a while loop, it is visible
int a = 0;
while(a < 5) {
// Use a
a++;
}
// a still visible
I wanted to create a function that would define an 1d Array, calculate a sum of the elements, and display that sum. I wrote the following code however I'm unaware of the use of pointers and other advanced techniques of coding.
#include <iostream>
using namespace std;
int main()
{
int size;
int A[];
cout << "Enter an array: \n";
cin << A[size];
int sum;
int sumofarrays(A[size]);
sum = sumofarrays(A[size]);
cout << "The sum of the array values is: \n" << sum << "\n";
}
int sumofarrays(int A[size])
{
int i;
int j = 0;
int sum;
int B;
for (i=0; i<size; i++)
{
B = j + A[i];
j = B;
}
sum = B;
return(sum);
}
When attempting to compile this code, I get following error:
SumOfArrays.cpp:19:18: error: called object type 'int' is not a
function or function pointer sum = sumofarrays(size)
If only you had used a container like std::vector<int> A for your data. Then your sum would drop out as:
int sum = std::accumulate(A.begin(), A.end(), 0);
Every professional programmer will then understand in a flash what you're trying to do. That helps make your code readable and maintainable.
Start using the C++ standard library. Read a good book like Stroustrup.
Please choose Bathsheba's answer - it is the correct one. That said, in addition to my comment above, I wanted to give some more tips:
1) You need to learn the difference between an array on the stack (such as "int A[3]") and the heap (such as a pointer allocated by malloc or new). There's some degree of nuance here, so I'm not going to go into it all, but it's very important that you learn this if you want to program in C or C++ - even though best practice is to avoid pointers as much as possible and just use stl containers! ;)
2) I'm not going to tell you to use a particular indentation style. But please pick one and be consistent. You'll drive other programmers crazy with that sort of haphazard approach ;) Also, the same applies to capitalization.
3) Variable names should always be meaningful (with the possible exception of otherwise meaningless loop counters, for which "i" seems to be standard). Nobody is going to look at your code and know immediately what "j" or "B" are supposed to mean.
4) Your algorithm, as implemented, only requires half of those variables. There is no point to using all of those temporaries. Just declare sum as "int sum = 0;" and then inside the loop do "sum += A[i];"
5) Best practice is - unlike the old days, where it wasn't possible - to declare variables only where you need to use them, not beforehand. So for example, you don't need to declare B or j (which, as mentioned, really aren't actually needed) before the loop, you can just declare them inside the loop, as "int B = j + A[i];" and "int j = B;". Or better, "const int", since nothing alters them. But best, as mentioned in #4, don't use them at all, just use sum - the only variable you actually care about ;)
The same applies to your for-loop - you should declare i inside the loop ("for (int i = ....") rather than outside it, unless you have some sort of need to see where the loop broke out after it's done (not possible in your example).
6) While it really makes no difference whatsoever here, you should probably get in the habit of using "++i" in your for-loops rather than "i++". It really only matters on classes, not base types like integers, but the algorithms for prefix-increment are usually a tad faster than postfix-increment.
7) You do realize that you called sumOfArrays twice here, right?
int sum;
int sumofarrays(A[size]);
sum = sumofarrays(A[size]);
What you really meant was:
const int sum = sumofarrays(A);
Or you could have skipped assigning it to a variable at all and just simply called it inside your cout. The goal is to use as little code as possible without being confusing. Because excess unneeded code just increases the odds of throwing someone off or containing an undetected error.
Just don't take this too far and make a giant mishmash or trying to be too "clever" with one-liner "tricks" that nobody is going to understand when they first look at them! ;)
8) I personally recommend - at this stage - avoiding "using" calls like the plague. It's important for you to learn what's part of stl by having to explicitly call "std::...." each time. Also, if you ever write .h files that someone else might use, you don't want to (by force of habit) contaminate them with "using" calls that will have an effect on other peoples' code.
You're a beginner, that's okay - you'll learn! :)
I started to read a book about C++ and found the following code.
It is an example on how you can send pass parameters by reference.
#include <iostream>
void swap(int &x, int &y);
int main()
{
int x = 5, y = 10;
std::cout << "Main. Before swap, x: " << x
<< " y: " << y << "\n";
swap(x, y);
std::cout << "Main. After swap, x: " << x
<< " y: " << y << "\n";
return 0;
}
void swap(int &rx, int &ry)
{
int temp;
std::cout << "Swap. Before swap, rx: " << rx
<< " ry: " << ry << "\n";
temp = rx;
rx = ry;
ry = temp;
std::cout << "Swap. After swap, rx: " << rx
<< " ry: " << ry << "\n";
}
.
Main. Before swap, x:5 y: 10
Swap. Before swap, rx:5 ry:10
Swap. After swap, rx:10 ry:5
Main. After swap, x:10, y:5
The logic is clear to me.
Now this may be a very stupid question (I'm not very experienced yet), but why can't you just declare private: int x as an instance variable? Isn't x in this case directly accessible everywhere in your class? (without the need for specifying parameters at all)? Thanks in advance for your answers!
For several reasons.
You should declare variables at the narrowest scope possible. Why? Look at 2 & 3
Variables are expensive, they take up memory, you only want them
around as long as you need them.
The greater a variables scope (i.e. how much code the variable is visible
to) the greater the chance that you will mistakenly use the
variable, and therefore it's value may change unexpectedly. This will be a bug, good luck hunting that one down.
Tight coupling (this is bad). If you write a class and put a swap method on the
class, and you write it so it uses instance member x (not method
variable x), then that swap method CAN ONLY EVER swap using x, if
in time you need it to swap on a different variable (or the
parameter of another method on the class) then you've to move the
value into x which is Inefficient & goto 5. Isn't it better to call the swap function with the values you have to hand, without needing to know there's a special x variable that you have to set first?
Error prone. Will this second method be called while another method
is using the swap method? What should the value of x be after it's
called? You're introducing lots of context around swap and knowing when it's
ok to call swap, and what can call swap. This is bad, the more self contained any piece of code is, then the less of have to worry about it, and about how it's used.
No other class can re-use your swap method, every class that needs a
swap method must implement it's own, and this is a huge big
no-no for more reasons than I can count here, but can sum up as it
voliates the DRY Principal
All of these problems can be removed by simply passing the values by reference. Bit of a no-brainer really :)
Hope this helps.
Passing values via arguments to a function ensures modularity in your code. It sounds like you're just starting out with C++, so I'm not sure how familiar you are with object oriented programming. Functions/methods represent a layer of encapsulation. Your swap() function should encapsulate the logic needed to perform its function/purpose. The caller should not be concerned with how this is accomplished. If your swap() function must assert there is a global variable available in the program, then it's not fully encapsulating the logic of "swapping".
Also, Lets say you wanted to reuse this function elsewhere in your class. It would be difficult and clumsy to use a set of global variables for calling this function. In addition, you may have other locations in your class that are referencing those global variables, and therefore your other calls to swap() would change those values, potentially causing confusion in other areas of the code.