Related
#include <stdio.h>
int main()
{
for(int i=0;i<100;i++)
{
int count=0;
printf("%d ",++count);
}
return 0;
}
output of the above program is: 1 1 1 1 1 1..........1
Please take a look at the code above. I declared variable "int count=0" inside the for loop.
With my knowledge, the scope of the variable is within the block, so count variable will be alive up to for loop execution.
"int count=0" is executing 100 times, then it has to create the variable 100 times else it has to give the error (re-declaration of the count variable), but it's not happening like that — what may be the reason?
According to output the variable is initializing with zero every time.
Please help me to find the reason.
Such simple code can be visualised on http://www.pythontutor.com/c.html for easy understanding.
To answer your question, count gets destroyed when it goes outside its scope, that is the closing } of the loop. On next iteration, a variable of the same name is created and initialised to 0, which is used by the printf.
And if counting is your goal, print i instead of count.
The C standard describes the C language using an abstract model of a computer. In this model, count is created each time the body of the loop is executed, and it is destroyed when execution of the body ends. By “created” and “destroyed,” we mean that memory is reserved for it and is released, and that the initialization is performed with the reservation.
The C standard does not require compilers to implement this model slavishly. Most compilers will allocate a fixed amount of stack space when the routine starts, with space for count included in this fixed amount, and then count will use that same space in each iteration. Then, if we look at the assembly code generated, we will not see any reservation or release of memory; the stack will be grown and shrunk only once for the whole routine, not grown and shrunk in each loop iteration.
Thus, the answer is twofold:
In C’s abstract model of computing, a new lifetime of count begins and ends in each loop iteration.
In most actual implementations, memory is reserved just once for count, although implementations may also allocate and release memory in each iteration.
However, even if you know your C implementation allocates stack space just once per routine when it can, you should generally think about programs in the C model in this regard. Consider this:
for (int i = 0; i < 100; ++i)
{
int count = 0;
// Do some things with count.
float x = 0;
// Do some things with x.
}
In this code, the compiler might allocate four bytes of stack space to use for both count and x, to be used for one of them at a time. The routine would grow the stack once, when it starts, including four bytes to use for count and x. In each iteration of the loop, it would use the memory first for count and then for x. This lets us see that the memory is first reserved for count, then released, then reserved for x, then released, and then that repeats in each iteration. The reservations and releases occur conceptually even though there are no instructions to grow and shrink the stack.
Another illuminating example is:
for (int i = 0; i < 100; ++i)
{
extern int baz(void);
int a[baz()], b[baz()];
extern void bar(void *, void *);
bar(a, b);
}
In this case, the compiler cannot reserve memory for a and b when the routine starts because it does not know how much memory it will need. In each iteration, it must call baz to find how much memory is needed for a and how much for b, and then it must allocate stack space (or other memory) for them. Further, since the sizes may vary from iteration to iteration, it is not possible for both a and b to start in the same place in each iteration—one of them must move to make way for the other. So this code lets us see that a new a and a new b must be created in each iteration.
int count=0 is executing 100 times, then it has to create the variable 100 times
No, it defines the variable count once, then assigns it the value 0 100 times.
Defining a variable in C does not involve any particular step or code to "create" it (unlike for example in C++, where simply defining a variable may default-construct it). Variable definitions just associate the name with an "entity" that represents the variable internally, and definitions are tied to the scope where they appear.
Assigning a variable is a statement which gets executed during the normal program flow. It usually has "observable effects", otherwise the compiler is allowed to optimize it out entirely.
OP's example can be rewritten in a completely equivalent form as follows.
for(int i=0;i<100;i++)
{
int count; // definition of variable count - defined once in this {} scope
count=0; // assignment of value 0 to count - executed once per iteration, 100 times total
printf("%d ",++count);
}
Eric has it correct. In much shorter form:
Typically compilers determine at compile time how much memory is needed by a function and the offsets in the stack to those variables. The actual memory allocations occur on each function call and memory release on the function return.
Further, when you have variables nested within {curly braces} once execution leaves that brace set the compiler is free to reuse that memory for other variables in the function. There are two reasons I intentionally do this:
The variables are large but only needed for a short time so why make stacks larger than needed? Especially if you need several large temporary structures or arrays at different times. The smaller the scope the less chance of bugs.
If a variable only has a sane value for a limited amount of time, and would be dangerous or buggy to use out of that scope, add extra curly braces to limit the scope of access so improper use generates immediate compiler errors. Using unique names for each variable, even if the compiler doesn't insist on it, can help the debugger, and your mind, less confused.
Example:
your_function(int a)
{
{ // limit scope of stack_1
int stack_1 = 0;
for ( int ii = 0; ii < a; ++ii ) { // really limit scope of ii
stack_1 += some_calculation(i, a);
}
printf("ii=%d\n", ii); // scope error
printf("stack_1=%d\n", stack_1); // good
} // done with stack_1
{
int limited_scope_1[10000];
do_something(a,limited_scope_1);
}
{
float limited_scope_2[10000];
do_something_else(a,limited_scope_2);
}
}
A compiler given code like:
void do_something(int, int*);
...
for (int i=0; i<100; i++)
{
int const j=(i & 1);
doSomething(i, &j);
}
could legitimately replace it with:
void do_something(int, int*);
...
int const __compiler_generated_0 = 0;
int const __compiler_generated_1 = 1;
for (int i=0; i<100; i+=2)
{
doSomething(i, &compiler_generated_0);
doSomething(i+1, &compiler_generated_1);
}
Although a compiler would typically allocate space on the stack once for j, when the function was entered, and then not reuse the storage during the loop (or even the function), meaning that j would have the same address on every iteration of the loop, there is no requirement that the address remain constant. While there typically wouldn't be an advantage to having the address vary on different iterations, compilers are be allowed to exploit such situations should they arise.
I've been told at my university that everything is put on the top of the "stack" when working with a function. So, when returning from one, the top of the stack is removed, until we reach the bottom - main(). Suggesting that everything is lost we have made in the local scope of the previous functions.
Most books tell me the same thing.
However, i have come across a number of occurrences, where i used this exact feature.
For instance:
void address (bool** xpp)
{
bool* y = (bool*) malloc(10*sizeof(bool));
y[2] = false;
**xpp = &y;
}
int main(void)
{
bool* x;
bool** xp = &x;
address(&xp);
xp[0] = false;
xp[2] = false;
xp[7] = false;
printf("%d", xp[0]);
printf("%d", xp[2]);
printf("%d", xp[7]);
return 0;
}
In this case, to my understanding, i should not be able to refer to the xp[] array in the main() after address(), because, indeed i have set it's pointer to an arrays first elements pointer, but after returning to main() the array i had created in address() is supposed to be gone. So it should be pointing to nowhere and should pop up an exception.
However, all of the bool xp elements print '0', implying it's success in working.
Well, there are two different answers here. Your question boils down to, "I heard that local variables are lost when they're popped from the stack, but I tried it, and they were still there", but your actual code does not demonstrate the use of local variables on the stack that would be lost; it demonstrates the use of malloc, which is completely different.
And then the second answer is, any time you ask anything like "I heard that X doesn't work, but I tried it, and it worked", you're playing with fire: it might have seemed to have worked, but it wasn't guaranteed to.
Let's look at a slightly different version of your program. Instead of playing with pointers to pointers, I'm just going to have the address function return a pointer to the first element of an array. And instead of an array of bools, I'm going to use an array of int, so I can more easily show interesting numbers. Here's the first version of the code:
#include <stdio.h>
#include <stdlib.h>
int *address()
{
int *p = malloc(5 * sizeof(int));
if(p == NULL) abort();
p[0] = 1; p[1] = 2; p[2] = 3; p[3] = 4; p[4] = 5;
return p;
}
int main()
{
int *a = address();
int i, sum = 0;
for(i = 0; i < 5; i++) sum += a[i];
printf("sum = %d\n", sum);
for(i = 0; i < 5; i++) printf("a[%d] = %d\n", i, a[i]);
}
Function address returns a pointer, but it's a pointer to dynamically-allocated memory, which is guaranteed to stick around even after address returns. The program prints
sum = 15
a[0] = 1
a[1] = 2
a[2] = 3
a[3] = 4
a[4] = 5
which is just what you would expect.
But now let's change function address to not call malloc, but instead, use a local array:
int *address()
{
int la[5];
la[0] = 1; la[1] = 2; la[2] = 3; la[3] = 4; la[4] = 5;
return la;
}
This function is broken. It returns a pointer to the first element of a local array. By the time the function returns to its caller, that array will no longer exist. The pointer can never be useful to its caller; it is virtually guaranteed not to work. Indeed, when I compile this second version, my compiler warns me about it:
warning: address of stack memory associated with local variable 'a' returned
But if Ignore that warning and run the resulting program anyway, here's what I get:
sum = 15
a[0] = 507402241
a[1] = -16764064
a[2] = 0
a[3] = 0
a[4] = 0
This is a very interesting result. The second thing to notice is that the contents of the array are all wrong. We don't see 1, 2, 3, 4, 5; we see some numbers that are clearly garbage. But this was to be expected, because that array la in function address is gone.
But the first and perhaps more interesting thing to notice is that the sum is correct! How did that happen? And the sum doesn't match the contents of the array as printed! It's as if the "broken" pointer returned by the address function worked for a little while, just long enough to compute the "correct" sum, but got trashed later. And, in fact, that's exactly what happened.
After function address returns, the array la is "gone", but the memory on the stack that it was using hasn't been reused or erased yet, so the bit patterns are still there. So the calling function, main, can try to access those bits, and it even seems to get the right answer -- it computes the same sum, 15. It's important to note that this is absolutely not guaranteed to work; you would never want to depend on it in a real program -- it just happens to work.
But then, having computed the sum, main calls printf to print it out. And printf is a function that gets called -- a big, complicated function -- and it does all sorts of stuff, and allocates all sorts of its own variables on the stack. So that's when the stack memory that had been allocated to the la array actually gets overwritten. So that's why, when the last half of the main function tries to print out the array, it's garbage.
There's another point to make and that has to do with addresses. When we worry about the local array la getting lost or not, there are two questions to ask: do we lose the contents of the array, and, do we lose the pointer to the array? And in answering those questions, we encounter a significant fact: a function can still, perfectly well, return a value, even though the function's local (stack) storage has gone away.
To see this, consider the function
int five()
{
int r = 5;
return r;
}
When function five returns, its local variable r goes away. But the caller who says
int x = five();
has no problem, because as function five returns, and even as function fives local variable r is being allocated, the return value 5 is being copied into the caller's own variable x, so it's not lost.
But with all of that said -- and besides the question of whether the array is a local (stack) array or allocated with malloc -- there's also something wrong, sort of differently wrong, with he way you're taking y's address. y is a local variable, so after the function exits, &y is bogus, and not guaranteed to work, no matter where you've stashed it. (But, again, it might seem to work, for a little while, until something else overwrites the stack.)
How is it possible to access a functions variable outside the function?
Assuming it's not declared static you simply cannot, for the reason you mentioned: It's gone the moment the function had been left.
after returning to main() the array i had created in address() is supposed to be gone.
The call to malloc did not create a "variable", but it allocated memory from the heap. All that is stored locally inside the function's variable y is the address of this very block of memory. This address indeed is lost when y goes away by leaving the function.
To not lose the address of the memory allocated fix the code for example like this:
#include <stdlib.h> /* for malloc() */
#include <stdio.h> /* for printf() */
void address (bool** xpp)
{
bool* y = malloc(10*sizeof(bool));
y[2] = false;
*xpp = y;
}
int main(void)
{
bool* xp;
address(&xp);
xp[0] = false;
xp[2] = false;
xp[7] = false;
printf("%d", xp[0]);
printf("%d", xp[2]);
printf("%d", xp[7]);
return 0;
}
A major flaw still with this code is, that the caller (main) and the callee (address) do not "talk" about how much memory has to be/was allocate.
Almost everything about this code is misleading.
The question is, "How can the xp pointer be valid after function address returns? But it turns out that the call to address does not modify the xp pointer.
xp is set to point to x. The call to address doesn't change that. (The call to address does end up changing what xp points to, that is, it changes x.
Although xp is not a pointer to bool, it's used as if it were, in the three assignments
xp[0] = false;
xp[2] = false;
xp[7] = false;
Although xp doesn't actually point to memory that's been allocated to hold 10 bools, wherever it does point (that is, somewhere on the stack surrounding x), there's evidently enough memory to accidentally store 10 bools without causing too much damage.
And then, having stored a few bools at wherever-it-is, trying to print those three bools back out (from wherever-it-was) happens to work.
For answers to the question of how the local storage in a function can still be accessed (though incorrectly) after the function returns -- and although this code doesn't actually end up doing that -- see my other answer.
For the record, there are other problems. The call
address(&xp);
is a type mismatch (&xpp is a pointer-to-pointer-to-pointer-to-bool, but address() accepts a pointer-to-pointer-to-bool). The line
**xpp = &y;
is a type mismatch (&y is a pointer-to-pointer-to=-bool, but **xpp is a bool). Lines like
xp[0] = false;
are a type mismatch (false is a bool, but xp[0] is a pointer-to-bool). Finally, lines like
printf("%d", xp[0]);
are a type mismatch (xp[0] is a pointer-tobool, but %d expects an int, or maybe a bool).
This is a question for my Programming Langs Concepts/Implementation class. Given the following C code snippet:
void foo()
{
int i;
printf("%d ", i++);
}
void main()
{
int j;
for (j = 1; j <= 10; j++)
foo();
}
The local variable i in foo is never initialized but behaves similarly to a static variable on most systems. Meaning the program will print 0 1 2 3 4 5 6 7 8 9. I understand why it does this (the memory location of i never changes) but the question in the homework asks to modify the code (without changing foo) to alter this behavior. I've come up with a solution that works and makes the program print ten 0's but I don't know if it's the "right" solution and to be honest I don't exactly know why it works.
Here is my solution:
void main()
{
int j;
void* some_ptr = NULL;
for (j = 1; j <= 10; j++)
{
some_ptr = malloc(sizeof(void*));
foo();
free(some_ptr);
}
}
My original thought process was that i wasn't changing locations because there was no other memory manipulation happening around the calls of foo, so allocating a variable should disrupt that, but ince some_ptr is allocated in the heap and i is on the stack, shouldn't the allocation of some_ptr have no effect on i? My thought is that the compiler is playing some games with the optimization of that subroutine call, could anyone clarify?
There cannot be a "right" solution. But there can be a class of solutions which work for a particular CPU architecture, ABI, compiler, and compiler options.
Changing the code to something like this will have the effect of altering the memory above the stack in a way which should affect many, if not most, environments in the targeted way.
void foo()
{
int i;
printf("%d ", i++);
}
void main()
{
int j;
int a [2];
for (j = 1; j <= 10; j++)
{
foo();
a [-5] = j * 100;
}
}
Output (gcc x64 on Linux):
0 100 200 300 400 500 600 700 800 900
a[-5] is the number of words of stack used for overhead and variables spanning the two functions. There is the return address, saved stack link value, etc. The stack likely looks like this when foo() writes to a[-5]:
i
saved stack link
return address
main's j
(must be something else)
main's a[]
I guessed -5 on the second try. -4 was my first guess.
When you call foo() from main(), the (uninitialized) variable i is allocated at a memory address. In the original code, it so happens that it is zero (on your machine, with your compiler, and your chosen compilation options, your environment settings, and given the current phase of the moon — it might change when any of these, or a myriad other factors, changes).
By calling another function before calling foo(), you allow the other function to overwrite the memory location that foo() will use for i with a different value. It isn't guaranteed to change; you could, by bad luck, replace the zero with another zero.
You could perhaps use another function:
static void bar(void)
{
int j;
for (j = 10; j < 20; j++)
printf("%d\n", j);
}
and calling that before calling foo() will change the value in i. Calling malloc() changes things too. Calling pretty much any function will probably change it.
However, it must be (re)emphasized that the original code is laden with undefined behaviour, and calling other functions doesn't make it any less undefined. Anything can happen and it is valid.
The variable i in foo is simply uninitialized, and uninitialized value have indeterminate value upon entering the block. The way you saw it print certain value is entirely by coincident, and to write standard conforming C, you should never rely on such behavior. You should always initialize automatic variables before using it.
From c11std 6.2.4p6:
For such an object that does not have a variable length array type, its lifetime extends from entry into the block with which it is associated until execution of that block ends in any way. (Entering an enclosed block or calling a function suspends, but does not end, execution of the current block.) If the block is entered recursively, a new instance of the object is created each time. The initial value of the object is indeterminate. If an initialization is specified for the object, it is performed each time the declaration or compound literal is reached in the execution of the block; otherwise, the value becomes indeterminate each time the declaration is reached.
The reason the uninitialized value seems to keep its value from past calls is that it is on the stack and the stack pointer happens to have the same value every time the function is called.
The reason your code might be changing the value is that you started calling other functions: malloc and free. Their internal stack variables are using the same location as i in foo().
As for optimization, small programs like this are in danger of disappearing entirely. GCC or Clang might decide that since using an uninitialized variable is undefined behavior, the compiler is within its rights to completely remove the code. Or it might put i in a register set to zero. Then decide all printf calls output zero. Then decide that your entire program is simply a single puts("0000000000") call.
About the following code:
#include <stdio.h>
int lastval(void)
{
`static int k = 0;
return k++;
}
int main(void)
{
int i = 0;
printf("I previously said %d\n", lastval());
i++;
i++;
i++;
i++;
i++;
printf("I previously said %d\n", lastval());
i++;
i++;
i++;
printf("I previously said %d\n", lastval());
i++;
i++;
i++;
printf("I previously said %d", lastval());
i++;
i++;
i++;
return 0;
}
can anyone explain to me how does static maintain its value ? I though it was because the stack frame for the function wasnt destroyed after the return so I wrote this code to run it under gdb and I after doing backtraces after every single line only main's stack frame show up (it doesnt even list lastval when I do a backtrace sitting on a printf call, but anyway).
How its k actually stored ? I know that's not like a normal variable since the first k++ returns 1 instead of 0, and its not like a global since i cant access k inside main for example, so .. what's going on ?
`on a local k, K++ // Always returns 0
`on a global k = 0, k++ // returns 0, 1, 2
`on a static k, k++ // returns 1, 2 ,3
Can anyone help me to understand these 2 issues ?
A static definition inside a function is just like a static definition outside a function other than the scope of the symbol (where in your the program you can refer to it). It has nothing to do with stack frames ... k isn't on the stack, it's in "static"/global/.data memory.
I know that's not like a normal variable since the first k++ returns 1 instead of 0
No, it returns 0, but k's value is then 1.
on a static k, k++ // returns 1, 2 ,3
No, that's not correct ... it returns 0, 1, 2 ...
and its not like a global since i cant access k inside main for example
That's simply how name scopes work; it has nothing to do with how k is stored.
variable k is defined inside function lastval so its scope is in this function only.But since you defined it with static keyword, its lifetime becomes equal to lifetime of programme.
so as per definition of static this variable k will be initialized only once and it will retain its last value and that is what happening in your case.Initialized static variable will go in .data section of memory.so k will get memory in .data.
The static variables stored as globals, except their scope. Your program outputs 0 1 2 3 on my computer, so double-check it.
Not to be snarky, but any reference on C will explain this.
The static keyword used on a variable within a function allows the value to persist across function calls. It's stored like a global, but you can only access it by name within the scope of the function where it is defined.
Some typical uses of static variables in the standard C library occur in the implementations of rand(3) and strtok(3). Their use is commonly discouraged because it can lead to functions that are not reentrant and thus play havoc when multiple threads are used. POSIX defines a strtok_r function for use when reentrancy is required.
The static variables are instantiated in the global memory space (Not in a stack frame) before the program start executing the main.
C,
That variable is initialized before the program start executing the main.
C++,
That variable is initialized when the program encounters this line for the 1st time.
When you execute the "lastval()" function, that "static int k = 0" will not be executed again.
I'm studying for a test and I came across something I'm finding hard to understand. We're working with pointers and memory allocation, and I was just fooling around with things, trying to see what changed what. I have this bit of code:
int * arr[10];
for(i=0; i<5;i++)
{
int index = i;
arr[index] = malloc(sizeof(int*));
int i = 2 * index;
*arr[index] = i;
printf("arr [%d] = %d\n", index, *arr[index]); /* should be 0, 2, 4, 6, 8 */
}
But what I've found is that if instead of using *arr[index] = i, I use arr[index] = &i I don't need the malloc. I've always assumed that these two things were essentially the same thing, but there must be some key difference I don't understand to warrant the use of malloc with the one.
I'm actually confused why I need malloc at all here really. I'm fairly new with memory allocation and I don't really understand when it's supposed to be used (obviously) and was wondering if anyone could clear this up for me.
Try this code instead:
int * arr[10];
for(i=0; i<5;i++)
{
int index = i;
int value = 2*i;
arr[index] = malloc(sizeof(int*));
*arr[index] = value;
}
for (i=0; i<5; i++)
{
int index = i;
printf("arr [%d] = %d\n", index, *arr[index]); /* should be 0, 2, 4, 6, 8 */
}
If you make the change you suggest, you would now have undefined behavior. Whereas this code still is valid.
You'd have undefined behavior because *arr[0] now points to a piece of stack memory that has left scope.
Your malloc should actually be malloc(sizeof(int)). You're allocating space for an int, not for a int *.
Written this way:
*arr[index] = i;
Means: Copy the value of i to the memory location pointed to by arr[index] (that was allocated earlier in your code).
arr[index] = &i;
Means: Copy the address of i to arr[index].
In your code i is automatically created inside the for loop and only exists inside that loop. Once you leave the loop (scope) the memory used to store i is then free to part of any newly created variables.
As sharth suggests, try looking at the values outside the original for loop to see some interesting results.
Yeah I think it is hard to understand, because i gets redefined in the middle of the for. I'll rewrite the code right now. I wrote i instead of index and 2*i instead of the redefined i.
int * arr[10];
for(i=0; i<5;i++)
{
arr[i] = malloc(sizeof(int));
*arr[i] = 2*i;
printf("arr [%d] = %d\n", i, *arr[i]); /* should be 0, 2, 4, 6, 8 */
}
You don't acutally need dynamic memory here, you know that array 0-4 will be used. You need dynamic memory, when you don't know how mutch data will you need. This code is written, so that the rest of your code will still work, but there is no malloc.
int array[5];
int **arr=array;
The following code means, that array[index] should point to the memory adress i is stored in. It does not copy the value that is in i, so when you change i, or i gets deleted, this will cause this pointer to be faulty, and cause problems later. You should't do this.
arr[index] = &i
One key difference is that &i will cease to exist once i goes out of scope (or, rather, that piece of memory can be reused for something else... which probably won't contain what you thought it contains).
Edit: I say below you didn't show how i was declared. Actually, you redeclare it, hiding the original value if i used in the loop. Regardless, i is going to go out of scope at the end of the loop or, likely, when the routine ends.
You don't show how i is declared here. However, in most cases, it'd be a local variable or perhaps a parameter passed to a method. In either case, the space for that variable is declared on the stack. You can take the address of that variable with &i, but that variable is going to go away after the method ends and the code pops those values off the stack. You might get lucky and have that value remain untouched for as long as you need it. But the moment another method is called, that value is likely to be overwritten and boom, your program is at best going to behave incorrectly.
You could get away with this if i is declared globally.
Further, you're pointing to the same address even after changing the value of i. If, at the end of your routine, you printed out all of the values of your array, you'd see they were all the same value - the last value you put into the array. That's because each entry in the array points to the same location.