c: Style: altering variables in place - c

Suppose we have something along these lines
int f(int n);
....
do{
int a = b;
int b = f(a);
}
Is there any risk to saying
do{
int b = f(b);
}
instead, assuming a is not used elsewhere? Would it be stylistically preferable to do the former?

It is important to understand that you're not "altering" any variables here, just changing the meaning of a name.
The important concept is called the point of declaration.
Let's look at your example:
int b = 42;
{
int a = b;
int b = 23 * a;
printf("%d\n", b);
}
printf("%d\n", b);
or
int b = 42;
{
int b = 23 * b;
printf("%d\n", b);
}
printf("%d\n", b);
The name b references two objects, depending on where you are in the code, let's call them b1 and b2. This is unsurprising in case 1:
int b1 = 42;
{
int a = b1;
int b2 = 23 * a;
printf("%d\n", b2);
}
printf("%d\n", b1);
Since in C the point of declaration is before the initializer, the second example resolves differently:
int b1 = 42;
{
int b2 = 23 * b2;
printf("%d\n", b2);
}
printf("%d\n", b1);
Note that here there's no link between b1 and b2, you're initializing b2 with its own (undefined) value. A diligent compiler will warn you about this, like
x.c:7:13: warning: 'b' is used uninitialized in this function [-Wuninitialized]

As the compiler parses C code it populates a symbol table, this table contains information about all the different symbols and by symbols I mean identifiers, such as the names you give your variables, functions, and so forth ...
Most C programs are constructed out of nested scopes, global -> function -> component_statements and so on, each scope usually has its own symbol table, so the compiler uses a stack of symbol tables to keep track of everything, when a variable is looked up but isn't defined in the current symbol table it starts the search by going upward the stack until it hits global or usually last table ... but as soon one is defined in the current scope an entry is made 'shadowing' the previous.
heres a simple program to illustrate.
#include <stdio.h>
/* global accessable by most things ... */
int a = 5;
int main()
{ /* function scope */
int a = 4; /* shadowing global */
{ /* nested scope within function scope */
int b = a;
int a = b; /* shadowing function */
printf("%i\n", a);
}
return 0;
}
if you run this you would get 4 which is to be expected but anyone following your code would have to keep in the back of their mind that a is different from all the other a from global, function main ... If the programmer maintaining the code isn't aware of this things or you yourself forgot then you can have subtle run-time bugs that can be quite hard to debug ...
also note that if you run this:
#include <stdio.h>
/* global accessable by most things ... */
int a = 5;
int main()
{ /* function scope */
int a = 4; /* shadowing global */
{ /* nested scope within function scope */
int a = a; /* shadowing function, but not actually accessing outer scope */
printf("%i\n", a);
}
return 0;
}
you wouldn't get 4 but some large random int on my machine its 1606422610 since the variable is being assigned to itself that was just shadow, and c doesn't initialize variables.

Related

Why does the int keyword have an effect on the variable value when changing a variable

If I do something like this:
int a = 1;
int b = 2;
a = a + b;
a gives 3 in this instance, however if I do something like this:
int a = 1;
int b = 2;
int a = a + b
a gives a very large number (1827585825)
Can anyone explain why this occurs?
Redefinition of variable as you attempted is not allowed in C, and fails to compile. However, a slightly modified version of your code does compile:
int main() {
int a = 1;
int b = 2;
{
int a = a + b;
// use a
}
return 0;
}
int a = a + b is valid, but doesn't mean what you think it does. The a in a + b refers to the inner and as-yet uninitialized variable a, and not to the outer a. Using it in an expression is undefined behavior and results in garbage output.
Your code is invalid and it will not compile at all.
The second a definition has to be in a different scope like in the example below.
#include <stdio.h>
int a = 1;
int b = 2;
int main(void)
{
int a = a + b; //declares new a variable which has undetermined value
}
The second definition of a hides the global one and newly defined int variable will not be initialized. You take this not initialized variable (having undetermined value) and add another value to it. The result will also undetermined. It is Undefined Behaviour.
https://www.tutorialspoint.com/cprogramming/c_scope_rules.htm

