C Declare array of struct/pointer to array of structs - c

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.

Related

Struct with pointer to function

can you please explain in details this line of code inside struct:
There is a pointer to function but why would you reference it to struct?
void (*function)(struct Structure *);
what does this mean
(struct Structure *)?
(struct Structure *)
It means that the function have a struct Structure * argument. Actually it will make more sense with (struct Structure *variable of struct).
In this way, you can use a pointer to point a struct and should put the address of the struct variable which can be used in the function.
#include <stdio.h>
typedef struct circle{
int rad;
int area;
} Circle;
void ShowCircleInfo(Circle *info)
{
printf("rad value: %d\n", info->rad);
printf("area value: %d", info->area);
}
int main(void)
{
Circle circle_one;
circle_one.rad = 2;
circle_one.area = 3;
ShowCircleInfo(&circle_one);
return 0;
}
void (*function)(struct Structure *); declares function to be a pointer to a function that has a parameter of type struct Structure * and does not return a value.
For example
#include <stdio.h>
struct Structure {
int a;
void (*function)(struct Structure *);
};
void foo(struct Structure *a) {
if (a->function == NULL) a->function = foo;
a->a++;
printf("%d\n", a->a);
}
int main(void) {
struct Structure a = {42, foo};
struct Structure b = {0}; // don't call b.function just yet!!
a.function(&b); // foo(&b)
b.function(&a); // foo(&a)
}
See code running at https://ideone.com/7E74gb
In C, function pointer declarations have almost the same structure as function headers.
Only the function name will change to have some parantheses and a "*" in it, and the arguments won't have names, because only their types are important when using pointers (we don't access the values of the arguments, so we don't need their names).
They basically look like this:
<return_value> (*<function_name>)(<argument_list>)
So, for example, the function pointer for the function
void swap(int* a, int* b);
would be
void (*swap_ptr)(int*, int*);
Notice that the name of the pointer is in the place of the name of the function, and looks a bit odd compared to normal pointer declarations.
An excellent reading on this topic (you can skip the C++ stuff): https://www.cprogramming.com/tutorial/function-pointers.html

Assign value to struct array without function

