return static structure array pointer with get() - c

I have a file in my project that has a local structure array defined like MyStruct_t myStruct[SIZE] which I can use well within that module. Now I would like to make it accessible to a different code module, so I came up with a function:
MyStruct_t *GetStruct(void) {
return myStruct;
}
But when I call this from my different module, I get an error expression must be a modifiable lvalue. My caller looks like:
void myFunc(void) {
MyStruct_t locStruct;
locStruct = GetStruct();
}
How can I do this best?

GetStruct returns a pointer to myStruct[SIZE] element, not a MyStruct_t. Unless you really need a copy, make locStruct a pointer, like this:
MyStruct_t *locStruct = GetStruct();
note that locStruct is an array of MyStruct_t, of size SIZE.
If you do want to make a copy, dereference GetStruct()'s result:
MyStruct_t locStruct = *GetStruct();
This would produce a copy of the initial element of myStruct array.
Since GetStruct does not provide additional services except accessing myStruct, you might as well make myStruct global (extern) instead of static.
Finally, you could change GetStruct to access a specific element. This would also take care of detecting overruns - i.e. attempts at getting an element past the SIZE or at a negative index:
bool GetStruct(int index, MyStruct_t *ptr) {
if (index < 0 || index >= SIZE) {
return false;
}
*ptr = myStruct[index];
return true;
}
Now the call of GetStruct() would look like this:
MyStruct_t locStruct;
if (GetStruct(5, &locStruct)) {
// All good
} else {
// Error
}

For example you can do the following way
void myFunc( void )
{
MyStruct_t locStruct[SIZE];
MyStruct_t *p = GetStruct();
memcpy( locStruct, p, SIZE * sizeof( MyStruct_t ) );
}
Or it might be enough to have a pointer to the first element of the array
void myFunc( void )
{
MyStruct_t *locStruct = GetStruct();
}
In this case the syntax for accessing elements of the array will be the same as for example locStruct[i]

GetStruct returns a pointer, so your locStruct variable should be a pointer, too.
void myFunc(void) {
MyStruct_t *locStruct;
locStruct = GetStruct();
}

If myStruct is global in the other module, then you might be looking for the extern keyword. Just put this in the other module:
extern MyStruct_t myStruct[];
(I've assumed MyStruct_t is a typedefed name. Otherwise you'd need to put the keyword struct before it, of course.)
This also requires access to the declaration of MyStruct. Put that in a header file and include it in both modules.
Here's a simple example:
// main.h ------------------------------------------------
typedef struct {
int a, b, c;
} AStruct;
// func.h ------------------------------------------------
void func(void);
// main.c ------------------------------------------------
#include <stdio.h>
#include "main.h"
#include "func.h"
AStruct as[100];
int main(void) {
func();
printf("%d,%d,%d\n", as[0].a, as[0].b, as[0].c);
return 0;
}
// func.c ------------------------------------------------
#include "main.h"
#include "func.h"
extern AStruct as[];
void func(void) {
as[0].a = 1;
as[0].b = 2;
as[0].c = 3;
}

Related

C Declare array of struct/pointer to array of structs

