Static scoping in C/C++ - c++

In the following code, 2 is printed.
int x = 1;
int f(int y)
{
return x;
}
int main() {
x = 2;
printf("%d", f(0));
}
How is it happening if we have static scoping in C? Why isn't 1 printed?
Printing 2 in this case isn't a dynamic scoping, is it?
I thought that in static scoping it should take the nearest x to the function definition.

It does take the nearest x, but since you only have one x it doesn't really matter.
If you change the code to
int x = 1;
int f(int y)
{
return x ;
}
int main() {
int x=2;
printf("%d", f(0));
}
so you have 2 x, the global one and the local one in main you will see 1 getting printed.

Those are usually called dynamic and lexical scoping.
Lexical scoping is determined entirely at compile time, dynamic scoping at runtime.
You only have one variable named "x", so scope is irrelevant to your program.
Here's a program that would be different depending on the scoping rules:
int x = 0;
int f()
{
return x;
}
int main()
{
int x = 1;
printf("%d\n", f(x));
}
Under lexical scoping, f returns the value of the x that is lexically "nearest" - the global one.
So it would print 0;
Under dynamic scoping, f would return the value of the newest x, which is the one in main.
So it would print 1.

The scoping is moot here since you have not declared an x locally that would have otherwise shadowed the global x.
2 is printed.
x is assigned in main to 2 immediately before f is called with the parameter 0.
(Conceptually int x = 1; is ran before main is entered.)

It is the way the compiler generates the assembly/machine code.
first global variable X is stored in memory location "abc"
next main is executed: global variable X at "abc" is changed to 2
Now function f() is called:
function f returns the value of global variable X at "abc": being 2
the return value of f() is printed.
So if you wanted a different X in the main-function scope, you should have made a new object, like in the answer by nwp.

Related

When is a variable in a nested scope destroyed from the memory?

