C: Store reference to stack variable in array - c

I'm writing a program that's running on an embedded MCU, so all of my memory allocations are to the stack (no malloc()). I have a struct being created in a function and returned to a caller, and I'm trying to keep a reference to that variable in an array, prior to being returned.
The problem is that the variable stored in the array seems to be a copy of the variable returned to the caller, so they're not in sync. The code below illustrates the issue:
#include <stdio.h>
int *ARRAY_OF_VARIABLES[1];
int initalizeVariables() {
int i = 0;
ARRAY_OF_VARIABLES[0] = &i;
return i;
}
int main(void)
{
int test = initalizeVariables();
test = 1;
printf ("Test: %d, ARRAY_OF_VARIABLES[0]: %d\r\n", test, (int)*ARRAY_OF_VARIABLES[0]);
}
This prints: Test: 1, ARRAY_OF_VARIABLES[0]: 0
How can I keep "test" and "ARRAY_OF_VARIABLES[0]" in sync without malloc() and pointers?

I solved this by creating a function that I can pass a pointer of i back into for storage in ARRAY_OF_VARIABLES. Here's the new code:
#include <stdio.h>
int *ARRAY_OF_VARIABLES[1];
int initalizeVariables() {
int i = 0;
return i;
}
void setInArray(int *i, int idx) {
ARRAY_OF_VARIABLES[idx] = i;
}
int main(void)
{
int test = initalizeVariables();
setInArray(&test, 0);
test = 123;
printf ("Test: %d, ARRAY_OF_VARIABLES[0]: %d\r\n", test, *ARRAY_OF_VARIABLES[0]);
}
If there are any better ways to do this, please feel free to post them :).

Related

initialize struct from function call