I have an example tutorial with 2 files, "functions.c" and "functions.h" which contain the prototypes and the body of the functions.
In the example there isn't the main that containing the declaration of the array of struct/pointer to array of structs and the calls to the functions.
functions.c:
#include "functions.h"
const char *getTeamA(const sTest *p)
{
return p->teamA;
}
void setTeamA(sTest *p, char *s)
{
strcpy(p->teamA, s);
}
int getNum(const sTest *p)
{
return p->num;
}
void setNum(sTest *p, int i)
{
p->num = i;
}
functions.h:
#ifndef FUNCTIONS_H_
#define FUNCTIONS_H_
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_CHAR 20
#define SIZE 5
typedef struct {
char teamA[MAX_CHAR];
int num;
// ...
} sTest;
const char *getTeamA(const sTest *p);
void setTeamA(sTest *p, char *s);
int getNum(const sTest *p);
void setNum(sTest *p, int i);
#endif /* FUNCTIONS_H_ */
So my question is
How can i declare the struct according to the code written above?
So for example:
int main()
{
sTest data[SIZE]; //size isn't important
sTest *dataPtr = data;
setTeamA(dataPtr[0].teamA, "name1");
// ...
printf("%d", getNum(dataPtr[1].num)); // just an example. i know that it isn't initialized
// ...
return 0;
}
Is this the correct way? Or is there a better way to declare variables and pass them to the functions?
The important thing is that i have to stick to the code written in functions.c and functions.h, so the functions cannot directly modify the struct data, you need to use pointers (because there are member selection operator "->" in functions.c).
You don't need to have dataPtr. You can do the exact same thing by doing data[i], since you declared data as an array of sTests, and so data points to the first element in the array.
Let's deconstruct what you're doing when you're calling setTeamA(dataPtr[0].teamA, "name1"). You're trying to set the first sTest struct in the data array to have "name1" as the teamA field. Notice that the prototype for setTeamA() actually takes in a sTest *p. In your example, you're passing in the teamA field. So what you really want to call is setTeamA(&dataPtr[0], "name1"). This translates to the pointer pointing to the data at dataPtr[0].
While this works, as I said before, the dataPtr is unecessary. So this is equivalent to:
setTeamA(&data[0], "name1").
Also worth noting, you can simply write:
setTeamA(data, "name1")
since data is already a pointer to the first element in the array.
Use
setTeamA(&data[0], "name1")
It indexes to index 0 and then takes the reference (which is a pointer) of the result therefore making the type an sTest* then the setTeamA function will do it's job setting the teamA field.
That dataPtr variable is useless here.

Pointer to pointer , values not updating

global.h
typedef enum _global_list {
TEST_VAR1,
TEST_VAR2
} list;
/*Mapper between enum varibales and global variable*/
typedef struct _var_map{
list list_type;
void *ptr;
} var_map;
/*struct to hold global variable*/
typedef struct _glo_ptr{
int *ptr1;
float *ptr2;
} g_ptr;
g_ptr ptr;
void update_global(list ,void *);
global.c
#include "globals.h"
static var_map map[2] = { { TEST_VAR1, &(ptr.ptr1) }, { TEST_VAR2, &ptr.ptr2 } };
update_global(list var, void* ptr){
if (map[0].list_type == TEST_VAR1){
map[0].ptr = ptr;
}
}
testfile.c
#include "globals.h"
int main(){
int test_var1=0;
update_global(TEST_VAR1, &test_var1);
test_var1=4;
printf("%d",*ptr.ptr1); //should contain value 4
}
What I'm trying to do is: my g_ptr should contain latest values pointed by it. But in pointer to pointer I'm doing somewhere some mistake leading not proper update of values. For exmple: my final g_ptr.ptr1 value should contain 4. What needs to be corrected in this?
Problem is you're changing the actual pointer in your map, but not affecting the data being pointed to:
map[0].ptr = ptr;
Should be:
*(int**)map[0].ptr = (int*)ptr;
The motivation behind your program is a little suspect, but I believe this will give you what you are looking for... I will keep my distance =)
Oh, I noticed another thing... You declare separate instances of ptr. When you include global.h in each source file, they see ptr as a private static variable. That's not what you want. You need to declare and define it like this:
global.h
extern g_ptr ptr;
global.c
g_ptr ptr;

Variable-length array in file scope?

I have this code for example.
#include <stdlib.h>
#include <stdio.h>
#define array_size 3
typedef struct {
int array[array_size];
} TEST;
void printout(TEST *p, int element) {
printf("element: %i\n", p->array[element]);
}
int main(void) {
TEST *p;
p = malloc(sizeof(TEST));
p->array[0] = 5;
printout(p, 0);
return 0;
}
But I'd like to assign "array_size" based on user input.
If I try to do so, the compiler says "variably modified ‘array_size’ at file scope". So, am I right that the only way to do what I want is to move everything to main()..?
It works just fine, but keeping structs and functions declarations in file scope seems, you know, neat.
The simplest approach is to just allocate the memory dynamically:
typedef struct {
int *array;
size_t size;
} TEST;
int main() {
size_t elem_count = /* from user input */
TEST p;
p->array = malloc(elem_count * sizeof int);
if(!p->array)
return -1;
p->size = elem_count;
/* ... */
free(p->array);
}
You can indeed not define a variable length array at file scope, you can however define a pointer at file scope and malloc it, just define a global pointer int* p = NULL; (lose the whole TEST stuff) and p = malloc(sizeof(int) * input_size); simply access with p[x].
For completeness, you can also use the so called flexible array member defined in C99:
From ISO/IEC 9899:1999, Section 6.7.2.1, paragraph 16:
As a special case, the last element of a structure with more than one
named member may have an incomplete array type; this is called a
flexible array member.
typedef struct {
other_type other_data
int array[];
} TEST;
...
TEST *p = malloc(sizeof(TEST) + sizeof(int) * input_size);
Though note that this is limited to a single member, you could make an array of structs if you would otherwise have multiple arrays of different types but the same length.
This was originally intended mostly for data with headers such as ofter encountered in file and/or network I/O.