void main() {
int x=5;
{
int x= 6;
cout<<x;
}
cout<<x;
}
the output is 6, 5.
My question is: when Assign x to 6, it reserved a memory cell for it, and then entered the nested block here( the old x is destroyed!! Or how it can defined two variables for the same name?
how it can defined two variables for the same name?
The two x in your example exists in different scopes. When you defined the inner x, it hides the x from outer scope. See the comments in the below given program.
int main()
{//---------------------------->scope1 started here
//------v---------------------->this variable x is in scope1
int x=5;
{//------------------------>scope2 started here
//----------v------------------>this variable x is in scope2
int x= 6;
//------------v---------------->this prints scope2's x value
cout<<x;
}//------------------------>scope2 ends here and x from scope2 is destroyed
//--------v---------------->this prints scope1's x value
cout<<x;
}//---------------->scope1 ends here
Also, the inner scope x is destroyed when that scope ends. Moreover, the inner scope x and outer scope x occupy different addresses in memory.
The output of the above program is 65 which can be seen here.
Additionally, note that void main() is not standard C++, you should instead replace it with int main() as shown in my above snippet.

My division function returns a zero. Should I declare x differently in main?

#include <iostream>
using namespace std;
int division(int c, int d);
int x = 2;
int y = 2;
int division(int c, int d)
{
return (c/d);
}
int main()
{
cout << "Hello World!\n";
int x = division(x,y);
cout << x;
return 0;
}
I expected the code to show 1 after Hello World!, but it prints 0.
I removed int from in front of x (in main()) and ran it again and it returned 1.
But I also passed x,x to the division function with the int in front of x (in main()) and it returned 1.
So I am not sure how the assignment statement is working.
This expression:
int x = division(x,y);
is equivalent to writing this:
// 'x' was defined globally somewhere here before
int x;
x = division(x, y);
This shadows the previous x variable defined globally and defines a local variable x which again is uninitialized so after passing it in the division() function, your code has Undefined Behavior. (When that happens, the output can be anything, it can be 0, it can even be 1 or something else entirely.)
What you want to do is to remove the declaration and turn it into an assignment instead:
x = division(x,y);
Then the above works properly and gives 1.
You should compile your code at least with -Wall flag.
You would then see a helpful warning message:
foo.cpp: In function ‘int main()’:
foo.cpp:17:21: warning: ‘x’ is used uninitialized [-Wuninitialized]
17 | int x = division(x,y);
| ~~~~~~~~^~~~~
It means that to the division() isn't passed global x, but the local one from main().
It's undefinied behaviour, no different than int z = division(z,y);
After removing int from before x in main() you no longer declare local variable, thus there is only one x in your program (the global one) and from initialization the line turns into plain assignment.

Why can't my function access and modify the variable passed to it?

i have written this little program to explain my point and my variable a remains unchanged it prints 4. I later learned that I need to use pointers or references; why is that?
#include <iostream>
void setToTen(int x) { x = 10; }
int main(){
int a = 4;
setToTen(a);
std::cout << a << std::endl;
}
In C++ arguments to functions are passed by value. This means that when you write
setToTen(a);
the parameter int x in setToTen is given a copy of the value stored in the variable a. In other words, you're not actually handing off the variable a into the setToTen function. Instead, you're giving a copy of that value to setToTen, so the changes made in that function affect the copy rather than the original.
On the other hand, if you change setToTen so that it takes its parameter by reference, like this:
void setToTen(int& x) {
x = 10;
}
the story is different. Here, calling setToTen(a) essentially hands the variable a into the function setToTen, rather than a copy of the value. That means that changes made to the parameter x in setToTen will change the variable a.
Your code requests a copy of x by having the signature void setToTen(int x).
Being able to take things by copy means that reasoning about the behavior of a function is far easier. This is true both for you, and for the compiler.
For example, imagine this:
int increase_some( int x, int y, int z ) {
for (int i = 0; i < y; ++i )
x+=z;
return x;
}
because x y and z are copies, you can reason about what this does. If they where references to the values "outside" of increase_some, the bit where you x+=z could change y or z and things could get crazy.
But because we know they are copies, we can say increase_some returns x if y<=0, and otherwise returns x+y*z.
Which means that the optimizer could change it to exactly that:
int increase_some( int x, int y, int z ) {
if (y<=0) return x;
return x + y*z;
}
and generate that output.
This is a toy example, but we took a complex function and turned it into a simple one. Real optimizers do this all the time with pieces of your complex function.
Going one step further, by taking things by immutable value, and never touching global state, we can treat your code as "functional", only depending on its arguments. Which means the compiler can take repeated calls to a function and reduce them to one call.
This is so valuable that compilers will transform code that doesn't have immutable copies of primitive data into code that does before trying to optimize -- this is known as static single assignment form.
In theory, a complex program with lots of functions taking things by reference could be optimized this same way, and nothing be lost. But in practice that gets hard, and it is really easy to accidentally screw it up.
That is the other side; making it easier to reason about by people.
And all you have to embrace is the idea of taking arguments by value.
Function parameters are function local variables that are not alive after exiting function.
You can imagine the function definition and its call
int a = 4;
setToTen(a);
//...
void setToTen(int x) { x = 10; }
the following way
int a = 4;
setToTen(a);
//...
void setToTen( /* int x */ ) { int x = a; x = 10; }
As it is seen within the function there is declared a local variable x which is initialized by the argument a. Any changes of the local variable x do not influence on the original argument a.
If you want to change the original variable itself you should pass it by reference that is the function will deal with a reference to the variable. For example
void setToTen(int &x) { x = 10; }
In this case you can imagine the function definition and its call the following way
int a = 4;
setToTen(a);
//...
void setToTen( /* int x */ ) { int &x = a; x = 10; }
As you see the reference x is as usual local. But it references the original argument a. In this case the argument will be changed through the local reference.
Another way is to declare the parameter as pointer. For example
void setToTen(int *x) { *x = 10; }
In this case you have to pass the original argument indirectly by its address.
int a = 4;
setToTen( &a );

Using a variable with the same name in different spaces

This code compiles, but I have a run time error in Visual Studio:
Run-time check failure #3 - the variable 'x' is being used without being initialized...
int x = 15;
int main()
{
int x = x;
return 0;
}
I don't understand that behavior... in the error box when I click continue the program resumes and x has a corrupted content (like -8556328 instead of 15).
Why does this code work without a problem, and the int array is well declared?
const int x = 5;
int main()
{
int x[x] = {1,2,3,4};
return 0;
}
x is defined at the left of =.
so in x[x], [x] refer to the global one,
whereas in x = x;, x hides the global x and initializes from itself -> UB.
When you declare a new variable, its name becomes visible right here
int x =
// ^- there
because it is at that point the variable is fully declared, and as such; its name means something. At this point in time any other (previously declared variable) in a surrounding scope will be hidden.
There is no scope resolution operator in C, so you may not be able to use
int x = x;
in your program.
please use SRO( Scope resolution operator ::) to tell compiler which x is real x in your mind. As user defined names are mangled( Names are decorated) something like this to avoid ambiguity at it's level, these are just names used by compiler that best suits it
int x = 15;// Real name = gui_x
int main()
{
int x = x;// lui_x
return 0;
}
In this way run-time will know which version you are using but to avoid ambiguity it expects from you to use specific names. Sometimes above problem arise where you don't know that you are using already used names. For this C++ has created SRO.
Now in case of array x is address & not integer that stores something, that's why compiler didn't jumbled. You need to write
namespace abc //now all global variables are belongs to this ns abc
int x = 15;// Real name = gui_x
int main()
{
int x = abc::x;// lui_x
return 0;
}

C++ Defining Global Variable

Very simple question:
I was fiddling with basic C++ (being very new to programming) and I got into trouble while declaring a global variable to do some addition
#include <iostream>
int x,y;
int sum(int, int)
{
return x + y;
}
int main()
{
using namespace std;
cout << "The sum of 10 and 4 is: " << sum(10,4) << endl;
return 0;
}
Changing "int x,y;" to "int x,y = 0" has the same result: The sum equates to 0.
Could someone explain this odd behavior? Thanks!
Your function always returns the sum of global variables x and y, which are always 0. x and y are implicitly set to zero at the program startup. You never change their values, so they remain zero forever. The sum of two zeros is zero, no surprise here.
You pass 10 and 4 to your function, but the function itself completely ignores what is passed to it, i.e. it ignores its parameters (they are not even named). It always sums global x and y, which are always 0.
If you want your function to sum its arguments, you have to name the function parameters and use them
int sum(int a, int b)
{
return a + b;
}
And now you don't need any global variables at all. (main remains as is.)
Alternatively, if you so desire, you can get rid of the parameters completely and sum the global variables instead
int x,y;
int sum()
{
return x + y;
}
but in this case you will have to pass the values to sum through those global variables, not as function arguments
int main()
{
using namespace std;
x = 10;
y = 4;
cout << "The sum of 10 and 4 is: " << sum() << endl;
return 0;
}
This latter approach is here just for illustrative purposes. It is definitely not a good programming practice.
What you have in your code is a weird disconnected hybrid of these two approaches, which can't possibly work.
In order to fix the issue, the thing requires changing is the sum function.
int sum(int a, int b){
return a+b; //a,b here are referring to the inputs, while what you did was referring to the global variable..
}
Besides, try not to use global variables, usually you would end up with lots of troubles.
Another thing, I don't think your way of defining a function is correct. The inputs have to look like this instead:
int sum(int a, int b)
Unless you wanna declare the function first and provide the actual implementation later, you are not suppose to miss the name of the inputs!
when you are just globally declare the variables x,y ,they implicitly set to zero value.in your function definition,you are just giving the datantype of args, not the args names.so when you returning the sum of x,y ,it returns zero.and the value passed by the main function goes nowhere.
your program must look like this
#include<iostream>
int x,y;
int sum(x,y)
{
return x+y;
}
int main()
{
int v,a,b;
cout<<"values of a and b";
cin>>a>>b;
v=sum(a,b)
cout<<"their sum is"<<v;
}
when you explicitly define the value in second case
i.e int x,y=0;
you are just explicitly giving the value of value y to 0 while the x implicitly remains 0 and since you are not giving the args name,the ultimately result return biy the function is zero,
Seems that you only need x and y inside your add function, so make them local to the function. There is no reason to make them global. Follow the "least accessibility" idiom to prevent other parts of your program from mistakenedly modifying variables.
You might need a global variable supposed you want to define a well known parameter that every function needs to know and yet modifiable during run time. If you want it fixed, then a global constant would be more proper.
Hope that helps.