C Rules for Compound Declaration and Global Variables [duplicate]

I'm a little Confused about this code result:
#include <stdio.h>
int g;
void afunc(int x)
{
g = x; /* this sets the global to whatever x is */
}
int main(void)
{
int g = 10; /* Local g is now 10 */
afunc(20); /* but this function will set it to 20 */
printf("%d\n", g); /* so this will print "20" */
return 0;
}
Why the result is 10 Not 20 ?
The local variable g shadows the global g.
If you want the printf() to show 20, you have to shadow your local variable g with a declaration of the global one you want to print:
int main(void)
{
int g = 10; /* Local g is now 10 */
afunc(20); /* Set global g to 20 */
printf("%d\n", g); /* Print local g, "10" */
{
extern int g; /* Use global g */
printf("%d\n", g); /* Print global g, "20" */
}
return 0;
}
Calling afunc changes the global g, and main retains its local g.
Entering a function doesn’t swap its scope with the global scope. Each function* has its own scope.
* Among other things
If you get rid of the int in
int g = 10;
then main will also be referring to the same global variable as afunc is.
This is called variable shadowing
Have NOT modified your code, but have adjusted your comments to indicate what the code is doing. By the way, commenting your code is a really good idea and makes for better lab scores!! signed, A Former Graduate TA
#include <stdio.h>
int g; /* define a global variable
void afunc(int x)
{
g = x; /* this sets the global to whatever x is */
}
int main(void)
{
int g = 10; /* Define and set a Local g to 10 */
afunc(20); /* This function sets global x to 20 */
printf("%d\n", g); /* this prints local g "10" */
return 0;
}
To think about this "look-up" from main to global storage. You see local g before global g, thus local g is used.
In both the occasions, though the variable name appears to be same, they 2 are referring 2 different memory area. The variable g declared outside any function got stored in the RAM memory area, and the variable g declared inside main is got stored in stack area. So the invocation of afunc() is changing the variable g stored in RAM but again printing the variable g(stored in stack) which got declared locally.

Do cycles have their own stack record? (aka why is this code legal)

Ok, so I'm having a little question for you here.
I'm going to write code in C, but I guess this would work just the same in most languages.
So, why is this code legal:
int x = 1;
while(true) {
int x = x + 2;
}
While this calls for error: redefinition of ‘x’
int x = 1;
int x = 3;
So, I am aware that I'd be able to use the same name for a variabile in different functions within my program, since each function call would have its own stack record.
But do cycles have their own stack records as well? On a memory level, code #1 doesn't result in me having N different associactions for the variable x within the same stack record block?
In short, why in code #2 I'm redefining the x variable, but in code #1 I am not?
The two variables are declared in different scope.
int x = 1;
while(true) {
int x = x + 2;
}
The variable declared in the inner scope hides the variable declared in the outer scope.
Pay attention to that this declaration
int x = x + 2;
has undefined behavior because the declared variable is used itself as an initializer though it was not initialized.
For example you can write
int x = 1;
int main( void )
{
int x = 2;
while ( 1 )
{
int x = 3;
/*...*/
}
}
In this program there are declared and defined three different objects with the name x.
The first variable has the file scope while the other two have block scopes.
As for this code snippet
int x = 1;
int x = 3;
two variables in the same scope are defined with the same name.
In C (but not in C++) you may write
#include <stdio.h>
int x;
int x = 1;
int main(void)
{
return 0;
}
because in the file scope this
int x;
is not a definition of the variable x but is only its declaration.
Also you may write for example
#include <stdio.h>
int x;
int x = 1;
int main(void)
{
extern int x;
printf( "x = %d\n", x );
return 0;
}
The line
extern int x;
introduces the declaration of the global variable x in the block scope of main.
As for the while statement then (The C STandard, 6.8.5 Iteration statements
)
5 An iteration statement is a block whose scope is a strict subset of
the scope of its enclosing block. The loop body is also a block whose
scope is a strict subset of the scope of the iteration statement.

