stack question: a pointer points to a variable inside function(stack) - c

a variable defined in a function is created on stack. then, when function call completed, the variable is vanished due to stack in/out.
the following code is passing a data structure
typedef struct
{
test_out_t output;
test_in_t input;
} message_t;
typedef struct
{
uint8_t len;
uint8_t* data_out;
} test_out_t;
typedef struct
{
uint8_t len;
uint8_t* data_in;
} test_in_t;
The function call is
void test(message_t *msg);
in the function, I defined a array, and assigned the pointer points to this array(the memory location). However, when the function call completed, I am expecting the pointer points the value becomes undetermined/Zeros, since the stack variable is gone.
However, it still has the value of the stack variable if I call printf() inside the function.
with the following code, the msg.output.data_out contains the value of array which created in the function.
If comment out the printf inside the test(). the msg.output.data_out is all zeros.
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#define DATA_SIZE (8)
typedef struct
{
uint8_t len;
uint8_t* data_out;
} test_out_t;
typedef struct
{
uint8_t len;
uint8_t* data_in;
} test_in_t;
typedef struct
{
test_out_t output;
test_in_t input;
} message_t;
void test(message_t *msg);
void test(message_t *msg)
{
uint8_t stackdata[DATA_SIZE];
memset(stackdata, 0, DATA_SIZE);
for (int i=0; i<DATA_SIZE; i++)
stackdata[i] = i+1;
msg->output.len = DATA_SIZE;
msg->output.data_out = stackdata;
uint8_t data2[msg->input.len];
memcpy(&data2, msg->input.data_in, msg->input.len);
for (int i=0; i<msg->input.len; i++)
printf("0x%X\t", data2[i]);
}
int main(void) {
message_t msg;
uint32_t data2 = 0x12345678;
msg.input.len = 4;
msg.input.data_in = (uint8_t*)&data2;
test(&msg);
printf("\n");
for (int i=0; i<msg.output.len; i++)
printf("0x%X\t", msg.output.data_out[i]);
return 0;
}
I assume something related to printf()
BTW, I am using online compiler to run the code.
https://repl.it/languages/c

The rules of C say that, when the lifetime of an object ends1, no guarantee is made to you about it. Thus, you cannot properly use it because you have no guarantee about it. The rules do not say that anything erases or randomizes the object.
In typical implementations, when a function returns, the stack pointer is changed to point to the new top of stack. Nothing does any extra work to erase any data on the stack. So it is still there until something else happens.
That does not mean you can reliably use the space on the stack. A variety of things can alter the data or alter your use of it:
Other routine calls will use the stack.
Other operations in the current routine may use the stack.
Signals could cause the stack to be used.
If the compiler observes your unsupported use of the object, its optimization might transform your program in unexpected ways.
Footnote
1 “The lifetime of an object is the portion of program execution during which storage is guaranteed to be reserved for it” (C 2018 6.2.4 1). For regular objects defined in functions, their lifetimes end when execution of the function ends (usually because the function returned, but possibly because a longjmp was executed or the program is being terminated). So, when the lifetime ends, all it means is that the storage is no longer guaranteed to be reserved. The storage still exists. Nothing is guaranteed to change it. All that changes is that while the function is executing, you are guaranteed the storage is reserved for that object, and, after the function ends, the guarantee is gone.

Related

Passing struct to function call doesn't work

