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

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
//...
}

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.

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

Pointer at function: access the data inside a structure?

I listed some example code below and the question is if there is a way for the function_name to access the value of number from struct_name?
typedef struct struct_name {
int number
void (*func)();
} * struct_name_ptr;
void function_name() {
//access number from struct
}
main() {
struct_name_ptr newobject;
newobject->func=&function_name;
newobject->func(); //can it print the value of the number in the structure above?
}
Uh - no.
A struct can certainly contain a function pointer. But the function you call wouldn't have any knowledge of the struct. Unless you passed a pointer as a function argument, or made the struct global.
With my limited knowledge of programming, I don't think this is possible. Though the struct contains a function pointer, the address of the function assigned to it is different and I don't think there will be anyway for it to access it unless you pass it as an argument.
Well, two things, struct_name->number should have a value, and it either needs to be in the same scope as &function_name or it needs to be explicitly passed. Two ways to do it:
/* Here is with a global calling struct */
#include<stdio.h>
typedef struct struct_name {
int number;
void (*func)();
} * struct_name_ptr;
struct struct_name newobject = { 0 };
void function_name() {
printf("%d",struct_name);
}
void main() {
struct struct_name_ptr newobject;
newobject->func=&function_name;
newobject->func();
}
/* And one with a modified function_name */
#include<stdio.h>
typedef struct struct_name {
int number;
void (*func)();
} * struct_name_ptr;
void function_name(struct_name) {
printf("%d",struct_name);
}
void main() {
struct struct_name_ptr newobject;
newobject.number = 0;
newobject->func=&function_name;
newobject->func(newobject);
}
No, a pizza won't ever know what the pizza delivery guy, who delivered it, looks like.
A regular function is just an address in memory. It can be called using a function pointer like in this case. In any case: The function won't know how it was called. In particular it won't know that it was called using a function pointer that's part of (a piece of memory corresponding to) some struct.
When using a language with classes like C++, member functions will have a hidden argument which is a pointer to the class instance. That's how member functions know about their data.
You can 'simulate' a simple OOP in plain C, for your example like:
typedef struct {
int number;
void (*func)();
} class;
void function_name(class *this) {
printf("%d",this->number);
}
#define CALL(c,f) c.f(&c)
int main() {
class object={12345,function_name};
CALL(object,func); // voilá
}

Passing struct to function

I'm a new C programmer and I wanted to know how I can pass a struct through to a function. I'm getting an error and can't figure out the correct syntax to do it. Here is the code for it....
Struct:
struct student{
char firstname[30];
char surname[30];
};
struct student person;
Call:
addStudent(person);
Prototype:
void addStudent(struct student);
and the actual function:
void addStudent(person)
{
return;
}
Compiler errors:
line 21: warning: dubious tag declaration: struct student
line 223: argument #1 is incompatible with prototype:
This is how to pass the struct by reference. This means that your function can access the struct outside of the function and modify its values. You do this by passing a pointer to the structure to the function.
#include <stdio.h>
/* card structure definition */
struct card
{
int face; // define pointer face
}; // end structure card
typedef struct card Card ;
/* prototype */
void passByReference(Card *c) ;
int main(void)
{
Card c ;
c.face = 1 ;
Card *cptr = &c ; // pointer to Card c
printf("The value of c before function passing = %d\n", c.face);
printf("The value of cptr before function = %d\n",cptr->face);
passByReference(cptr);
printf("The value of c after function passing = %d\n", c.face);
return 0 ; // successfully ran program
}
void passByReference(Card *c)
{
c->face = 4;
}
This is how you pass the struct by value so that your function receives a copy of the struct and cannot access the exterior structure to modify it. By exterior I mean outside the function.
#include <stdio.h>
/* global card structure definition */
struct card
{
int face ; // define pointer face
};// end structure card
typedef struct card Card ;
/* function prototypes */
void passByValue(Card c);
int main(void)
{
Card c ;
c.face = 1;
printf("c.face before passByValue() = %d\n", c.face);
passByValue(c);
printf("c.face after passByValue() = %d\n",c.face);
printf("As you can see the value of c did not change\n");
printf("\nand the Card c inside the function has been destroyed"
"\n(no longer in memory)");
}
void passByValue(Card c)
{
c.face = 5;
}
The line function implementation should be:
void addStudent(struct student person) {
}
person is not a type but a variable, you cannot use it as the type of a function parameter.
Also, make sure your struct is defined before the prototype of the function addStudent as the prototype uses it.
When passing a struct to another function, it would usually be better to do as Donnell suggested above and pass it by reference instead.
A very good reason for this is that it makes things easier if you want to make changes that will be reflected when you return to the function that created the instance of it.
Here is an example of the simplest way to do this:
#include <stdio.h>
typedef struct student {
int age;
} student;
void addStudent(student *s) {
/* Here we can use the arrow operator (->) to dereference
the pointer and access any of it's members: */
s->age = 10;
}
int main(void) {
student aStudent = {0}; /* create an instance of the student struct */
addStudent(&aStudent); /* pass a pointer to the instance */
printf("%d", aStudent.age);
return 0;
}
In this example, the argument for the addStudent() function is a pointer to an instance of a student struct - student *s. In main(), we create an instance of the student struct and then pass a reference to it to our addStudent() function using the reference operator (&).
In the addStudent() function we can make use of the arrow operator (->) to dereference the pointer, and access any of it's members (functionally equivalent to: (*s).age).
Any changes that we make in the addStudent() function will be reflected when we return to main(), because the pointer gave us a reference to where in the memory the instance of the student struct is being stored. This is illustrated by the printf(), which will output "10" in this example.
Had you not passed a reference, you would actually be working with a copy of the struct you passed in to the function, meaning that any changes would not be reflected when you return to main - unless you implemented a way of passing the new version of the struct back to main or something along those lines!
Although pointers may seem off-putting at first, once you get your head around how they work and why they are so handy they become second nature, and you wonder how you ever coped without them!
You need to specify a type on person:
void addStudent(struct student person) {
...
}
Also, you can typedef your struct to avoid having to type struct every time you use it:
typedef struct student{
...
} student_t;
void addStudent(student_t person) {
...
}
Instead of:
void addStudent(person)
{
return;
}
try this:
void addStudent(student person)
{
return;
}
Since you have already declared a structure called 'student' you don't necessarily have to specify so in the function implementation as in:
void addStudent(struct student person)
{
return;
}

Resources