Is variable declaration necessary in C?

See the comments to see what is being referred as declaration.
If the whole variable declaration part was missing, what would be the problem?
Appears that variable definition and initialization either simultaneously or separately like in the example would suffice.
#include <stdio.h>
// Variable declaration:
extern int a, b;
extern int c;
extern float f;
int main () {
/* variable definition: */
int a, b;
int c;
float f;
/* actual initialization */
a = 10;
b = 20;
c = a + b;
printf("value of c : %d \n", c);
f = 70.0/3.0;
printf("value of f : %f \n", f);
return 0;
}
If the declaration was missing then it would create no problem in main function since the locally defined variables i.e. a,b,c,f will be used in the functionality of main till its scope ends.
The declaration merely tells that the definition lies elsewhere (in some other .c file) or the definition lies after the function main in the same .c file.
There will be no problem here if the mentioned declaration is missing.
// Variable declaration:
extern int a, b;
extern int c;
extern float f;
This tells the compiler that these variables are defined somewhere else(in another file).
/* variable definition: */
int a, b;
int c;
float f;
This is where you define variables but they are not the same as the external variables you declared since they are in the inner scope of the main function.
The scope is the place where variables live. extern keyword notes that the scope is global.
You can define variables with the same name in an inner scope and access only them as you did in the main function but it's not a good practice.
void foo()
{
int a = 5;
printf("%d\n", a); // 5
// Creating an inner scope
{
int a = 20;
printf("%d\n", a); // 20
}
printf("%d\n", a); // 5
}
The correct way to use the extern keyword with variables is like this.
//h1.h
extern int global_var; // Declaration of the variable
//c1.c
#include h1.h
int global_var = 0; // Definition of the global var. Memory is allocated here.
//main.c
#include h1.h
int main()
{
printf("global var value is %d\n", global_var); // use of the var defined and
// initialized in c1.c
return 0;
}
This program will print 0 since the variable is defined and initialized in c1.c.
Extern extends the visibility of the C variables and C functions. so that lets the compiler know that there is another place that those vars are declared and memory was allocated for them elsewhere.
for example in another c file.
if you compile a c file containing a global var for example:
int c = 5;
and you create a function on you c file that uses this c var, for example:
int someFunc(void){
return c;}
if you run someFunc in your main and print its return value, you will get 5. but you must compile both c files together.
in your program, you only use the locally allocated var declared in your main function.
When it comes to simple variables, there is really no difference between the declaration and definition. There is a difference when it comes to structs and functions. Here is an example:
// Declarations
struct myStruct;
int foo();
int main()
{
...
}
// Definitions
struct myStruct {
int a, b;
};
int foo() {
return 42;
}
In your case, you are hiding the previous declarations so that they are not accessible before the end of the scope. This is commonly called shadowing. It's basically the same thing as this:
int main()
{
int i=0;
printf("i: %d\n", i);
{
int i=42; // Now the previous i is inaccessible within this scope
printf("i: %d\n", i);
}
// And now it is accessible again
printf("i: %d\n", i);
}

declaration of variables with same name as global,local and static