Since C does not support pass by reference, and I'm developing something that cannot use heap memory, how can I make this work? I want the function call set_var_name to actually change the variables global_log instead of just a local copy. Thanks
#include <stdio.h>
struct Record
{
char type[1];
char var_name[1014];
void* var_address;
char is_out_dated[1];
};
struct Global_Log
{
struct Record records[1024];
int next_slot;
};
void set_var_name(struct Global_Log global_log, int next_slot, char* data, int size)
{
for(int i = 0 ; i < size; i++)
global_log.records[0].var_name[i] = data[i];
printf("%s\n",global_log.records[0].var_name);//here prints out "hello"
}
int main()
{
struct Global_Log global_log;
char a[6] = "hello";
set_var_name(global_log, 0, a, 6);
printf("%s\n",global_log.records[0].var_name); // here prints out nothing
return 0;
}
It seems that you are working with a copy of the struct instance, instead of a reference. Try passing a pointer of a struct as a parameter, so you can work with a reference of the instance:
void set_var_name(struct Global_Log* global_log, int next_slot, char* data, int size)
Another alternative is using a global variable, since it sounds like there won't be another instance of it.
C is a call-by-value language -- when you call a function, all arguments are passed by value (that is, a copy is made into the callee's scope) and not by reference. So any changes to the arguments in the function only affect the copy in the called function.
If you want to call "by reference", you need to do it explicitly by passing a pointer and dereferencing it in the called function.

Passing a pointer to a function doesn't work as expected

I have this tiny code :
#include <stdio.h>
#include <stdlib.h>
typedef struct Ship Ship;
struct Ship
{
int x, y;
};
int main()
{
Ship* ship;
assignShip(ship);
printf("%d", ship->x);
return 0;
}
void assignShip(Ship* ship)
{
Ship anotherShip;
anotherShip.x = 10;
ship = &anotherShip;
}
And it doesnt' work.
I create a pointer of type Ship named ship, and then I pass the pointer to my function, I set the pointer to anotherShip and then tries to see if it worked but the console goes in "isn't responding" and crash.
What am I doing wrong ?
There are ... some issues with your code and approach:
Parameters are passed by value
In C parameters are passed by value. This means that assignShip receives a copy of the pointer you have in main. So this assignment ship = &anotherShip; has no effect on the Ship* ship; variable from main, because you modify the local copy the function has.
The fix to this is to have a pointer to the main variable. I.e.:
int main()
{
Ship* ship;
assignShip(&ship); // we pass a pointer to the variable `ship`
printf("%d", ship->x);
return 0;
}
void assignShip(Ship** ship) // receive pointer to pointer
{
Ship anotherShip;
anotherShip.x = 10;
*ship = &anotherShip; // ... still wrong
}
This however brings us to the next big issue you have:
Local function variables have automatic storage duration
anotherShip is local to the function assignShip which means that as soon as the function call ends that variable is destroyed, so in main you will be left with a dangling pointer
The fix to this is to use dynamic allocation:
int main()
{
Ship* ship;
assignShip(&ship);
printf("%d", ship->x);
return 0;
}
void assignShip(Ship** ship) // receive pointer to pointer
{
Ship* anotherShip = malloc(sizeof(Ship));
anotherShip->x = 10;
*ship = anotherShip;
}
Now we have an object will will survive the call to assignShip.
And this brings us to the next problem:
Object with dynamic storage duration must have the lifetime managed by the programmer
Unlike automatic storage duration where the compiler is responsible to manage the lifetime of objects, with dynamic storage duration that is the responsibility of the programmer. So every memory allocated with malloc must be released with free:
int main()
{
Ship* ship;
assignShip(&ship);
printf("%d", ship->x);
free(ship); // free the memory
return 0;
}
And this brings us to the next issue:
Ownership of manually managed resources must be clear
Although the above version of our program is technically correct, there is a problem with they way we handle memory management.
Consider this snippet:
Ship* ship;
assignShip(&ship); // we pass a pointer to the variable `ship`
Does assignShip allocate memory for the parameter. Do we have to call free after it or does it expect to receive a pointer to a valid memory location?
To answer this we must consult the documentation of assignShip (if that exists) and/or the source code of assignShip
One approach is to make that clear from the function name. e.g. allocateAndAssignShip.
The other one is to move the allocation out of the function:
int main()
{
Ship* ship = malloc(sizeof(Ship));
assignShip(ship);
printf("%d", ship->x);
free(ship);
return 0;
}
void assignShip(Ship* ship)
{
ship->x = 10;
}
"What am I doing wrong ?"
A bunch of things.
First, inside function assignShip, the local variable anotherShip goes out of scope at the end of the function, leaving ship pointing to a variable that no longer exists.
Secondly, since you are passing variable ship by value, not reference, you cannot make permanent changes to it from within the function.
Instead:
#include <stdio.h>
#include <stdlib.h>
typedef struct Ship Ship;
struct Ship
{
int x, y;
};
int main()
{
Ship* ship = NULL;
assignShip(&ship);
// Check ship here, it is now non-NULL.
printf("%d", ship->x);
return 0;
}
void assignShip(Ship** ship)
{
static Ship anotherShip;
anotherShip.x = 10;
*ship = &anotherShip;
}
Ship anotherShip; is declared on the stack , once you leave the function the pointer is undeclared which means you assigned undeclared pointer .
either alloc it or make it locally static or globally and it should work

C - Changing the value of a variable outside of a function by passing pointers

I have an assignment in C to implement a abstract data type STACK. The nature of the data type requires key structure that needs to have memory allocated. My problem is that my instructor insists, for now, for the initialization function to take in a pointer to the key structure. The init() function will do nothing more than allocate the memory necessary for the structure and set a field to zero, but the pointer that is passed in needs to be assigned that memory location.
I can't think of a way to do this without either having the function return a pointer, or to pass in a 2-star pointer - both of which are not allowed. I know The function prototype must be (where stackT* is a pointer to the key STACK data structure):
void init(stackT* stack);
I came up with this and it works fine:
void init(stackT** stack){
*stack = (stackT*) malloc(sizeof(stack));
(*stack)->count = 0;
return;
}
But it does not abide by the restrictions of the assignment.
tl;dr version:
Basically, how can I pass in the address of my original pointer to the STACK data structure (&stackPtr) into a function that takes one-star pointers as arguments and not get a pointer-type warning? Further, once you change the arguments to (stackT* stack) the below code does not work, even though I am passing the same thing either way - this is where my problem is.
I thought it is REQUIRED to have the argument as a 2-star pointer if you intend to pass in a pointer to a pointer .. the compiler must know what it is dealing with when you dereference a pointer.
At any rate, I am not sure how to do this given the restrictions. In my opinion this is only making it unnecessarily more difficult.
I believe, as pointed out in a comment, that you're missing the intention.
I think the idea is that the "root" stackT instance should be a well-known structure, so that you can declare one locally. Then you call init() to set up the actual stack described by the stackT instance:
int push_four(void)
{
stackT my_stack;
init(&my_stack);
push(&my_stack, 1);
push(&my_stack, 2);
push(&my_stack, 3);
push(&my_stack, 4);
}
The above assumes that the stack stores integers, i.e. the allocation inside init() should be something like:
void init(stackT *stack)
{
stack->items = malloc(64 * sizeof *items);
stack->count = 0;
}
And this, in turn, assumes a declaration like:
typedef struct {
int *items;
size_t count;
} stackT;
Of course, the default maximum depth (64) should be a parameter to init(), you must check (but not cast!) the return value of malloc(), and so on.
Typically when you have complex structures then there is a control struct and that one will have a pointer to the real memory.
Example:
struct stack_control_s {
void * memory;
size_t memory_size;
size_t current_size;
};
Then you would pass a pointer to the control structure to your initialiser and make it do the real work;
#define STACK_MIN_SIZE 0x100
int stack_init(struct stack_control_s * stack) {
memset(stack, 0, sizeof(*stack));
stack->memory = calloc(STACK_MIN_SIZE, 1);
if (!stack->memory)
return -1; //error
stack->memory_size = STACK_MIN_SIZE;
return 0; // all good
}
Here is a slightly modified header for a generic C list that I once made. I have added to macros to make it useable as a stack. Maybe this will give you some inspirations:
list_t.h
Use:
list_t(char) mylist;
list_init(&mylist);
list_push(&mylist, 'A');
printf("%c\n", list_pop(&mylist));
Probably it is not the best solution, but you can define your stack globally.
In this case it will look like a:
stackT G_stack;
....
void init(stackT* stack){
stack->count = 0;
return;
}
int main() {
.....
init(&G_stack);
.....
}
In this case you don't need to change prototype.
This assignes the pointer the address of the definition of STACK and passes the pointer to be initialized (using a single * :)... Will this work for you?
#include <ansi_c.h>
typedef struct {
int count;
} COUNT;
typedef struct {
COUNT count;
int *element1;
int *element2;
int address;
} STACK;
STACK stack, *pStack;
void InitStack(STACK *iS);
int main(void)
{ //This is how I think you will meet the
//criteria you are talking about (single *)
pStack = &stack; //assigning address of stack to pointer
InitStack(pStack);
//pStack->address == pStack
return 0;
}
void InitStack(STACK *iS)
{
iS->count.count = 0;
iS->address = (int)iS; //assigning address of stack to member of struct
iS->element1 = calloc(10, sizeof(int));
iS->element2 = calloc(10, sizeof(int));
}

C Function implementation - with Pointer vs without Pointer

I've just started to work with C, and never had to deal with pointers in previous languages I used, so I was wondering what method is better if just modifying a string.
pointerstring vs normal.
Also if you want to provide more information about when to use pointers that would be great. I was shocked when I found out that the function "normal" would even modify the string passed, and update in the main function without a return value.
#include <stdio.h>
void pointerstring(char *s);
void normal(char s[]);
int main() {
char string[20];
pointerstring(string);
printf("\nPointer: %s\n",string);
normal(string);
printf("Normal: %s\n",string);
}
void pointerstring(char *s) {
sprintf(s,"Hello");
}
void normal(char s[]) {
sprintf(s,"World");
}
Output:
Pointer: Hello
Normal: World
In a function declaration, char [] and char * are equivalent. Function parameters with outer-level array type are transformed to the equivalent pointer type; this affects calling code and the function body itself.
Because of this, it's better to use the char * syntax as otherwise you could be confused and attempt e.g. to take the sizeof of an outer-level fixed-length array type parameter:
void foo(char s[10]) {
printf("%z\n", sizeof(s)); // prints 4 (or 8), not 10
}
When you pass a parameter declared as a pointer to a function (and the pointer parameter is not declared const), you are explicitly giving the function permission to modify the object or array the pointer points to.
One of the problems in C is that arrays are second-class citizens. In almost all useful circumstances, among them when passing them to a function, arrays decay to pointers (thereby losing their size information).
Therefore, it makes no difference whether you take an array as T* arg or T arg[] — the latter is a mere synonym for the former. Both are pointers to the first character of the string variable defined in main(), so both have access to the original data and can modify it.
Note: C always passes arguments per copy. This is also true in this case. However, when you pass a pointer (or an array decaying to a pointer), what is copied is the address, so that the object referred to is accessible through two different copies of its address.
With pointer Vs Without pointer
1) We can directly pass a local variable reference(address) to the new function to process and update the values, instead of sending the values to the function and returning the values from the function.
With pointers
...
int a = 10;
func(&a);
...
void func(int *x);
{
//do something with the value *x(10)
*x = 5;
}
Without pointers
...
int a = 10;
a = func(a);
...
int func(int x);
{
//do something with the value x(10)
x = 5;
return x;
}
2) Global or static variable has life time scope and local variable has scope only to a function. If we want to create a user defined scope variable means pointer is requried. That means if we want to create a variable which should have scope in some n number of functions means, create a dynamic memory for that variable in first function and pass it to all the function, finally free the memory in nth function.
3) If we want to keep member function also in sturucture along with member variables then we can go for function pointers.
struct data;
struct data
{
int no1, no2, ans;
void (*pfAdd)(struct data*);
void (*pfSub)(struct data*);
void (*pfMul)(struct data*);
void (*pfDiv)(struct data*);
};
void add(struct data* x)
{
x.ans = x.no1, x.no2;
}
...
struct data a;
a.no1 = 10;
a.no1 = 5;
a.pfAdd = add;
...
a.pfAdd(&a);
printf("Addition is %d\n", a.ans);
...
4) Consider a structure data which size s is very big. If we want to send a variable of this structure to another function better to send as reference. Because this will reduce the activation record(in stack) size created for the new function.
With Pointers - It will requires only 4bytes (in 32 bit m/c) or 8 bytes (in 64 bit m/c) in activation record(in stack) of function func
...
struct data a;
func(&a);
...
Without Pointers - It will requires s bytes in activation record(in stack) of function func. Conside the s is sizeof(struct data) which is very big value.
...
struct data a;
func(a);
...
5) We can change a value of a constant variable with pointers.
...
const int a = 10;
int *p = NULL;
p = (int *)&a;
*p = 5;
printf("%d", a); //This will print 5
...
in addition to the other answers, my comment about "string"-manipulating functions (string = zero terminated char array): always return the string parameter as a return value.
So you can use the function procedural or functional, like in printf("Dear %s, ", normal(buf));

