Variable scope behavior c language - c

Code snippet:
void function(void)
{
while(1)
{
int i = 0;
i += 1;
if(i == 500) break;
}
}
The variable i is stored in stack every time when restart the loop ?
What is the memory structure when running this code ?
What is the behavior of this variable ?
It is a bad or good practice do this ?
Thanks.

You will never reach i == 500. It's being reset every time through the loop since it's within the scope of while(1){}.
The following will work.
void function(void)
{
int i = 0;
while(1)
{
i += 1;
if(i == 500) break;
}
}

When a function runs in C, it allocates space for all the local variables its going to need. If the variables are allocated all next to each other at the top of the function its easy to see how it works:
void foo(){
int x;
int y;
y = 1;
x = y + 2;
return x + y;
}
If the variables are declared inside inner blocks of the function, what the compiler does is "lift" those variable declarations to the top of the function. If there are variables with clashing names, the compiler renames things for you so they reference the correct variable.
// This is what you write
void original(){
int x = 0;
while(1){
int x = 1;
}
}
// This is what the compiler "sees"
void lifted(){
int x1;
int x2;
x1 = 0;
while(1){
x2 = 0;
}
}
In your case, your code is behaving like this one:
void function(void)
{
int i;
while(1)
{
i = 0;
i += 1;
if(i == 500) break;
}
}
In this version, its clear that the i is being reset to 0 all the time, which is why the loop will run forever.
As for if declaring variables in inner scopes is a good practice or not, it doesn't have to do with memory usage but with the scope of your variable names. In general its a good thing to keep your variables confined to inner scopes if possible (for the same reason why local variables are preferred to global ones). That said, you always have to initialize your variables before the loop and not inside it. In this case, its about removing bugs and not about being a best practice.

Logically speaking, each iteration of the loop creates a new instance of the i variable which only exists within the body of the loop. As written, this code will never terminate, because each iteration of the while loop creates a new instance of i and initializes it to 0.
Attempting to reference i outside the body of the loop results in undefined behavior; IOW, code like
int *p;
while ( 1 )
{
int i = 0;
p = &i;
if ( some_condition )
break;
...
}
printf( "last value of i was %d\n", *p );
isn't guaranteed to do what you expect.
In practice, the generated machine code will set aside the space for i once at function entry; however, you should not rely on that behavior.

The variable i will always be at 0 or 1 in this code; the break will never execute.
The variable i is declared in and is local to the while loop.
In the C language, a pair of braces can create a new scope
that hides variables with the same name declared outside the
scope.
This code:
void function(void)
{
while(1)
{
int i = 0;
i += 1;
if(i == 500) break;
}
}
should be changed to this:
void function(void)
{
int i = 0;
while(1)
{
i += 1;
if(i == 500) break;
}
}

Related

Can a function remember variables between numerous calls?