I have the following code snippet and I have to analyse what the output will be:
#include <stdio.h>
void f(int d);
int a = 1, b = 2, c = 3, d = 4;
int main(){
int a = 5, c = 6;
f(a);
f(b);
f(c);
printf("%d %d %d %d\n",a,b,c,d);
return 0;
}
void f(int d){
static int a = 0;
a = a + 7;
b = a + d;
c++;
d--;
printf("%d %d %d %d\n",a,b,c,d);
}
The output I've got is as follows:
7 12 4 4
15 26 5 11
21 27 6 5
5 27 6 4
This really baffled me. I noticed that in all 3 function calls the globally declared a suffers the assignment and that in the printf() from main() body the a declared in main() is printed. However, I am not sure about the behaviour of the rest of the variables. Is this undefined behaviour or it actually makes sense?
int a = 1, b = 2, c = 3, d = 4; ---> Global variables
int main(){
int a = 5, c = 6; ---> Shadows the global `a` and `c`
....
void f(int d){
static int a = 0; ---> local static variable visible only inside `f`
...
This is related to C's identifier scopes. The scope of a declaration is the region of the C program over which that declaration is visible. There are six scopes:
Top level identifiers: extends from the declaration point to the end of the source program file
Formal parameters in a function definiton: extends to the end of the function body
Formal parameters in function prototypes
Block (local) identifiers: extends up to the end of the block
Statement labels
Preprocessor macros
What happens in your program is known as overloading of names - a situation in which the same identifier may be associated to more than one program entity at a time. There are 5 overloading classes in C (aka namespaces):
Preprocessor macro names
Statement labels
Structure, union and enumeration tags
Component names
Other names
In C, declarations at the beginning of a block can hide declarations outside the block. For one declaration to hide another, the declared identifiers must be the same, must belong to the same overloading class, and must be declared in two distinct scopes, one of which contains the other.
With this in mind, in your code, local a and c hide global a and c in main(), and a in f() hides global a. All other references are manipulating the global variables.
void f(int d){
**static int a = 0;**
a = a + 7;
b = a + d;
c++;
d--;
printf("%d %d %d %d\n",a,b,c,d);
}
That's right you declared global int a and global void function f
but also you have declared static variable a
Whenever function has called, function is refering a variable of function.
if you want to avoid this problem, you should make a pointer of global variable, and refering a pointed address's value global variable.
As you know static variable is keep their last value until end of program.
each function's variable is exactly going to placed in "Stack" unless allocated by malloc.
And global variable is "Heap".
I am not sure but if you disassembly your program, static value a would go to stack
and treated with PUSH and POP instruction.
In C/C++, the identifiers in a given scope shadow the identifiers in the outer scope from the point of declaration onwards.
The following example demonstrates this:
#include <stdio.h>
const char a[] = "a";
static const char b[] = "b";
void test(const char * arg)
{
const char c[] = "c1";
printf("1-. a=%s b=%s c=%s arg=%s\n", a,b,c,arg);
const char a[] = "a1";
static const char b[] = "b1";
// arg is present in this scope, we can't redeclare it
printf("1+. a=%s b=%s c=%s arg=%s\n", a,b,c,arg);
{
const char a[] = "a2";
const char b[] = "b2";
const char arg[] = "arg2";
const char c[] = "c2";
printf("2-. a=%s b=%s c=%s arg=%s\n", a,b,c,arg);
{
static const char a[] = "a3";
const char b[] = "b3";
static char arg[] = "arg3";
static const char c[] = "c3";
printf("3. a=%s b=%s c=%s arg=%s\n", a,b,c,arg);
}
printf("2+. a=%s b=%s c=%s arg=%s\n", a,b,c,arg);
}
printf("1++. a=%s b=%s c=%s arg=%s\n", a,b,c,arg);
}
int main(void)
{
test("arg");
return 0;
}
Output:
1-. a=a b=b c=c1 arg=arg
1+. a=a1 b=b1 c=c1 arg=arg
2-. a=a2 b=b2 c=c2 arg=arg2
3. a=a3 b=b3 c=c3 arg=arg3
2+. a=a2 b=b2 c=c2 arg=arg2
1++. a=a1 b=b1 c=c1 arg=arg
This output actually makes sense.
In C/C++, the identifiers in a given scope are given preference over the identifiers in the outer scope. In this case in the function main, variables a and c will be used as local variables and rest b and d as global variables. Similarly, in the function void f(int d), d is the passed parameter, a will be used as static whenever the function is called, b and c will be used as global variables.
Hence the output will be calculated.
However you have shown the incorrect output. Correct output must be :
7 12 4 4
14 26 5 11
21 27 6 5
5 27 6 4

Resources