Functions to return a structure in c - c

I have a fight game between 4 Magicians and 1 Demon in C.
Each of them have 3 attributes :
NAME
PV(Life points)
PM(Magic points)
I had to create a structure for Magician and Demon so i wrote :
struct Magician{
char name_magician[20];
int pm;
int pv;
};
struct Demon{
char name_demon[20];
int pv;
int pm;
};
typedef struct Magician magician;
typedef struct Demon demon;
Now:
How can i create a function that create a Demon?
And a function to create a group of 4 Magicians ?
What i tried in main function basically the simple :
demon d1;
d1.name_demon="demonx123";
d1.pv=15;
d1.pm=20;

Returning a single structure from a function is easy: You do it just like any other function returning a value:
demon create_demon(void)
{
demon d;
// Initialize the demon
return d;
}
Returning an array of multiple structures is a little harder, but just like for returning a single structure is the same as returning any value, returning an array of structures is exactly the same as returning an array of any other value. This can be done either by allocating on the heap, and returning a pointer. Or by passing a pointer to the first element as an argument to the function.

To make group of Magician, you can use array of Magician structure.
Something like...
> struct Magician m[4];
Use this statement in a function.
This will create you 4 members of Magician.Now you can initialize them as you are doing for demon.

struct Magician *m = malloc (sizeof(struct Magician)*NumOfMagitians);
And return the pointer

This way you can easily create your demons.
struct demon *createDemon(char *name, int pv, int pm){
struct demon *tmp = malloc(sizeof(struct demon));
if (tmp == NULL || sizeof(tmp->name) < strlen(name))
return NULL;
for (int i = 0; i < strlen(name); i++)
tmp->name[i] = name[i];
tmp->pm = pm;
tmp->pv = pv;
return tmp;
}
And in case you wonder, this way you can remove it again.
void removeDemon(struct demon *dtr){
if (dtr != NULL){
free(dtr);
}
}
To make your structure a little less static you should however change
the way you initialize the name of your creature, like:
struct demon{
char *name;
int pv;
int pm;
};
This way you can allocate the space you need for your creatures name dynamically like:
struct demon *createDemon(char *name, int pv, int pm){
// Try to allocate demon structure. If fail return NULL
struct demon *tmp = malloc(sizeof(struct demon));
if (tmp == NULL)
return NULL;
// Try to allocate demon name. If fail, return NULL
tmp->name = malloc(strlen(name));
if (tmp->name == NULL) {
free(tmp->name);
return NULL;
}
// Set Variables and return structure
tmp->name = name;
tmp->pm = pm;
tmp->pv = pv;
return tmp;
}
And you need to renew your removal function as well to remove the allocated space created for the name like:
void removeDemon(struct demon *dtr){
if (dtr != NULL){
free(dtr->name);
free(dtr);
}
}

Related

Cannot allocate dynamic array on C