I am trying to create a function that will take in the positions of numerous bodies moving in circular motion, and output their orbital periods. Each body is stored in a struct which contains its X, Y and Z co-ordinate (as well as some other information I don't need for this specific task).
My current function for doing this is:
double calc_period(Body *bodies, double t, int Nbodies, int i)
{
double orbit_angle[Nbodies];
double initial_angle[Nbodies];
double last_angle[Nbodies]
double last_time[Nbodies];
double half_step[Nbodies];
double running_total[Nbodies];
double orbitN[Nbodies];
double average_period[Nbodies];
orbit_angle[i] = atan(bodies[i].r[Y] / bodies[i].r[X]);
if (t==0) {
//Initialise all the variables to 0 the first time through
last_angle[i] = 0;
initial_angle[i] = orbit_angle[i];
orbitN[i] = 0;
half_step[i] = 1;
}
if (last_angle[i] < initial_angle[i] && orbit_angle[i] > initial_angle[i]) {
if (half_step[i] == 0) {
if (orbitN[i]==0) {
last_t[i] = t;
running_total[i] = t;
} else {
running_total[i] += t - last_t[i];
last_t[i] = t;
}
orbitN[i]++;
average_period[i] = running_total[i] / (DAYS_TO_SECS * orbitN[i]);
half_step[i] = 1;
} else if (half_step[i] == 1) {
half_step[i] = 0;
}
}
last_angle[i] = orbit_angle[i];
return average_period[i];
}
and this function is called in main like so:
for (double j = 0; j < max_time; j += timestep) {
update_positions(bodies, Nbodies, j);
for (int i = 0; i < Nbodies; i++) {
average_period[i] = calc_period(bodies, j, Nbodies, i);
if (j > max_time - timestep) {
printf("%s average period: %lg\n", bodies[i].name, average_period[i]);
}
}
}
and the problem that I'm having is that of course when the calc_period function finishes, the variables within are destroyed, so it cannot remember what initial_angle, last_angle or last_t were, so doesn't work. However I'm struggling to come up with a solution for this. If anyone can give any guidance it would be much appreciated.
Any data in the stack is volatile within function calls. The space in the stack you are using now will be replaced on future function calls, so functions on the stack should be used just until the function ends.
For your problem different methods exists.
You can create a struct as a global variable which will be stored in BSS, you can create a global pointer pointing to your struct on dynamic memory, allocated with functions like malloc().
Also you can create a static variable so on future calls to that function you can use it.
The best solution would be either defining a static pointer to malloc() where your struct resides, or doing the same on a global variable as a pointer.

C - Passing a local variable in a function without initializing

so I'm really new at this, and I was wondering how I would go about passing a local variable in a function (in terms of the initialization). For example, I have one function (move) that declares and initializes two variables (t_row and t_column) to be used in a for loop, and within that loop, I have another functions (swap), that is called if certain conditions are met. How do I go about using those variables in the swap function. I know I need to declare them, but their initialization in the swap function depends on what iteration of the for loop swap was called. Thanks in advance for any help!
bool move(int tile)
{
for (int t_row = 0; t_row < d; t_row++)
{
for (int t_column = 0; t_column < d; t_column++)
{
if (tile == board[t_row][t_column])
{
if (0 < t_row && board[t_row - 1][t_column] == 0)
{
swap(t_row - 1, t_column);
return true;
}
}
}
}
return false;
}
void swap(int row_new, int column_new)
{
int t_row;
int t_column;
int hold = board[t_row][t_column];
board[t_row][t_column] = 0;
board[row_new][column_new] = hold;
}
The easiest way I can see to do this would be to pass in the values of the old row and column.
void swap(int row_new, int col_new, int row_old, int col_old) {
int hold = board[row_old][col_old];
board[row_old][column_old] = 0;
board[row_new][column_new] = hold;
}

Function Warnings in C

Hello guys i have threefunctions for which i get 4 warnings...!!
The first one is this
void evaluatearxikos(void)
{
int mem;
int i;
double x[NVARS+1];
FILE *controlpointsarxika;
controlpointsarxika = fopen("controlpointsarxika.txt","r");
remove("save.txt");
for(mem = 0; mem < POPSIZE; mem++)
{
for(i = 0; i < NVARS; i++)
{
x[i+1] = population[mem].gene[i];
}
rbsplinearxiki();
XfoilCall();
population[mem].fitness = FileRead();
remove("save.txt");
}
fclose(controlpointsarxika);
}
For this one the compiler warns me tha variable x is set but not used...!! But actually i am using the variable x...!!!
The second function is this one...
void elitist(void)
{
int i;
double best,worst;
int best_mem,worst_mem;
best = population[0].fitness;
worst = population[0].fitness;
for(i = 0; i < POPSIZE - 1; i++)
{
if(population[i].fitness > population[i+1].fitness)
{
if(population[i].fitness >= best)
{
best = population[i].fitness;
best_mem = i;
}
if(population[i+1].fitness <= worst)
{
worst = population[i+1].fitness;
worst_mem = i+1;
}
}
else
{
if(population[i].fitness <= worst)
{
worst = population[i].fitness;
worst_mem = i;
}
if(population[i+1].fitness >= best)
{
best = population[i+1].fitness;
best_mem = i+1;
}
}
}
if(best >= population[POPSIZE].fitness)
{
for(i = 0; i < NVARS; i++)
{
population[POPSIZE].gene[i] = population[best_mem].gene[i];
}
population[POPSIZE].fitness = population[best_mem].fitness;
}
else
{
for(i = 0; i < NVARS; i++)
{
population[worst_mem].gene[i] = population[POPSIZE].gene[i];
}
population[worst_mem].fitness = population[POPSIZE].fitness;
}
}
For this one i get two warnings that the variables worst_mem and best_mem may be used uninitialized in this function..!! But i initialize values to both of them..!!
And the third function is this...
void crossover(void)
{
int mem,one;
int first = 0;
double x;
for(mem =0; mem < POPSIZE; mem++)
{
x = rand()%1000/1000;
if(x < PXOVER)
{
first++;
if(first%2 == 0)
{
random_Xover(one,mem);
}
else
{
one = mem;
}
}
}
}
For which i get that the variable one may be used unitialized..!! But it is initialized..!
Can you please tell me what is wrong with these functions...??
Thank you in advance
In your first function, you set (assign) x, but you never read it, hence you are not using it... you're only wasting CPU cycles by writing to it. (Note also that because you index it as i+1 you write beyond the space you've allocated for it).
In the second function, your initializations to those variables are in conditional blocks. You can see that (perhaps? I didn't verify) in all conditions they are initialized but your compiler isn't that smart.
In your third function, it does appear that one could be refered to without having first been initialized.
First: You set x but do not use it. It's a local variable that gets set but it's dropped as soon as the function returns.
Second: There might be values that makes it so that your best_mem/worst_mem never gets set in your if/else, but you are using them later on. If they haven't been set, they contain garbage if not initialized.
Third: While it shouldn't happen that you try to use an uninitialized variable in your code, it still looks weird and compiler doesn't see that it won't happen first time.
When you get compiler warnings, treat is as you are doing something wrong or rather not recommended and that it could be done in a better way.
The x variable is only used on the left hand side (i.e. assigned a value). You are not using that value on the right hand side or pass it to a function.
It may be possible to get to the end of the loop for(i = 0; i < POPSIZE - 1; i++) without those variables given a value. Why not set them in the declaration.
The call to random_Xover(one,mem); could be called when one is not set. Change the line int mem,one; to int mem,one = <some value>;

In C, are variables declared within a loop, local?

#include <stdio.h>
int a;
void myproc()
{
int a = 2;
while (a == 2)
{
int a = 3;
printf("a = %d\t", a);
break;
}
printf("a = %d\t", a);
}
int main()
{
a = 1;
myproc();
printf("a = %d\t", a);
return (0);
}
I expected the above code to print: a = 3 a = 3 a = 1
However, it prints: a = 3 a = 2 a = 1 Can someone please provide a valid explanation?
Here is an explanation -- see the commentary below.
#include <stdio.h>
int a;
void myproc()
{
int a = 2; // (1) a = 2
while (a == 2) // true
{
int a = 3; // (2) new scope, new a = 3
printf("a = %d\t", a); // (X) prints 3 as it gets the 'nearest a' in the scope
break;
} // throws away a=3 from (2)
printf("a = %d\t", a); // (Y) Uses (1) i.e. 2 and print it
}
int main()
{
a = 1;
myproc();
printf("a = %d\t", a); // (Z) Just prints 1 as the scope is not effected by myproc
return (0);
}
So this will print (X) (Y) and (Z)
i.e. 3 2 1
Yes, they are local automatic variables and are pushed on and popped off the stack when you enter and exit a given scope unless the compiler decides to make certain optimizations (such as storing them in registers, etc.) But for a given variable, the most locally scoped version of that variable is used when accessing it. For instance, in C89 should you decide to declare your loop counters within a for-loop declaration, the following typically produces a compiler error:
for (int i=0; i < N; i++)
for (int i=0; i < J; i++)
printf("%d", i);
The value of i printed will always be the value of i declared in the inner for-loop, since that is the most locally scoped version of i.
"Within a loop"?
The question you are asking has absolutely no relation to any loops at all. There's no difference between what you have in your code and the ordinary
int a;
void myproc()
{
int a = 2;
{
int a = 3;
printf("a = %d\t", a);
}
printf("a = %d\t", a);
}
Each nested block has it own variables. That's all there is to it. And it has nothing to do with any loops.
The declaration that is really related to the loop would be the declaration made in the header of the loop, as in
int a = 3;
for (int a = 0; a < 10; ++a)
{
...
}
printf("a = %d\n", a); // <- prints `3`
That a declared in the for header is still local to the loop.
The { } variables declare scope. As when you declare a variable between those braces it is only available in those braces. If you have nested variables (like in myproc you declare a = 2 and then inside the loop a=3) then the variable declared closet to the current scope is the one referenced (in the example, a = 3).
Since your print statements are nested in the {} only the most recently declared variable a is printed, getting your results.
Whenever you declaring a variable inside a loop, which is not available outside (out of scope for that variable ). So in your code
void myproc()
{
int a = 2;
while (a == 2)
{
int a = 3;// This is not accessable to outside while loop.
printf("a = %d\t", a);
break;
}
printf("a = %d\t", a);
}
If you want to print 3, 3, 1 remove int inside while loop :)
Actually, the loop is a significantly convenient obfuscator here.
Consider the while loop's test. This test is run twice during the execution of the program, and the first time the test succeeds, as the a it is examining has the value 2. The second time it is run, the test fails, because the a it is testing is a different a, which hold the value 3! This is very surprising.
Given my colleagues explanations, the three declarations of a exist in only their enclosing '{' and '}' delimited scopes (or the world scope for the first one). If this were literally true, then the while (a == 2) test should pass forever, as the interior a declaration assigned to the value 3 is completely hidden from it by the '{' and '}'
int a = 1; // world scope - a is 1
myproc()
{ // New scope; can define names inside here
int a = 2; // Redefine a to be 2
while ( a == 2 ) // We test whether a is 2
{ // New scope; can define names inside here
int a = 3; // Redefine a to be 3
} // end of scope, the a = 3 disappears; also branch back to top of loop
} // end of myprog scope, so the a=2 disappears
The way to understand this is to realize that the while (test) { statements; } is actually implemented as:
if ( test ) { // T1
L1: {
statements;
if ( test ) // T2
goto L1;
}
}
and so in truth, the test statement is replicated, and the first one 'T1' is executed in the scope outside of the '{' and '}' and gets the a that is 2, and passes; and the second one 'T2' is executed inside the scope of the '{' and '}' and gets the a that is 3 and the test fails.
Given your statements, the second test uses its locally scoped definition of a which is 3, so the loop is exited after one pass.