What is wrong with this C code

I have a piece of code where I am trying to return the square of the value pointed to by *ptr.
int square(volatile int *ptr)
{
int a,b;
a = *ptr;
b = *ptr;
return a * b;
}
main()
{
int a=8,t;
t=square(&a);
printf("%d",t);
}
Its working fine for me but author of this code said it might not work because of following reason:
Because it's possible for the value of *ptr to change unexpectedly, it is possible for a and b to be different. Consequently, this code could return a number that is not a square!. The correct way to do is
long square(volatile int *ptr)
{
int a;
a = *ptr;
return a * a;
}
I really wanted to know why he said like that?
The idea of the volatile keyword is exactly to indicate to the compiler that a variable marked as such can change in unexpected ways during the program execution.
However, that does not make it a source of "random numbers" - it just advises the compiler - what is responsible for actually changing the variable contents should be another process, thread, some hardware interrupt - anything that would write to the process memory but not inlined in the function where the volatile declaration finds itself. In "older times" (compilers with less magic) everything it did was preventing the compiler from caching the variable value in one of the CPU registers. I have no idea on the optimisations/de-optimistions strategies triggered by it by modern compilers - but it will at least do that.
In the absense of any such external factor, a "volatile" variable is just like any other. Actually - it is just like any other variable - as variables not marked as volatile can also be changed by the same external causes (but the compiled C code would not be prepared for that in this case, which might lead to incorrect values being used).
Since the question has an accepted and correct answer, I will be brief: here is a short program that you can run to see the incorrect behavior happening for yourself.
#include <pthread.h>
#include <math.h>
#include <stdio.h>
int square(volatile int *p) {
int a = *p;
int b = *p;
return a*b;
}
volatile int done;
void* call_square(void* ptr) {
int *p = (int*)ptr;
int i = 0;
while (++i != 2000000000) {
int res = square(p);
int root = sqrt(res);
if (root*root != res) {
printf("square() returned %d after %d successful calls\n", res, i);
break;
}
}
done = 1;
}
int main() {
pthread_t thread;
int num = 0, i = 0;
done = 0;
int ret = pthread_create(&thread, NULL, call_square, (void*)&num);
while (!done) {
num = i++;
i %= 100;
}
return 0;
}
The main() function spawns a thread, and modifies the data being squared in a loop concurrently with another loop calling the square with a volatile pointer. Relatively speaking, it does not fail often, but it does so very reliably in less than a second:
square() returned 1353 after 5705 successful calls <<== 1353 = 33*41
square() returned 340 after 314 successful calls <<== 340 = 17*20
square() returned 1023 after 5566 successful calls <<== 1023 = 31*33
First understand what's volatile: Why is volatile needed in C?
and then, try to find answer by yourself.
It's a game of volatile and hardware world. :-)
Read answer given by Chris Jester-Young:
volatile tells the compiler that your variable may be changed by other means, than the code that is accessing it. e.g., it may be a I/O-mapped memory location. If this is not specified in such cases, some variable accesses can be optimised, e.g., its contents can be held in a register, and the memory location not read back in again.
If there is more than one thread, the value the pointer points to might change inbetween statement "a = *ptr" and statement "b = *ptr". Also: you want the square of a value, why put it into two variables?
In the code you present then there is no way for the variable a that is defined in your main to be modified whilst square is running.
However, consider a multi-threaded program. Suppose that another thread modified the value to your your pointer refers. And suppose that this modification took place after you had assigned a, but before you had assigned b, in the function sqaure.
int square(volatile int *ptr)
{
int a,b;
a = *ptr;
//the other thread writes to *ptr now
b = *ptr;
return a * b;
}
In this scenario, a and b would have different values.
The author is correct (if *ptr will be changed by other threads)
int square(volatile int *ptr)
{
int a,b;
a = *ptr;
//between this two assignments *ptr can change. So it is dangerous to do so. His way is safer
b = *ptr;
return a * b;
}
Because the value of the pointer *ptr might change between the first affection and the second one.
I don't think the value of *ptr can change in this code barring an extremely unusual (and non-standards-compliant) runtime environment.
We're looking at the entirety of main() here and it's not starting up other threads. The variable a, whose address we are taking, is a local in main(), and main() doesn't inform any other function of that variable's address.
If you added the line mysterious_external_function(&a); before the t=square(&a) line, then yes, mysterious_external_function could start a thread and diddle the a variable asynchronously. But there's no such line, so as written square() always returns a square.
(Was the OP a troll post, by the way?)
I see some answers with *ptr can be changed by other threads. But this cannot happen since *ptr is not a static data variable. Its a parameter variable and local and parameter variables being hold inside stack. Each thread has its own stack section and if *ptr has been changed by another thread, it should not effect the current thread's.
One reason why the result might not give the square can be an HW interrupt might happen before assigning b = *ptr; operation as indicated below:
int square(volatile int *ptr) {
int a,b;
a = *ptr; //assuming a is being kept inside CPU registers.
//an HW interrupt might occur here and change the value inside the register which keeps the value of integer "a"
b = *ptr;
return a * b;
}

Resources