Im trying to create a graph structure on C but I got some issues. First, Im getting 2 compilation errors:
main.c:18:19: error: member reference type 'node' is not a
pointer; did you mean to use '.'?
graph[index]->start = NULL;
~~~~~~~~~~~~^~
.
main.c:18:27: error: expression is not assignable
graph[index]->start = NULL;
~~~~~~~~~~~~~~~~~~~ ^
2 errors generated.
compiler exit status 1
I cannot figure out what Im doing wrong. I tried to create an array of nodes* but the compiler doesn't recognize it as a pointer for some reason. It's like malloc doesn't work. Also, I can't manage to acess edge* fields because it's like the array of nodes* is non-existent.
#include <stdio.h>
#include <stdlib.h>
#define maxNodes 4
typedef struct edge {
int target;
struct edge* next;
} edge;
typedef struct {
edge* start;
} node;
void initializeGraph(node* graph) {
graph = (node *) malloc(maxNodes * sizeof(node));
for(int index = 0; index < maxNodes; index++) {
graph[index]->start = NULL;
}
}
int main(void) {
node test;
initializeGraph(&test);
}
Im trying to initialize my structure. Any help is appreciated.
You have a large number of problems in your short example code. As to your error, that is covered by #dbush's answer and [...] serves as a dereference on your pointer making the '.' (dot) operator proper instead of the -> arrow operator.
Next, you cannot declare a node with static storage duration in main() and pass its address for allocation in your function. When you declare node test; all storage is already provided on the stack. You can't then pass that address to your function and allocate additional memory for that struct.
If you intend to have more than one node, then you can either declare an array with static storage duration in main(), or you must declare a pointer in main() and allocate in your function. To make that allocation visible in main(), as noted in my comment, you can either (1) make the return type node * and return a pointer to the allocated block for assignment in the caller, or (2) make the parameter node** and pass the address of your pointer as the parameter.
Putting that altogether and choosing option (1) above, you could do:
#include <stdio.h>
#include <stdlib.h>
#define maxNodes 4
typedef struct edge {
int target;
struct edge* next;
} edge;
typedef struct {
edge* start;
} node;
node *initializeGraph (void) {
node *graph = malloc(maxNodes * sizeof *graph);
if (!graph)
return NULL;
for (int index = 0; index < maxNodes; index++) {
graph[index].start = NULL;
}
return graph;
}
int main (void) {
node *test = initializeGraph();
if (!test)
fputs ("error: initialization failed.\n", stderr);
else
puts ("initialization succeeded");
}
Example Use/Output
$ ./bin/graphinit
initialization succeeded
Allocating For Each test[i].start
Before you can make use of any of the start pointers, you must allocate storage for a struct edge and assign the beginning address for that block of memory to each of your test[i].start pointers. You can do that in your same initializeGraph() function by allocating where you currently set the pointers NULL, e.g.
node *initializeGraph (void)
{
node *graph = malloc(maxNodes * sizeof *graph);
if (!graph)
return NULL;
for (int index = 0; index < maxNodes; index++) {
graph[index].start = malloc (sizeof *graph[index].start);
if (!graph[index].start)
return NULL;
}
return graph;
}
You can then assign a value to the target in each. Extending the earlier example, you could do:
int main (void) {
node *test = initializeGraph();
if (!test)
fputs ("error: initialization failed.\n", stderr);
else
puts ("initialization succeeded");
for (int i = 0; i < maxNodes; i++)
test[i].start->target = i;
puts ("targets filled");
}
Example Use/Output
$ ./bin/graphinit
initialization succeeded
targets filled
(don't forget to free the memory you allocate when it is no longer needed)
Look things over and let me know if you have further questions.
The array index operator [] implicitly dereferences a pointer. The syntax a[b] is exactly the same as *(a + b).
This means that graph[index] has type node, not node *. So use . instead of -> as the error message suggests.
graph[index].start = NULL;

First element in a double pointer to struct is jiberrish

I am creating a simple array of structures in C, but the first structure is always jibberish. How do i fix this?
I have tried to set the first element of the double pointer to struct in many ways but it always fails.
This is my graph.h file:
#ifndef GRAPH_H
#define GRAPH_H
#include "set.h"
typedef struct urlNode * URLList;
typedef struct GraphRep * Graph;
struct urlNode {
int id;
char* URL_NAME;
URLList next; // link to next node
};
struct GraphRep {
int nV;
URLList * collections;
};
Graph newGraph(Set s);
int nameToId(Graph g, char *name);
void showGraph(Graph g);
#endif
And my newGraph(Set s) function looks like this:
Graph newGraph(Set s){
int size = nElems(s);
Graph new_graph = malloc(sizeof(struct GraphRep));
if (new_graph == NULL) {
printf("ERROR: COULDNT ALLOCATE GRAPH\n");
}
new_graph->nV = size;
char *name = getNextVal(s);
// THIS IS THE NODE TO BE ADDED TO THE GRAPH
URLList list_to_add = malloc(sizeof(struct urlNode));
list_to_add->URL_NAME = strdup(name);
list_to_add->id = 0;
list_to_add->next = NULL;
// HERE I ADD THE NODE TO THE GRAPH.
new_graph->collections[0] = list_to_add;
// PRINT OUT THE VALUES OF THE NEWLY ADDED NODE TO MAKE SURE IT WORKS
// THE URL_NAME IS PRINTED OUT FINE
// BUT THE ID IS JIBBERISH.
printf("%s\n", new_graph->collections[0]->URL_NAME);
printf("%d\n", new_graph->collections[0]->id);
if(new_graph->collections[0]->next != NULL) {
printf("%s\n", new_graph->collections[0]->next->URL_NAME);
printf("%d\n", new_graph->collections[0]->next->id);
}
printf("\n");
return new_graph;
}
I expect new_graph->collections[0]->id to be 0 but it keeps on giving me random ints.
Also even if the next for the newly declared pointer to struct is NULL, it still gives me a jibberish next value too.
Any help would be appreciated, thanks!
The data member collections of the object *new_graph is not initialized.
There is initialized only this data member
new_graph->nV = size;
So this statement
new_graph->collections[0] = list_to_add;
results in undefined behavior.
If you need an array of pointers of the type URLList you have to allocate the memory and its address assign to the pointer collections.
For example
new_graph->collections = malloc( new_graph->nV * sizeof( URLList ) );
And after that this statement
new_graph->collections[0] = list_to_add;
could be valid.
(I suppose that the data member nV corresponds to the number of elements in the dynamically allocated array though it may not be truth)
Pay attention to that as the string pointed to by the pointer name is not changed in the function then it is better to declare it like
const char *name = getNextVal(s);

C NULL is the same as empty struct

So say I have a basic struct with just a couple of values:
struct my_struct {
int val1;
int val2;
}
and I want to pass it to a function
int test_the_struct(struct my_struct *s);
and then inside that function I check for NULL and returns an error code, but I want it to continue if an empty struct is passed instead. For example:
struct my_struct *test_struct = (struct test_struct *) calloc(1, sizeof(struct test_struct));
test_the_struct(NULL); //this should fail
test_the_struct(test_struct); //this should not fail
How could I differentiate between the two? In this situation, I CANNOT alter the structure of my_struct
If I understand you correctly, you just don't have a problem.
Just check the pointer against NULL and you are fine.
int test_the_struct(struct my_struct *s)
{
if (s) { // or if (s != NULL) or whatever you want to express it...
return s->val1 + s->val2;
} else {
return 42;
}
}
If you call it with your test_struct, both values are 0. There is nothing wrong or special about it.
To find if a pointer s is null you can use
if (s) {
/* not null */
} else {
/* is null */
}
A pointer to an "empty" struct is not null.
design your function as belows
int test_the_struct(void *ptr)
{
if (ptr == NULL)
return -1; //error
else
return 0;
}

create C structs using a variable as filename

is it possible to do say
int filename = 0;
typedef struct{
char name;
char sname;
int number;
}foo;
foo filename;
filename++;
foo filename;
and have a new foo struct named 1 and another named 2?
C isn't interpreted language, so you can't create variable names runtime. The other way is to create array having multiple instances.
typedef struct{
char name;
char sname;
int number;
}foo;
foo *files = malloc(sizeof(foo)*3);
files[0].name = "A";
files[1].name = "B";
files[2].name = "C";
Edit: used malloc instad new foo[3]
No, this is not possible. Declaring foo filename; will attempt to declare another variable named filename of type foo, so the integer value will never come into play there.
In addition, the introduction of two more variables named filename within the same scope wouldn't be allowed.
You probably want a linked list, rather than an array, if you will be changing its size often. Then, your code looks something like:
typedef struct node{
char name;
char sname;
int number;
struct node* next;
}foo;
And you would use functions like the following to add new nodes/fetch nodes:
foo head = NULL;
void addNode(foo newNode)
{
if(head == NULL)
head = newNode;
else
{
foo temp = head;
while(foo->next != NULL)
foo = foo->next;
foo->next = newNode
}
}
foo fetchNode(int index)
{
if(index < 0)
return NULL;
int n = 0
foo temp = head;
while(n < index && temp != NULL)
{
temp = temp->next;
n++;
}
return temp;
}
The way this works is that each node has the necessary data, plus a pointer to the next node, which is NULL if its the last node. Then, all you need is a pointer to the first one and you can fetch nodes by walking the next pointers. This also makes it trivial to delete a node that is partway down the list.

Allocate struct from function in C

I'm having issues writing a function that allocates a struct in C. Ideally, I want to have the function fill the fields of the struct with parameters passed into it.
I have defined the struct in my header file like so:
typedef struct {
char name[NAME_SIZE]; //Employee name
int birthyear; //Employee birthyear
int startyear; //Employee start year
} Employee;
And this is what I have for my function currently:
void make_employee(char _name, int birth_year, int start_year) {
Employee _name = {_name,birth_year,start_year}; //allocates struct with name
} /* end make_employee function */
Any advice on how to accomplish this?
The problem with your current code is that the struct your creating is created on the stack and will be cleaned up as soon as the function returns.
struct foo
{
int a;
int b;
};
struct foo* create_foo( int a, int b )
{
struct foo* newFoo = (struct foo*)malloc( sizeof( struct foo ) );
if( newFoo )
{
newFoo->a = a;
newFoo->b = b;
}
return newFoo;
}
This will get you a heap allocated object. Of course, you'll need a function to free that memory or this is a memory leak.
void destroy_foo( struct foo* obj )
{
if( obj )
free( obj );
}
void print_foo( struct foo* obj )
{
if( obj )
{
printf("foo->a = %d\n",obj->a);
printf("foo->b = %d\n",obj->b);
}
}
(btw, this style gets you part of the way toward an "object oriented" C. Add some function pointers to the struct (to get polymorphic behavior) and you have something interesting; though I'd argue for C++ at that point.)
You have to return a pointer allocated via malloc:
Employee* new_employee(char *_name, int birth_year, int start_year) {
struct Employee* ret = (struct Employee*)malloc(sizeof(struct Employee));
ret->name = _name;
ret->birth_year = birth_year;
ret->start_year = start_year;
return ret;
}
two more things: (1) you should make the struct definition of name a char* instead of char[NAME_SIZE]. Allocating a char array makes the struct much bigger and less flexible. All you really need is a char* anyway. And (2) change the function definition to char*.
Why does the make Employee return void? You need to return the Employee from the make_employee function!
Are you having trouble with the compiler complaining about the x = {a,...} syntax? Write it the long way then: Emp e; e.field1 = a; ...
Are you having weird overwriting / bogus numbers problems? If you allocate a struct in the function it will become invalid (and prone to being overwriten) as soon as the function returns! To go around this you either have to:
Return a copy of the struct (this is OK for small structs):
Employee make_emp(int a){
Emp emp; //Allocate temporary struct
emp.filed1 = a; //Initialize fields;
return emp; // Return a copy
}
Allocate the struct in the heap instead and deal with it through references (ie.: pointers) instead:
Employee* make_emp(int a){
Emp* emp = malloc(sizeof(Emp)); //Allocate the struct on the heap
//And get a reference to it
emp->filed1 = a; //Initialize it
return emp; //Return the reference
}
Don't forget to free() the Employee after you are done with it in this case!
Employee * make_employee(char *_name, int birth_year, int start_year)
{
Employee *employee;
if (employee = (struct Employee *)memalloc(sizeof(Employee)) == NULL)
{
return NULL;
}
else
{
strcpy(&(employee->name), _name);
employee->birthyear = birth_year;
employee->startyear = start_year;
return employee;
}
}

Resources