Accessing a general structure member using a variable

Not entirely sure my question title describes what I want to do, but couldn't think how better to word it!! I'm using C, and perhaps the pseudocode below will describe what I'm trying to do:
typedef struct obj
{
char *str1;
char *str2;
char *str3;
} object;
/* global variable */
object *glob;
void black_box_function(local, member) ????
{
/* Do something with glob->member and local->member */
}
void main()
{
object *ob1, *ob2;
/* Initialise glob, ob1 and ob2 somewhere */
black_box_function(ob1, str1);
black_box_function(ob2, str3);
}
Hopefully, you can see what I'm trying to do. I have a "black-box" function that will do something with a particular member, and I need to be able to tell the black-box function which member to use.
I don't want to just pass the member directly to the function, like in this code, as that won't fit into the rest of my code easily.
black_box_function(ob1->member, glob->member)
You could do the following magic (with GCC extensions):
#define black_box(local, member) black_box_function((local), __builtin_offsetof(object, member))
void black_box_function(object *local, int offset)
{
char *lmember = ((void *)local) + offset;
char *gmember = ((void *)global) + offset;
/* do stuff */
}
However, you must know in advance the type of your members. Keep in mind that C is not a dynamically typed language, so you have no runtime introspection at all.
EDIT: You can implement offsetof() functionality without resorting to GCC extensions, like this:
#define offsetof(type, field) ((int) (unsigned long) &((type *) 0)->field)
Perhaps you could create accessor functions for your struct and pass those accessors as function pointer arguments instead of passing the members directly
typedef struct
{
int a;
int b;
} foo;
typedef int* (*accessor)(foo*);
int* get_a(foo* f) { return &f->a; }
int* get_b(foo* f) { return &f->b; }
void black_box_function(foo* object, accessor fn)
{
int* p = fn(object);
}
int main(void)
{
foo bar1;
foo bar2;
black_box_function(&bar1, get_a);
black_box_function(&bar2, get_b);
return 0;
}
Since all are char*, you can redefine the struct like:
typedef struct obj
{
char **str; // Array of c
} object;
Then you can send the index of str from main which you want work with:
black_box_function(obj1, index)
So you can it like obj1->str[i] in your blackbox.
Btw, black-box_function will not compile.
On a side note: A little more info/code on your blackbox function and compilable code would give a better picture of what you are trying to do.

Return a struct from a function containg a static array in C

struct MyStruct
{
int i;
double arr[10];
};
struct MyStruct func()
{
};
When returned from the function, will be fully copied to a local variable?
struct Mystruct ms = func();
Yes you can, the structure will be fully copied.
Yes, if func() returns a variable of type Mystruct.
The correct way to do this:
void func(struct MyStruct* by_ref);
int main()
{
struct MyStruct ms;
func(&ms);
}
This won't upload a bombastic struct on the stack, nor will you get issues with static variables. Returning a pointer to a static variable is very bad for the following reasons:
It breaks private encaptulation. Very bad program design.
A multi-threaded program doing this gets vulnerable.
Pure bugs, as in this example:
static uint8 static_str[6];
uint8* func(const uint8 str[6])
{
uint8 i;
for(i=0; i<6; i++)
{
static_str[i] = str[i];
}
return static_str;
}
int main()
{
print_strings(func(“hello”), func(“world”));
}
The output from a function printing the two strings will be either “hello hello” or “world world” (depending on the order of evaluation of function parameters).
You have no return value so in any case you need to set that. Furthermore, it is better to use a pointer:
struct MyStruct* func()
{
struct MyStruct *pMyStruct=calloc(1,sizeof(struct MyStruct));
/* fill struct */
return pMyStruct;
};

Resources