I'm having some problem with freeing dynamic struct array and I can't understand why.
first of all there is this struct:
typedef struct
{
char name[LEN];
char address[MAX];
} Airport;
And the constructor I made for this struct isn't using allocation for this struct building.
sec of all there is this struct:
typedef struct
{
Airport* airports;
int maxAPS;
int currentAPS;
} AirportManager;
//constructor
void addAirport(AirportManager* pAirportManager)
{
if (pAirportManager->maxAPS == pAirportManager->currentAPS)
{
pAirportManager->maxAPS++;
pAirportManager->airports = (Airport*)realloc(pAirportManager->airports, sizeof(Airport)*pAirportManager->maxAPS);
//pAirportManager->airports[pAirportManager->currentAPS] = *(Airport*)malloc(sizeof(Airport));
}....
and when I'm ending my program and want to free the AirportManager with the following code:
void freeAirportManager(AirportManager* pAirportManager)
{
for (int i = 0; i < pAirportManager->currentAPS; i++)
free(&pAirportManager->airports[i]);
free(pAirportManager->airports);
}
I've debuged this one and all the parameters are just fine but after one run in the loop the program exits, what should I change in the free function ?
do I need the marked line in the constructor ? I just added this on thinking it might help, but seems to not work as well... do I need to free only the array itself ?
for (int i = 0; i < pAirportManager->currentAPS; i++)
free(&pAirportManager->airports[i]);
You need only to free pAirportManager->airports. You do not have pointer to pointer here.
So instead of those two lines:
free(pAirportManager->airports);
I would use flexible array member instead of pointer.
typedef struct
{
char name[LEN];
char address[MAX];
} Airport;
typedef struct
{
size_t maxAPS;
size_t currentAPS;
Airport airports[];
} AirportManager;
For sizes use size_t type instead of int
Related
Namaste! I want to initialize my struct array position 0 myList.items[0] with a pointer to my item struct, but it prints out jibberish on the relevant positions when I print it out from my print function. It changes what was previously initialized (for test) so I know it works partially, but what's causing the bad output and what should be changed?
Before:
----My Shopping list---------
1 - Chocolate 40 100g
2 - Fishsauce 9 l
After:
----My Shopping list---------
1 - c┴®¶²` 128565603 ■ lüIv
2 - Fishsauce 9 l
typedef struct{
char name[20];
int amount;
char amountType[10];
}item;
typedef struct{
item *items[5];
int length;
}list;
int addItemToList(list *myList);
main(void)
{
list myList;
myList.length = 0;
for(int i; i<5;i++)
{
myList.items[i] = NULL;
}
addItemToList(&myList);
return 0;
}
int addItemToList(list *myList)
{
item newItem = {"Potatoes",2, "kg"};
myList->items[myList->length]=&newItem; //Something wrong here?
myList->length++;
printf ("Added [%s %i %s] as #%i.", newItem.name, newItem.amount,newItem.amountType, myList->length);
return 0;
}
This:
int addItemToList(list *myList)
{
item newItem = {"Potatoes",2, "kg"};
That allocates newItem on the stack. That means the memory for it will go away when addItemToList is completed, so &newItem will be pointing to gibberish later. It will be fine while still running code in addItemToList, but then after that the memory contents will be replaced in any further functions that are called.
You can either use malloc to allocate some memory for newItem, or you can allocate newItem on the stack in your main function and pass the pointer to newItem to any other called functions.
You cannot initialize a struct on the stack and then pass the pointer to that struct to a different struct that lives longer than that stack frame is open. Once the function returns, the stack frame where your item was allocated will close and the assigned values to the fields will be gone.
You need an initializer function with a heap allocated struct like this:
item* item_new(const char* name, int amount, const char* amountType);
Then your initialization function should:
call Malloc for the size of struct,
Copy the name and amountType strings to the struct.
copy the amount to the struct.
Then you can do this: myList->items[myList->length]=newItem;, where newItem is created by your init function.
You are mixing stack and heap memory, I rewriten it for you, it should give you some sense what went wrong. Also always free allocated memory its no java:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct{
char name[20];
int amount;
char amountType[10];
}item;
typedef struct{
item *items[5];
int length;
}list;
int addItemToList(list *myList);
int main(void)
{
list myList;
myList.length = 0;
for(int i; i<5;i++)
{
myList.items[i] = 0;
}
addItemToList(&myList);
for(int i; i<myList.length; i++)
{
free(myList.items[i]);
}
return 0;
}
int addItemToList(list *myList)
{
item* newItem = malloc(sizeof(item));
strcpy(newItem->name, "Potatoes");
newItem->amount = 2;
strcpy(newItem->amountType, "kg");
myList->items[myList->length++] = newItem; //Something wrong here?
printf ("Added [%s %i %s] as #%i.\n", newItem->name, newItem->amount, newItem->amountType, myList->length);
return 0;
}
I don't love this, but I have a struct with nearly 45 members inside; all are characters or character arrays. That said, I am going to need to optimize the way I initialize each struct. Ordinarily, I would pass the entire object into my init_struct() function, but I feel like that is not the best way to do this.
How would I create and use a pointer to the struct to accomplish this?
Old Method would look something like this:
void init_struct(struct general){
...initialize members...
}
int main(){
struct general[10];
for(int i = 0 ; i < 10 ; ++i){
init_struct(general[i];
}
}
Since this struct is so large, as I said nearly 45 members inside it, I think a point to the struct would go a long way in optimizing this process. How would I accomplish that?
Just in case you need, here is the typedef for my struct
typedef struct
{
//Basically, everything we want to read from HUDL should be here...
int play_num;
char down;
char dist[3];
char ydln[4];
char gnls[3];
char hash[3];
char home[20];
char away[20];
char odk[2];
char qtr[2];
char series[3];
char result[20];
char penalty[20];
char act_cb[20]; //How do they act post-snap
char act_dl[20];
char act_lb[20];
char act_ol[20];
char act_qb[20];
char act_rb[20];
char act_saf[20];
char aln_cb[20]; //How do they align pre-snap
char aln_dl[20];
char aln_lb[20];
char aln_ol[20];
char aln_qb[20];
char aln_rb[20];
char aln_saf[20];
char aln_wr[20];
char blitz[20];
char box_cnt[3];
char saf_count[20];
char coverage[20];
char cvr_basic[20];
char def_front[20];
char mtn_def[20];
char num_rush[3];
char off_form[20];
char form_var[20];
char motion[20];
char off_pro[20];
char off_play[20];
char play_var[20];
char personnel[20];
char play_type[20];
char time[2];
char score_diff[4];
char field_zone[2];
char dd_type[2];
char form_strength[2];
} HUDL; // MAXIMUM of 63 Members
There's a couple of things wrong on your code.
First of, your function definition is wrong because you omit the parameter name. Your function definition should look like this:
void init_struct(struct general mygeneralstruct){}
Alternatively, you could use an alias for your struct using typedef, like so:
typedef struct {
int a;
} general;
In which case, your function declaration could look like this:
void init_struct(general mygeneralstruct){}
You have the same problem when you declare your array of structures. You omit the name of your variable. Instead of
struct general[10];
it should be
struct general mygeneralstruct[10]
or
general mygeneralstruct[10](typedef)
Finally, you can't change your array of structures by passing each structure's value to the function. You need to pass each structure's address instead.
Your function declaration should then be(using typedef):
void init_struct(general* mygeneralstruct){}
and the code in the loop:
init_struct(&mygeneralstruct[i]);
To pass a pointer to your array element, you just prefix the parameter with &, make sure you declare the function correctly:
void init_struct(HUDL* pGeneral){
if ( pGeneral != NULL ) {
//This will ensure the entire structure contains '0'
memset(pGeneral, 0, sizeof(HUDL));
...initialize members...
}
}
int main(){
HUDL general[10];
for( int i=0; i<(sizeof(general) / sizeof(general[0])); i++ ) {
init_struct(&general[i]);
}
}
I'm not sure why you haven't used the typedef 'HUDL' makes life a lost easier and code easier to read.
A slightly cleaner and better approach would be to have a constructor and destructor function to allocate memory dynamically to structure and free it after use.
static void HUDL_destroy(HUDL* ptr)
{
if(ptr)
{
//...any other clean up that needs to be done goes here..
free(ptr);
}
}
static HUDL* HUDL_create()
{
HUDL* ptr = malloc(sizeof(HUDL));
if(!ptr)
return NULL;
//do initialization bits...
init_struct(ptr);
return ptr;
}
int main()
{
//allocate and initialise structure
HUDL *general = HUDL_create();
//do stuff...
//free structure after use
HUDL_destroy(general);
}
You might need an array of pointers in your case. So modify your main() accordingly.
int main()
{
//we need an array of structure pointers
HUDL* general[SIZE];
//allocate and initialize structure
for(int i=0; i<SIZE; i++)
general[i] = HUDL_create();
//do stuff...
//free structure after use
for(i=0; i<SIZE; i++)
HUDL_destroy( general[i] );
}
I have a small trouble initializing (dynamic) parts of my structures that are in an array. This is what i have so far I am using a sub-routine to create the struct
t_grille_animaux creer_grille(int dim_ligne, int dim_col)
{
t_grille_animaux grille;
grille.la_grille = (t_case_animal **) malloc(sizeof(t_case_animal)*dim_ligne*dim_col);
grille.dim_colonne = dim_col;
grille.dim_ligne = dim_ligne;
grille.nb_predateurs = NULL;
grille.nb_proies = NULL;
return grille;
}
This is my structure:
typedef struct
{
t_case_animal ** la_grille; //2D array
int dim_ligne;
int dim_colonne;
int nb_proies;
int nb_predateurs;
} t_grille_animaux;
typedef struct
{
t_contenu etat;
t_animal animal;
} t_case_animal;
typedef enum {VIDE, PROIE, PREDATEUR} t_contenu;
typedef struct
{
int age;
int jrs_gestation;
int energie;
int disponible;
} t_animal;
(Sorry for the language)
What I get right now is that everything that isn't the struct in the array is fine. But everything in the array is undeclared.
This should do the trick:
#define NUM_ROWS (10)
#define NUM_COLS (15)
grille.la_grille = malloc(NUM_ROWS * sizeof(*grille.la_grille));
for(int row = 0; row < NUM_ROWS; row++)
grille.la_grille[row] = malloc(NUM_COLS * sizeof(**grille.la_grille));
The malloc() function does not (necessarily) initialise the allocated bytes to any value in particular. So after calling malloc(), you should explicitly initialise the allocated data.
Having said that, you have a couple of choices about how you can store your two-dimensional array. It depends on how you want to access the data. Since C does not have true multidimensional arrays, you can either:
declare a single dimension array of size dim_ligne*dim_col of t_case_animal values
declare an array of row pointers of size dim_ligne that each point to another single dimensional array of dim_col values
For the first case, change your declaration of la_grille to:
t_case_animal * la_grille;
and access your values as something like la_grille[j*dim_colonne+i].
For the second case, be sure to initialise your subarrays:
grille.la_grille = (t_case_animal **) malloc(sizeof(t_case_animal*)*dim_ligne);
for (int i = 0; i < dim_ligne; i++) {
grille.la_grille[i] = (t_case_animal *) malloc(sizeof(t_case_animal)*dim_col);
}
In the second case, you would access your values as something like la_grille[j][i].
You can use malloc() to allocate memory for each row. The following code should work:
#include<stdlib.h>
typedef struct
{
int age;
int jrs_gestation;
int energie;
int disponible;
}t_animal;
typedef enum {VIDE, PROIE, PREDATEUR} t_contenu;
typedef struct
{
t_contenu etat;
t_animal animal;
} t_case_animal;
typedef struct
{
t_case_animal ** la_grille; //2D array
int dim_ligne;
int dim_colonne;
int nb_proies;
int nb_predateurs;
} t_grille_animaux;
t_grille_animaux creer_grille(int dim_ligne,int dim_col)
{
t_grille_animaux grille;
grille.la_grille = (t_case_animal**) malloc(sizeof(t_case_animal*)*dim_ligne);
for(int i=0; i<dim_ligne; i++) {
grille.la_grille[i] = (t_case_animal*) malloc(sizeof(t_case_animal)*dim_col);
}
grille.dim_colonne = dim_col;
grille.dim_ligne = dim_ligne;
grille.nb_predateurs = 0;
grille.nb_proies = 0;
return grille;
}
int main(int argc, char* argv[])
{
t_grille_animaux test;
test = creer_grille(3, 4);
}
I have a structure as follows
struct a
{
char* ap;
char* inputs[10];
int e;
};
then I have created an array of this structure like struct a list [100];
now i want to fille the array inputs[10] and for that I am using the syntax to access the first location :
ip=0;
inp=0;
list[ip].inputs[inp]
but I am gettin the error "error C2107: illegal index, indirection not allowed" on compiling the code
please suggest how to access the array location inside array of structure.
regards
priya
Here you use array of character pointer in your structure. So Initially you allocate memory for you structure by creation list of 100. I think you didn't create memory for you array of character pointer. You have to create memory for each of character pointer. So I suggest example code.
#include <stdio.h>
struct a
{
char* ap;
char* inputs[10];
int e;
};
int main()
{
int ip=0;
int inp=0;
struct a list[100];
list[ip].inputs[inp]= (char*)malloc(25);
scanf("%s",list[ip].inputs[inp]);//Or other copy function to fill string
printf("output %s",list[ip].inputs[inp]);
}
Working fine on my pc.. here is my code..
#include <stdio.h>
struct a
{
char* ap;
char* inputs[10];
int e;
};
int main()
{
int ip=0;
int inp=0;
struct a list[100];
list[ip].inputs[inp] = 'A';
printf("This: %c", list[ip].inputs[ip]);
return 0;
}
OUTPUT= This: A
let me know whether it helped or not..
The struct themselves do not have data. You need to create objects of the struct type and set the objects ...
struct a
{
char* ap;
char* inputs[10];
int e;
};
/* I like to separate the type definition from the object creation */
struct a list [3];
list [0].inputs[0] = "Choclate";
list [0].inputs[1] = "Almond";
list [0].inputs[2] = "Rasberry";
Hope it ll usefull. Also refer this article
I am (trying to) write a server-side daemon in c, and it accepts connections from clients. I need a struct that keeps information on each open connection, so I have created an array of my defined struct, and I have it dynamically re-sizing with realloc.
The problem I have is creating the struct within the array. I keep getting this error:
test.c:41: error: conversion to non-scalar type requested
What am I doing wrong?
I spend most of my time in PHP, and am a noob with c. I realize that I am making some simple, beginner mistakes (in other words, feel free to make fun of me). If I am doing something stupid, please let me know. I've put my quality time in with google, but have not figured it out. I have reproduced the issue on smaller scale, as below:
here is my test.h:
typedef struct test_ test;
and here is my test.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "test.h"
//define the struct
struct test_ {
int id;
char *ip;
int user;
char *str;
};
//yes, the list needs to be global
test *test_list;
//
// add an item to the global list
//
int add(int id, char *ip, int size)
{
//
// increment size
if(id>size) {
size = id;
//try to expand the list
test *tmp = realloc(test_list,size);
if(tmp) {
//it worked; copy list back
test_list = tmp;
} else {
//out of memory
printf("could now expand list\n");
exit(1);
}
}
//
// HERE IS THE TROUBLE CODE::
test_list[id] = (struct test)malloc(sizeof(test)+(sizeof(int)*5)+strlen(ip)+1);
test_list[id].id = id;
test_list[id].ip = malloc(strlen(ip));
strcpy(test_list[id].ip,ip);
test_list[id].user = 0;
test_list[id].str = NULL;
}
//
// main
//
int main(void)
{
//initialize
int size = 1;
test_list = malloc(size*sizeof(test));
//add 10 dummy items
int i;
for(i=0; i<10; i++) {
size = add(i, "sample-ip-addr", size);
}
//that's it!
return 0;
}
Try changing
test *tmp = realloc(test_list,size);
to
test *tmp = realloc(test_list,size*sizeof(test));
then delete
test_list[id] = (struct test)malloc(sizeof(test)+(sizeof(int)*5)+strlen(ip)+1);
When you allocate for test_list, there's already space for each member of the struct allocated, so you don't need to do it again. You just have to allocate for any pointers within the struct
The return value from 'malloc' is the memory address you've allocated. You can't cast it to a struct. What would that even mean?
You want something like: test_list=realloc(test_list, num_alloc * sizeof(test_));