Feel like im taking crazy pills just trying to do literally the simplest stuff I can imagine in C. Any help would be extremely appreciated. why does this work?
#include <stdio.h>
#include <stdlib.h>
#define Q_LIMT 100
typedef struct servers
{
int id;
int num_in_Q;
int server_status;
}SERVER;
void initialize(SERVER *s);
void initialize(SERVER *s)
{
int i=0,j=0;
for(i=0; i<2; i++) { //i=0; i=1
s[i].id = i; // 0, 1
s[i].num_in_Q = i*i + 1; // 1, 2
s[i].server_status = i+i + 2; // 2, 4
} // the bracket was missing
}
int main()
{
int i;
SERVER serv[2];
initialize(serv);
for(i=0; i<2; i++) {
printf("server[%d].id = %d\n", i, serv[i].id);
printf("server[%d].num_in_Q = %d\n", i, serv[i].num_in_Q);
but this throws away the initialized struct?
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
'''
int POINTERS_PER_INODE = 5;
struct Inode {
int valid;/* 0 == invalid, 1 == valid*/
int size;
int Blocks [5];
};
int InodeToString(char * InodeString, struct Inode iNode){
char * blockBuffer;
sprintf(InodeString, "%d", iNode.valid);
int i;
for (i = 0; i < POINTERS_PER_INODE; i++){
blockBuffer = malloc(8);
sprintf(blockBuffer, "%d", iNode.Blocks[i]); //no valid pointers yet
strcat(InodeString,blockBuffer);
free(blockBuffer);
}
return 0;
}
int initializeInode(struct Inode iNode){
int i;
for (i = 0; i < POINTERS_PER_INODE; i++){
iNode.Blocks[i] = -1; //no valid pointers yet
}
iNode.valid = 0; //initialized as invalid inode
return 0;
}
int main() {
struct Inode iNode1;
initializeInode(iNode1);
char * InodeString;
InodeString = malloc(20);
InodeToString(InodeString, iNode1);
printf("%s", InodeString);
free(InodeString);
iNode1.valid = 1;
InodeString = malloc(20);
InodeToString(InodeString, iNode1);
printf("%s", InodeString);
return 0;
}
This is test code btw, so the includes probably dont make sense. stack overflow says I dont have enough details so I guess I have to keep typing sentences. Let me know if theres any details that would make this more clear. its for a basic super simplified file system simulation project. it seemed in a previous version when I initialized the inode outside of the function, I was able to pass the string into the string function, assign it values, not use it as the return value and still end up on the other side of the function with an updated string.
As is normal in C, arguments to a function are passed by value. The object called iNode in initializeInode is local to that function, and changes to it have no effect on any other object in the program. If you want a function to modify an object that's local to the caller, you have to pass a pointer to it, and dereference that pointer to get at the caller's object.
So what you probably want is:
int initializeInode(struct Inode *iNode){
int i;
for (i = 0; i < POINTERS_PER_INODE; i++){
iNode->Blocks[i] = -1; //no valid pointers yet
}
iNode->valid = 0; //initialized as invalid inode
return 0;
}
int main() {
struct Inode iNode1;
initializeInode(&iNode1);
// ...
}

Global pointers between functions

So I was trying to use a global pointer that I define in a function and I'm going to use in another function without passing as parameters.
Here is my fun.c file
#include <stdio.h>
#include <stdlib.h>
int *step;
int step_counter;
int init(int num){
step = &num;
step_counter = *step;
return 0;
}
void reset_counter(){
step_counter = *step;
printf("%d ", step_counter);
}
Here is the main.c file
#include <stdio.h>
#include <stdlib.h>
#include "fun.c"
int main()
{
init(3);
reset_counter();
return 0;
}
I was expecting that the reset_counter function to print 3. But instead it prints out 0. I don't know what's the problem. I'm pretty new to C.
You have undefined behavior.
You point step to the address of num but num is a local variable that's destroyed after init() returns. Trying to derefence step in reset_counter() gives you UB as what it's pointing to is already destroyed.
Why are you using a pointer for step? You could just use step = num; and have step be an int.
In this function
int init(int num){
step = &num;
step_counter = *step;
return 0;
}
parameter num is a local variable of the function. After exiting the function the variable will not be alive and its memory can be reused by some other parts of the program.
As result the pointer step will have an invalid value and the program will have undefined behavior if it'll try to access the memory pointed to by the pointer.
You could rewrite the function the following way.
int init(int num){
step = malloc( sizeof( *step );
int success step != NULL;
if ( success )
{
*step = num;
step_counter = *step;
}
return success;
}
You should not forget to free the pointer before exiting the program.
Though it is not clear why you need the additional variable step_counter.
I would rewrite the code snippet the following way
int *step;
int init(int num){
step = malloc( sizeof( *step ) );
int success = step != NULL;
if ( success ) *step = num;
return success;
}
void reset_step(){
free( step );
step = NULL;
}

Pointers to structures, fields changing values inexplicably

I'm fully prepared to be told that I'm doing something stupid/wrong; this is what I expect.
I'm getting a feel for structures and coming a cropper when it comes to accessing the fields from the pointers. Code to follow.
matrix.h:
#ifndef MATRIX_H_INCLUDED
#define MATRIX_H_INCLUDED
#include <stdlib.h>
typedef struct
{
size_t size;
int* vector;
} vector_t;
#endif // MATRIX_H_INCLUDED
main.c:
#include <stdio.h>
#include <stdlib.h>
#include "matrix.h"
vector_t* vector_new(size_t size)
{
int vector[size];
vector_t v;
v.size = size;
v.vector = vector;
return &v;
}
int main(int argc, char* argv[])
{
vector_t* vec = vector_new(3);
printf("v has size %d.\n", vec->size);
printf("v has size %d.\n", vec->size);
return EXIT_SUCCESS;
}
So this is a very simple program where I create a vector structure of size 3, return the pointer to the structure and then print its size. This, on the first print instance is 3 which then changes to 2686668 on the next print. What is going on?
Thanks in advance.
You are returning a pointer to a local variable v from vector_new. This does not have a slightest chance to work. By the time vector_new returns to main, all local variables are destroyed and your pointer points to nowhere. Moreover, the memory v.vector points to is also a local array vector. It is also destroyed when vector_new returns.
This is why you see garbage printed by your printf.
Your code has to be completely redesigned with regard to memory management. The actual array has to be allocated dynamically, using malloc. The vector_t object itself might be allocated dynamically or might be declared as a local variable in main and passed to vector_new for initialization. (Which approach you want to follow is up to you).
For example, if we decide to do everything using dynamic allocation, then it might look as follows
vector_t* vector_new(size_t size)
{
vector_t* v = malloc(sizeof *v);
v->size = size;
v->vector = malloc(v->size * sizeof *v->vector);
return v;
}
(and don't forget to check that malloc succeeded).
However, everything that we allocated dynamically we have to deallocate later using free. So, you will have to write a vector_free function for that purpose.
Complete re-write of answer to address your question, and to provide alternate approach:
The code as written in OP will not compile: &v is an illegal return value.
If I modify your code as such:
#include <stdlib.h>
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
size_t size;
int* vector;
} vector_t;
vector_t* vector_new(size_t size)
{
int vector[size];
vector_t v, *pV;
pV = &v;
pV->size = size;
pV->vector = vector;
return pV;
}
int main(int argc, char* argv[])
{
vector_t* vec = vector_new(3);
printf("v has size %d.\n", vec->size);
printf("v has size %d.\n", vec->size);
getchar();
return EXIT_SUCCESS;
}
It builds and runs, but returns unintended values for vec->size in main() due to the local scope of that variable in the function vector_new.
Recommend creating globally visible instance of your struct, and redefine vector_new() to int initVector(void):
#include <stdlib.h>
#include <stdio.h>
#include <stdlib.h>
#define SIZE 10
typedef struct
{
size_t size;
int* vector;
} vector_t;
vector_t v, *pV;//globally visible instance of struct
int initVector(void)
{
int i;
pV->size = SIZE;
pV->vector = calloc(SIZE, sizeof(int));
if(!pV->vector) return -1;
for(i=0;i<SIZE;i++)
{
pV->vector[i] = i;
}
return 0;
}
int main(int argc, char* argv[])
{
int i;
pV = &v; //initialize instance of struct
if(initVector() == 0)
{
printf("pV->size has size %d.\n", pV->size);
for(i=0;i<SIZE;i++) printf("pV->vector[%d] == %d.\n", i, pV->vector[i]);
}
getchar(); //to pause execution
return EXIT_SUCCESS;
}
Yields these results:
You still need to write a freeVector function to undo all the allocated memory.

How to realloc a memory? I keep getting segmentation fault

I keep geeting a segfault in the main function. I create a pointer to a struct I created and I pass it's reference to another function which allocates and reallocates memory. Then accessing it in the main function (where it was originally defined) causes a segfault.
Here is my test code:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef struct {
char desc[20];
int nr;
} Kap;
void read(Kap *k);
int main(void) {
Kap *k = NULL;
read(k);
printf("__%s %d\n", k[4].desc, k[4].nr);
return 0;
}
void read(Kap *k) {
int size = 3;
k = (Kap*) calloc(size, sizeof(Kap));
k[0].nr = 1;
k[1].nr = 2;
k[2].nr = 3;
strcpy(k[0].desc, "hello0");
strcpy(k[1].desc, "hello1");
strcpy(k[2].desc, "hello2");
size *= 2;
k = (Kap*) realloc(k, sizeof(Kap)*size);
if(k == NULL) {
printf("ERROR\n");
exit(EXIT_FAILURE);
}
k[3].nr = 4;
k[4].nr = 5;
k[5].nr = 6;
strcpy(k[3].desc, "hello3");
strcpy(k[4].desc, "hello4");
strcpy(k[5].desc, "hello5");
}
What am I doing wrong?
Here's a simplified version of the problem you are having:
#include <stdio.h>
void func(int x)
{
x = 10;
}
int main()
{
int x = 5;
printf("x = %d\n", x);
func(x);
printf("x = %d\n", x);
}
The same reason x does not change is the reason that k does not change in your program. A simple way to fix it is this:
Kap *read()
{
Kap *k = calloc(...);
...
k = realloc(k, ...);
...
return k;
}
int main()
{
Kap *k = read();
...
}
The problem is you're not passing the pointer back to main(). Try something like this instead:
Kap * read();
int main(void) {
Kap *k = read();
printf("__%s %d\n", k[4].desc, k[4].nr);
return 0;
}
Kap * read() {
... everything else you're already doing ...
return k;
}
The code you showed passes a pointer by value into read(). The subroutine can use that pointer (though it's kind of useless since its local copy is immediately changed), however changes made within read() do not bubble back to its caller.
My suggestion is one method of allowing read() to send the new pointer back up, and it's probably the right method to choose. Another method is to change read()s signature to be void read(Kap **);, where it will receive a pointer to a pointer -- allowing it to modify the caller's pointer (due to being passed by reference).

Errors when passing array by value in C, using a callback implementation

My program includes three files: main.c, app.c and callbk_struct.h
The function "get_data" in main.c makes callbacks to a function in app.c, which returns an array of integers.
When I print the array in "get_data", using "printf", everything seems to be fine.
But if I try to pass the array to another function, in this case the function "print_buffer" or "sizeof", something weird happens. I usually don't get problems when passing arrays between functions like this...
Could someone explain what is going on here?
See my program below:
callbk_struct.h
struct callback_struct{
int * (*ptr_data)(void);
};
extern struct callback_struct user_functions; // is defined in app.c
app.c
#include <stdio.h>
#include "callbk_struct.h"
int* my_data(void);
struct callback_struct user_functions={
.ptr_data = my_data,
};
int* my_data(void){
int i;
// create some test data
int N = 15;
int data[N];
for(i=0; i<N; i++){
data[i] = i;
}
return data;
}
main.c
#include <stdio.h>
#include "callbk_struct.h"
#define MAX_DATA 15
void print_buffer(int *data){
int i;
for(i = 0; i < MAX_DATA; i++){
printf(" %d ", data[i]);
}
}
void get_data(int* (*ptr)(void)){
int *data = ptr();
// If I try to print the values directly with printf, I get the right values
printf("Data from app.c %d %d %d", data[0], data[1], data[2]);
//If I try to get the number of elements in the array, I get weird values..
int data_size = sizeof(data)/sizeof(int);
// If I try to print the array, via this function, I get weird values..
print_buffer(data);
}
int main(void){
get_data(user_functions.ptr_data);
return 1;
}
The weird values are caused by returning from my_data the local array, which ceases to exist when the value is returned from the function, so the behaviour of your program is undefined.

Resources