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.
Related
Edit : Read this first : https://stackoverflow.com/a/8800541/14795595
I have this code :
#include <assert.h>
#include <stddef.h>
#include <string.h>
#include <stdlib.h>
typedef struct{
double x;
double y;
} point;
point *inserer_point( unsigned *len, point chemin[], point p, unsigned pos ){
assert( pos <= *len );
printf("%d",*len);
if( chemin == NULL )
assert( *len == 0 && pos == 0 );
chemin = realloc( chemin, (*len + 1) * sizeof( point ) );
assert( chemin );
memmove( chemin + pos + 1, chemin + pos, sizeof(point)*( *len - pos ) );
chemin[pos] = p;
(*len)++;
return chemin;
}
int main(){
point *c=NULL;
unsigned l = 0;
c = inserer_point( &l, c, (point){.x = 4, .y = 6}, 0);
c = inserer_point( &l, c, (point){.x = 5, .y = 7}, 0);
c = inserer_point( &l, c, (point){.x = 6, .y = 8}, 2);
c = inserer_point( &l, c, (point){.x = -7, .y = -9}, 1);
c = inserer_point( &l, c, (point){.x = -4, .y = -6}, 4);
c = inserer_point( &l, c, (point){.x = -44, .y = 9}, 4);
c = inserer_point( &l, c, (point){.x = -444, .y = -69}, 2);
}
As you can see, l is declared in main without a malloc, a calloc or a realloc. Which means it is declared in stack. And we don't have control over it.
It should be read only and can only be modified in the context of execution (in the main function).
However, we send a pointer to l in the other function as *len.
And then we increment len (*len++) at the bottom of the function.
As I said, it should not be possible since it is not on the heap and should be read only.
But this code works and len gets incremented.
Am I wrong about memory access ? What did I not get ? Thank you !
EDIT 2:
This is pretty similar returns SEGMENTATION FAULT. Why ?
void disp (int t[], int a, int b) {
for (int i = a; i < b - 1; i++) {
printf ("%d, ", t[i]);
}
printf("%d\n", t[b - 1]);
}
int *build (int a, int n) {
int t[n];
for (int i = 0; i < n; i++) {
t[i] = a + i;
}
printf ("t : %p : ", t);
disp (t, 0, 15);
return t;
}
int main(void){
printf ("\nbuild tab\n");
int *t = build (0, 15);
printf ("tab : %p\n", t);
disp (t, 0, 15); // SEG_FAULT!
return 0;
}
The key concepts here are scope and lifetime.
Here's a simpler example:
#include <stdio.h>
void func(int *param) {
*param = 20;
}
int main(void) {
int n = 10;
printf("Before, n = %d\n", n);
func(&n);
printf("After, n = %d\n", n);
}
We have an object n of type int defined locally in main. Its storage class is automatic, which typically means it's allocated on the stack.
The scope of the identifier n is the region of program text in which the name n is visible. It extends from the definition of n to the closing } of the main function.
The lifetime of the object named n is the period of time during program execution in which the object exists. It begins when execution enters the main function and ends when main completes.
(The lifetime of an object created by malloc extends from the successful malloc call until the object is deallocated, for example by passing its address to free, or until the program terminates. Such an object has no scope because it has no name; it can only be referred to indirectly.)
Inside the body of func, the name n is out of scope, so if I wrote n = 42; inside func I'd get a compile-time error. The name is not visible. However, while func is executing, the object named n exists, and can be referred to indirectly (though not by its name).
The object n is not read-only. If you wanted it to be, you could define it with the const keyword. You'd also have to define param as const int *param, because it's illegal to pass a pointer to a const object to a function that takes a pointer to a non-const object.
There is no reason to expect the above program (or yours, as far as I can tell) to suffer a segmentation fault, since no objects are accessed outside their lifetimes.
Passing a pointer to an object to a function so the function can modify that object is perfectly valid, and is very common.
It should be read only and can only be modified in the context of execution (in the main function).
That's just incorrect. It's not read-only, and it can be modified at any time during its lifetime. In this case, it's modified via a pointer.
UPDATE: I see you've added code that does produce a segmentation fault. Here's an abbreviated summary of the relevant part:
int *build (int a, int n) {
int t[n];
/* ... */
return t;
}
t is a VLA (variable length array), defined locally in the build function. It has automatic storage duration, meaning that its lifetime is ends when build returns. The return t; statement doesn't return the array object; it returns a pointer to it. That pointer becomes a dangling pointer when the caller (main) attempts to use it. In main you have:
int *t = build (0, 15);
t points to an object that no longer exists.
Your original code did not do anything like that. Your inserer_point function returns a pointer, but it points to an object that was created in main, so it still exists when main receives the pointer to it. (And main doesn't do anything with the pointer other than assigning it to an object which is never used.)
C does not support passing arrays as parameters or returning them from functions, but a lot of the syntax makes it look like it does. Read section 6 of the comp.lang.c FAQ.
You passed the object l by reference to the function inserer_point.
c = inserer_point( &l, c, (point){.x = 4, .y = 6}, 0);
^^
In C passing by reference means passing an object indirectly through a pointer to it.
So dereferencing the pointer within the function you have a direct access to the pointed object and can change it.
Here is a simple demonstrative program.
#include <stdio.h>
void f( int *px )
{
*px = 20;
}
int main(void)
{
int x = 10;
printf( "Before calling f x is equal to %d\n", x );
f( &x );
printf( "After calling f x is equal to %d\n", x );
return 0;
}
The program output is
Before calling f x is equal to 10
After calling f x is equal to 20
That is it is unimportant where an object is defined (allocated). You can use a pointer to the object to change it by means of dereferencing the pointer that gives you an access to the memory where the object is present.
I learned that variables not using malloc are stored in stack. And we can't manage stack except in the context of execution.
It's always difficult to communicate basic concepts when one side makes up words like "context of execution" when things have proper names (closest would be "scope" in this case).
I believe the missing gap in knowledge here is that the scope of l is the scope it belongs to (ie the closest pair of braces, in this case the function main), as well as every single function's scope called from within this scope.
And this isn't an arbitrary rule, it makes sense when you consider that the stack gets expanded as you call functions, and only reduced when you exit functions. Your l is valid until the stack frame that it belongs to is no longer valid, ie until you exit main. It gets a little more complicated when you have nested scopes within your function scope, but in this case you do not.
You seem to be confused regarding the difference between the scope and lifetime of an object.
The scope of an object designates where an object can be accessed by its declared name. For a local variable, that starts at the point it is declared until the block containing it ends, and only within that block.
The lifetime of an object designates how long the memory set aside for it is valid for. For a local variable, that starts and the beginning of the block where it is declared and ends when that block ends, and includes any functions that may be called within that block.
In your first example, l is a local variable in the main function, so its lifetime starts when main starts and ends when main returns, and is still valid when other functions are called within main. That's why you can pass &l to a function and dereference the pointer safely.
In your second example, t is an array local to the build function. Its lifetime starts when the build function is entered and ends when build returns. You then return t from the function. This actually returns a pointer to the first member of the array. So now your main function has a pointer to the first element of t, but since build returned that means the lifetime of t has ended rendering the returned pointer indeterminate, and attempting to dereference it triggers undefined behavior which in your case causes a crash.
As you can see, l is declared in main without a malloc, a calloc or a
realloc. Which means it is declared in stack. And we don't have
control over it.
That l is declared inside main means that it has automatic storage duration and that the scope the identifier l ends at the end of main. Whether such a variable lives on the stack, or whether there even is a stack, is a detail of your C implementation. It is true, however, that you don't have control over where it is allocated.
It should be read only
No. I don't see what gives you that idea.
and can only be modified in the context of
execution (in the main function).
"can be modified" is inconsistent with "read only", but of course I have already denied your assertion about the object being read only.
Now also no, nothing about the declaration of l implies that the object it identifies can be modified only by code in main. The limitation here is that the object can be accessed via its identifier only within the scope of the identifer, which is limited to main. But via its identifier, if it even has one, is not the only way to access an object.
However, we send a pointer to l in the other function as *len.
You obtain a pointer via the address-of operator: &l. Another way to access an object is via a pointer to it. C does not distinguish between objects with different storage durations in this regard (as long as objects are accessed only during their lifetimes), nor does the scope of an identifier come into it other than for obtaining a suitable pointer in the first place.
Having passed that pointer value to your function, it being received as the value of parameter len, in that function the expression *len designates the same object that l designates in main.
And then we increment len (*len++) at the bottom of the function.
Yes. No problem with that.
As I said, it should not be possible since it is not on the heap and
should be read only.
No. Supposing that we stipulate a stack / heap memory arrangement, which indeed is very common, you can obtain a pointer to an object on the stack. That does not move it to the heap, nor make a copy of it on the heap. It just obtains the address of that object, wherever in memory it may be. You would probably be better off forgetting about (this kind of) stack and heap, since again, they are not C language concepts at all.
Moreover, even if you passed a pointer to an object on the heap, there is no reason to think that such an object would be read only.
But this code works and len gets incremented.
Yes.
Am I wrong about memory access ? What did I not get ?
Yes, apparently you are pretty wrong. Stack and heap storage are not C concepts. Pointers can point to any object in the program, stack / heap considerations notwithstanding. Taking the address of an object does not copy or move the object. Nothing about an object being on the heap has anything to do with whether it is read only. Neither does identifier scope.
C doesn't enforce any memory restrictions. Some compilers may generate warnings if you define a pointer as a const, and then try to modify it but that's about it. You are free to modify the heap/stack/anything, and the language is happy to allow it (although you may get a segmentation fault).
The whole point of languages like Rust is that they provide a C-like environment that is memory safe. If you want memory safety, don't use C.
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.
I have code similar to the following in our product. According to me, the output is '0 1 2 3'. But the output of the similar code is '1 1 1 1'.
for(i = 0 ;i < 5;i++){
int j;
if(i)
printf("%d ",j);
j = i;
}
My understanding is that the j is allocated on the stack only once during the entire period of 'for' loop and the same value is used during iterations. Also, if I move the declaration of j outside for loop, I'm getting the expected result. What am I missing here?
PS - When I run the same code on my personal machine, I am getting the expected output. But on production it is different.
First, to clear things about the storage duration of an automatic local variable, let me quote the C11 standard, chapter §6.2.4, (emphasis mine)
An object whose identifier is declared with no linkage and without the storage-class
specifier static has automatic storage duration, [...]
and,
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.
So, in your code, each iteration gets a new instance of j. Nothing is retained.
In your code,
int j; //not initialized
if(i)
printf("%d ",j); //this one here
you're trying to use an unitialized automatic local variable j, which has indeterminate value. It invokes undefined behavior.
As per C11, chapter §6.7.9
If an object that has automatic storage duration is not initialized explicitly, its value is
indeterminate
and related, for UB, annex §J.2
The value of an object with automatic storage duration is used while it is
indeterminate.
Once your code hits UB, the output cannot be justified, anyway.
OTOH, when you declare j outside the loop, it has function scope. Then, unlike above case, there will be only one instance of j for all iterations of the loop.
As per the execution flow, first time, i being 0, if will evaluate to false, printf() will be skipped and j will get initialized. Then, in next iteration, when you hit the printf(), j is initialized and it's all well thereafter.
For some clarity, I think the for loop would be converted under the hood to something like:
i = 0;
LoopStart:
if(!(i<5)){ goto LoopEnd;}
{
int j;
if(i)
printf("%d ",j);
j = i;
}
i++;
goto LoopStart;
LoopEnd:
Actual implementations would differ, but this serves to highlight this point:
The block is entered and exited for each iteration of the loop, meaning each auto in the block is created and destroyed 5 times in this example.
as others mentioned, this means you are using an uninitialized j each time in your printf.
As for why the code might work on some platform / compilers. its probably because j is allocated the same stack address each time, and the compiler doesn't clear the stack when it creates or destroys j, so it just so happens the last value assigned to old, dead j, is accessible through the new, uninitialized one.
#include <stdio.h>
#include <stdlib.h>
void func(int i);
int main() {
int i;
for(i=0;i<3;i++){
func(i);
}
return 0;
}
void func(int i){
int k;
if(i==0){
k=4;
}
printf("%d\n",k);
Sample Run:
4
4
4
Can someone please explain how come k is always equal to 4. Everytime I call the function I am redefining k and how can the value of k be preserved everytime I call the function
You're not initializing k either... so it's probably just re-using the same memory location each time you call the function and it just happens to still be 4 from the first call...
Try this int k = 0;
If you want to preserve the value of K but into the local scope of the function you could use the static type modificator.
static int k=0;
thus, your variable is global from the point of view of duration, but its scope is local to the function or block where it is initialized.
And yes,.. probably the function reuses the same location of k, because you do not initialize its value as Buddy points out.
Your current code exhibits undefined bahaviour (there might be demons flying out of your nose), as k is not initialized. Any value you actually read is invalid (technically: whatever is at its current memory location). Rason is that local variables are not initialized by default for performance reasons.
So, if you do not want that, you have to explictily initialize it by an initial assignment. This may be included in the definition as for any other variable, but with a non-constant expression.
If you want to keep the last value of k, you have to define it static. Note that any initialization is done when the program loads and it does preserve its value between calls. Thus, the initialization has to be a constant expression If you do not explicitly initialize it, it defaults to 0.
Why does the following code output the same memory location everytime?
int x;
for (x = 0; x < 10; x++) {
int y = 10;
printf("%p\n", &y);
}
I thought that the memory location should change as each time the for-loop is run, the variable is new.
Yes, you are absolutely right that the memory location could change. But it doesn't have to :). In each iteration the old variable is "destroyed" and a new one is "created" at the same place. Although any decent compiler would optimize the unnecessary "actions" away
Yes, the variable is new each time around, but at the end of the block any new variables on the stack are released again.
Hence next time around the stack pointer is back exactly where it was. NB: this behaviour is common, but not guaranteed by the standards.
It's a compiler optimization. Because the local variable is going out of scope and a variable of the exact same type is about to be created, it's reusing the memory address. It's important to note that this is still a "fresh" or "new" variable as far as your program is concerned.
Compare the following code snippets and output:
for (i = 0; i < 3; i++) {
int n = 0;
printf("%p %d\n", (void *)&n, n++);
}
0x7fff56108568 0
0x7fff56108568 0
0x7fff56108568 0
for (i = 0; i < 3; i++) {
static int n = 0;
printf("%p %d\n", (void *)&n, n++);
}
0x6008f8 0
0x6008f8 1
0x6008f8 2
The scoping rules for variables only describe the scope in which you have the right to access a local variable: from the definition to the end of its block.
This rule says nothing about the moment that space is reserved for it. A common strategy for that is to reserve space for all variables that will be needed for an invocation of a function at once, at the beginning of the function.
So when execution crosses a definition of a variable, usually nothing particularly has to be done, not a single instruction. On the other hand this leaves the value of that variable to whatever was found there previously. So the importance of initializing to a known state, as you did in your example with the = 10.