I am currently working on a device manager but encountered a problem...
As shown i declared a struct array which is supposed to hold the writer function of a device (vga, serial)... The main issue is that i don't want to call an initialize function, e.g vga_init() or serial_init() to assign them to the structure, tbh that would lose sense... Rather i wanna have those functions stored in an struct array, is there a way to assign vga_write/serial_write without a function, like shown below (Notice the two comments)?
Thanks for incoming advices!
/* device.h */
#define vga 0
#define serial 1
/* device info structure */
struct device_io {
void (*write)(const char *str);
}
extern struct device_io *io[];
/* vga.c */
io[vga] = { .wr = &vga_write }; // Won't work!
void vga_write(const char *str) { ...
/* serial.c */
io[serial] = { .wr = &serial_write }; // Won't work also!
void serial_write(const char *str) { ...
Outside of a function you can only use an initializer expression to assign a value to a global (or static or bss) variable.
That in turn means the initializer expression you're using must initialize the entire array at once, like so:
static int test[] = { 4, 5, 6 };
, which, of course, can be extended to arbitrary data like function pointers or structs
void some_func0(const char *v) { }
void some_func1(const char *v) { }
static void (*test[])(const char *) = { &some_func0, &some_func1 };
. As you can see though, this requires that all the functions you intend to use are at least declared before the initializer. At the point of declaration of the array in your question (in "device.h") I presume you don't know all implementations.
However, you need to have a source file somewhere in your program where you do know all array elements at once. To work around this, you can restructure your code like:
device.h
extern void (*test[])(const char *); // <-- or your struct type
vga.h
extern void vga_write(const char *);
vga.c
void vga_write(const char *c) {...
device_array_initialization_helper_this_is_a_very_verbose_file_name.c
#include "device.h"
#include "vga.h"
// Definition of the array, which is declared in device.h
void (*test[])(const char *) = { &vga_write, ... };
Of course, you can use your struct type as well.

How to declare a function that has a structure containing an array, whose size is determined by argv, as an argument?

I have a structure dt that contains an internal array whose size is determined by argv. I need to feed this structure to a function func so I tried to declare it with a void pointer argument but the compiler is complaining that it's not being void at the end of the day. Here is the code :
#include <stdio.h>
#include <string.h>
void func(void *);
int main(int argc, char *argv[])
{
int RETSIZE;
sscanf(*++argv, "%d", &RETSIZE);
struct
{
char name[6];
char ret[RETSIZE];
} dt[100];
func(dt);
}
void func(void *dt)
{
dt->ret[2] = 3;
}
How and where do I declare the structure dt and the function func so it works out ?
If you want to use a structure in two (or more) functions, you need to define it in the global scope, so both functions have access to it. There's simply no way around it.
As for the array, in this case it's not possible to use variable-length arrays. You need to either use a flexible array member or to use a pointer. Both of these requires dynamic allocation of the heap. You also need to keep the number of elements in the array as a member in the structure.
Try This:
#include <stdio.h>
#include <string.h>
#define MAX_OBJECT 100
typedef struct
{
char name[6];
char ret[];
} dt;
void func(dt *strPtr)
{
strPtr->ret[2] = 3;
}
int main(int argc, char *argv[])
{
dt obj[MAX_OBJECT];
func(&obj[0]);
printf("Verify values written successfully or not: %d \n",obj[0].ret[2]); //Just for example
}
Here are few corrections/comments for your code:
- Keep the struct in global scope so that the struct is visible to all the whole code.
- In the func void func(void *dt), you should again type cast it the original datatype(struct in this case), in order to use it.
- As suggested in the above post, in C lang the size of the array(string) should be known to the compiler. Or else some garbage value will be present in RETSIZE and that much amount of stack memory is allocated to the ret. So, the struct should be
struct mystruct
{
char name[6];
char *ret;
};
And for memory allocation,
dt.ret = (char *)malloc(RETSIZE*sizeof(char));
- Also your func should be modifed cuz you have declared an struct array of 100, and you are passing it to the func

How to access elements in an array of structs (not global)

Trying to continue with my assignment but would like to sidetrack and figure out how array of structs work. Not sure if I'm not looking hard enough but I can't seem to find an answer.
Let's say I have one source file, main.c
#include "data.h" //this contains the struct data.
newPerson person[20];
int mainMenu(){
addName();
}
void addName(){
strcpy(person[0].firstName, "George");
}
Doing it this way, I'm able to access the array of struct, however isn't this method considered taboo since my array of person is a global variable?
I then tried moving the array initialization into the main function instead
#include "data.h" //this contains the struct data.
int mainMenu(){
newPerson person[20];
addName();
}
void addName(){
strcpy(person[0].firstName, "George");
}
Doing it this way, when I get to the addName() function, I get a 'person undeclared' error. How can I access the person[] array outside of its function without making it a global variable? Thank for the help in advance. Below I have the example data.h included if needed.
data.h
typedef struct person{
char firstName[20];
char familyName[20];
char telephoneNum[20];
}newPerson;
Just pass parameters to the addName() function.
Example
#include "data.h" //this contains the struct data.
int mainMenu(){
newPerson person[20];
addName(person, 0, "George");
}
void addName(newPerson *person, unsigned int index, const char *const name) {
if ((person == NULL) || (index >= 20))
return; /* ^ this number could be specified with a macro */
/* or via a parameter */
strcpy(person[index].firstName, name);
}
Yeah, pass the variable, person in this case.
person is an array of struct newPerson.
to pass arrays as parameters you should define the function like this
//Option 1, the last dimension without number
void addName(newPerson person[]){
//...
}
//Option 2, as a pointer, but it neets a cast on the call (newPerson*)
void addName(newPerson *person){ //I prefer option 1
//...
}

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;

Resources