Does For-Loop counter stay?

Simple Question. Imagine this in ANSI-C:
int i;
for(i=0 ; i<5 ; i++){
//Something...
}
printf("i is %d\n", i);
Will this output "i is 5" ?
Is i preserved or is the value of i undefined after the loop?
Yes. If i is declared outside of the for loop it remains in scope after the loop exits. It retains whatever value it had at the point the loop exited.
If you declatred I in the loop:
for (int i = 0 ; i < 5 ; i++)
{
}
Then i is undefined after the loop exit.
Variable i is defined outside of the scope of the loop (which is great, or you wouldn't be able to print it in that case).
And it is post-icnremented for every-turn of the loop, for which the end condition is "stop when i is bigger or equal to 5".
So it really makes perfect sense for i to be equal to 5 at this point.
A block scope is not exactly the same as a function scope in C. The variable i doesn't "get back" magically to its previous value when you step out of the loop's scope.
i's value will be 5 after your loop. Unless you did something like
i = 50000;
inside of it.
It's also generally recommended against using "i" after you exit the loop in most coding standards I have ever read. In particular do NOT do:
for(i = 0; i < num_elements; i++)
{
if(element[i].id == id)
{
/* Do something to element here. */
break;
}
}
if(i == num_elements)
{
fprintf(stderr, "Failed to find element %d.", id);
succeeded == false;
}
While this will work it is poor coding. It is less readable and maintainable than the alternatives. E.g.
succeeded = false;
for(i = 0; i < num_elements; i++)
{
if(element[i].id == id)
{
/* Do something to element here. */
succeeded = true;
break;
}
}
if(false == succeeded)
{
fprintf(stderr, "Failed to find element %d.", id);
}
Yes, variables are valid only inside the block in which they are declared.
Here's an example:
#include <stdio.h>
void main(int argc, char *argv[])
{
if(argc == 2) {
int x;
x = 7;
}
x = 1;
}
That's the compiler:
gcc ex.c
ex.c: In function ‘main’:
ex.c:10: error: ‘x’ undeclared (first use in this function)
ex.c:10: error: (Each undeclared identifier is reported only once
ex.c:10: error: for each function it appears in.)

Resources