Accessing members of dynamically allocated array of pointers to structs - arrays

I need to have a global dynamic array of pointers, in which I will store my structs, beacuse later I will need to iterate through this array to list all the stored information, I also need to be able to read the name, age and job variables from the console, and store them in a person_t in the iterator array.
#include <stdio.h>
#include <stdlib.h>
typedef struct Person
{
char name[30];
int age;
char job[30];
} person_t;
person_t **iterator;
int capacity = 10;
int size = 0;
int main()
{
int i;
*iterator = (person_t *)malloc(capacity * sizeof(person_t));
for (i = 0; i < capacity; ++i)
{
person_t p;
p.age = i;
*iterator[i] = p;
}
return 0;
}
I get no errors/warnings compiling this code (gcc -ansi -pedantic -Wall -Wextra), but when I try to run it, I get a Segmentation fault immediately.

When you do this:
*iterator = (person_t *)malloc(capacity * sizeof(person_t));
You're deferencing iterator, however as a file-scope pointer variable it's initialized to NULL. Attempting to dereference a NULL pointer invokes undefined behavior.
I suspect what you really want is an array of structs, not an array of pointers to structs. That being the case, define iterator as:
person_t *iterator;
Then you allocate memory for it like this:
iterator = malloc(capacity * sizeof(person_t));
Then assign to array elements like this:
iterator[i] = p;

Your stated purpose is to create a "global dynamic array of pointers, in which I will store my structs". The following modification of your code (see comments) will do this:
person_t p[10] = {0};
int main()
{
int i;
// with declaration: person_t **iterator = NULL;,
//following is all that is needed to create an array of pointers:
iterator = malloc(capacity * sizeof(person_t *));//no need to cast return of malloc
for (i = 0; i < capacity; ++i)
{
//person_t p;//moved to scope that will exist outside of main()
p[i].age = i;
iterator[i] = &p[i];//assign the address of the object to the pointer
//iterator[i] is the ith pointer in a collection of
//pointers to be assigned to point to
//instances of struct person_t
}
//Once all fields are populated (to-do), the following will display the results:
for (i = 0; i < capacity; ++i)
{
printf("%d) Name: %s Age: %d Job: %s\n", i, iterator[i]->name,iterator[i]->age,iterator[i]->job);
}
return 0;
}

you are not allocating memory correctly
First you need to allocate memory for a pointer which can store capacity number of address i.e done through iterator = malloc(capacity * sizeof(person_t*)); and then you need to allocate memory for holding each structure element i.e iterator[i] = malloc(sizeof(person_t));
all the malloc'ed memory should be free'd once we are done with it.
Also, have not done the error check for malloc's , that is left as an exercise for you.
int main()
{
int i;
// test data
char *names[] = {"ABC", "DEF"};
char *jobs[] = {"Accountant", "Security"};
int ages[] = {50, 60};
// first allocate memory for iterator , which can hold pointers to store iterator poniters
iterator = malloc(capacity * sizeof(person_t*));
for (i = 0; i < capacity; ++i)
{
// now allocate memory for individual iterator
iterator[i] = malloc(sizeof(person_t));
strcpy(iterator[i]->name,names[i]);
iterator[i]->age = ages[i];
strcpy(iterator[i]->job, jobs[i]);
}
for (i = 0; i < capacity; ++i)
{
printf("name = %s ", iterator[i]->name);
printf("Age = %d ", iterator[i]->age);
printf("Job = %s\n", iterator[i]->job);
}
return 0;
}

Related

Accessing Element in Array Inside Struct Dynamically Allocated

So I have an array of structs with every struct containing a dynamic array of strings.
typedef struct _test {
int total;
char *myarray[];
} Test;
This how I allocated enough memory
Test *mystruct = (Test *)malloc(size);
Above is how my struct is formated
mystruct[x].myarray[index] = strdup(name);
index++;
mystruct[x].total = index;
when trying to access a string in that array i.e. :
printf("%s", mystruct[0].myarray[0]);
Nothing prints, thanks for any help!
The following is correct. I'll explain below.
typedef struct TEST {
int total;
char *myarray[];
} Test;
int StackOveflowTest(void)
{
int index;
Test *mystruct = malloc(sizeof(Test)+10*sizeof(char *));
for (index=0; index<10; index++)
mystruct->myarray[index] = strdup("hello world");
mystruct->total = index;
for (index=0; index<10; index++)
printf("%s\n", mystruct->myarray[index]);
return 0;
}
Actually, you declare an "array of pointers" myarray, however that array has zero elements. This "trick" is used to have the ability that at the end of the struct you have an array of variable size when malloc'ing the array:
Test *mystruct = malloc(sizeof(Test)+10*sizeof(char *));
This allocates the size of the struct and adds room for 10 array elements.
Since you did not allocate this flexible part of the struct, you wrote into "nothing" and are lucky the program did not abort (or it did, which is why there was no output).
P.s.: don't forget to free the memory when you are done:
for (index=0; index<10; index++)
free(mystruct->myarray[index]);
free(mystruct);

Garbage value even after initializing members of dynamically allocated struct array

I have a dynamically allocated array of structures, 'buff'. Each element is a structure that has a few integer variables and a pointer 'buffer_ptr' which points to another dynamically allocated array of structures. The size of both arrays is given as command line input.
int buffer_size;
int user_num;
struct tuple
{
char userID[5];
char topic[16];
int weight;
};
struct buff_ctrl
{
struct tuple* buffer_ptr;
int in;
int out;
int numItems;
int done;
};
The arrays are created and initialized in main() as follows:
int main(int argc, char* argv[])
{
void *status;
pthread_t mapThd;
if(argc != 4)
{
printf("Input format: ./combiner <buffer_size> <number_of_users> <input_file>\n");
return -1;
}
buffer_size = atoi(argv[1]);
user_num = atoi(argv[2]);
struct buff_ctrl *buff = (struct buff_ctrl*)malloc(user_num * sizeof(struct buff_ctrl));
for(int i=0; i<user_num; i++)
{
struct buff_ctrl* curr_buff = (buff + (i*sizeof(struct buff_ctrl)));
struct tuple *ptr = (struct tuple*)malloc(buffer_size * sizeof(struct tuple));
curr_buff->buffer_ptr = ptr;//points to another array
curr_buff->in = 8;
curr_buff->out = 4;
curr_buff->numItems = 7;
curr_buff->done = 0;
printf("%p\n",curr_buff);
}
Then, I need to pass the 'buff' pointer as an argument when creating thread using pthread_create:
pthread_create(&mapThd, NULL, mapper, (void*)buff);
pthread_join(mapThd, &status);
free(buff);
/*end of main*/
My function pointer is as follows:
void* mapper(void *buff)
{
struct buff_ctrl* arr = (struct buff_ctrl *)buff;
struct buff_ctrl* temp_ptr;
printf("######################################################\n");
for(int k=0; k<user_num; k++)
{
/*Printing just to check values */
temp_ptr = arr + (k*sizeof(struct buff_ctrl));
printf("buffer ptr = %p\n", temp_ptr->buffer_ptr);
printf("in = %d\n", temp_ptr->in);
printf("out = %d\n", temp_ptr->out);
printf("numItems = %d\n", temp_ptr->numItems);
}
printf("######################################################\n");
pthread_exit((void*)buff);
}
But, when I print the values of 'buffer_ptr' from the created thread (only one), for ODD number of user_num, there is always ONE element of the array 'buff' which gives garbage value after pthread_create statement! When the values are checked in main itself after removing calls to pthread, it runs fine.
This line
struct buff_ctrl* curr_buff = (buff + (i*sizeof(struct buff_ctrl)));
should be
struct buff_ctrl* curr_buff = buff + i;
buff + i is pointer arithmetic and the compiler already takes the size of the
object pointed to by buff into consideration. By doing i*sizeof(struct buff_ctrl) you are assigning
a pointer that may be after the allocated memory.
As general suggestion:
Don't cast malloc. And instead of using sizeof(<type>), use sizeof *variable, this is more safe, because
it's easier to make mistakes when writing sizeof(<type>).
So:
struct buff_ctrl *buff = malloc(user_num * sizeof *buff);
...
struct tuple *ptr = malloc(buffer_size * sizeof *ptr);
And you don't need to declare a separate pointer, you can do:
for(int i=0; i<user_num; i++)
{
buff[i].buffer_ptr = malloc(buffer_size * sizeof *buff[i].buffer_ptr);
buff[i].in = 8;
buff[i].out = 4;
buff[i].numItems = 7;
buff[i].done = 0;
}
Also you should always check for the return value of malloc. If it returns
NULL, you cannot access that memory.
This is wrong:
struct buff_ctrl* curr_buff = (buff + (i*sizeof(struct buff_ctrl)));
When you do pointer arithmetic, it operates in units of the size of what the pointer points to, so you don't need to multiply by sizeof. As a result, you're effectively multiplying twice and accessing outside the array bounds.
Just treat buff as an array, rather than dealing with pointers.
for(int i=0; i<user_num; i++)
{
struct tuple *ptr = malloc(buffer_size * sizeof(struct tuple));
buff[i].buffer_ptr = ptr;//points to another array
buff[i].in = 8;
buff[i].out = 4;
buff[i].numItems = 7;
buff[i].done = 0;
}
Also, see Do I cast the result of malloc?
You have a fundamental error.
Pointer arithmetics works by adding the offset in multiples of the pointer type, so adding the offset yourself will not work as you apparently expect it to.
If it was a char * pointer then you would need to add the offset manually, increments would be multiplied by one. But in your case increments by n are multiplied by the size of the pointer base type.
There are times when doing pointer arithmetics with the addition notation makes sense, but most of the time it's much clearer to write index notation instead.

how can i solve this when i try to return a 2d struct from a function

this is how i declare this struct
typedef struct cache{
int vaild;
char* tag;
char* data;
}cache;
this is part of my main which called this function
struct cache **cacheA = createCache(Setnum,(int)pow(2,blocksize),cachesize);
struct cache **cacheB = createCache(Setnum,(int)pow(2,blocksize),cachesize);
and now this is my called function
struct cache ** createCache(int numset, int blocksize, int cachesize){
int numcache = (int)((cachesize/blocksize)*numset);
struct cache out[numset][numcache];
int i,j;
for (i=0; i < numset; i++){
for (j=0; j < numcache; j++){
out[i][j].tag = "0";
out[i][j].vaild = 0;
out[i][j].data ="0";
}
}
return out;
}
and when i try to compile this, it tells me that
return from incompatible pointer type
function returns address of local variable
(which points to the line "return out;")
I have no idea whats wrong with my code, i mean the type of the function return is the same as how i declear "out", so what causes this problem?
You create struct cache out[numset][numcache];
within the function prototyped as: struct cache ** createCache(...).
Then attempt to return out.
It is because struct cache [][] is typed differently than struct cache ** that you are getting the return errors.
Other comments:
1) If you truly do want a pointer to pointer to struct, then malloc or calloc will need to be used at some point to allocate memory.
2) the char * members of the struct also need to be assigned memory before assigning values. For illustration below, they are changed to char []
3) assigning values to strings does not work by using = assignment operator. Use a string function such as strcpy, sprintf, etc.
4) you've named the struct with the same symbol as that of the new type you have created, i.e. cache. In this application, the name cache is not necessary. Also, purely for style, I show the new type in CAPS. This is not necessary, but just a style I use to make the new type more recognizable in code.
In consideration of the comments above, the struct could be changed to the following:
typedef struct { /// don't need name here when it in this application
int vaild;
//char *tag;
char tag[20];//for illustration, to avoid additional dynamic allocation of memory
//char* data;
char data[80];
}CACHE;//capitalization is style only, not a necessity here.
Note, there is no name, but the new type CACHE was created. Now, you can create the function createCache:
CACHE ** createCache(int ncache, int nset)//note for simplicity of freeing this
//object later, simplify number of arguments
{
CACHE **out;
out = calloc(ncache, sizeof(CACHE *));//create array of pointers to CACHE
if(!out) return NULL;
int i;
for (i=0; i < nset; i++)
{
out[i] = calloc(nset, sizeof(CACHE));//create space for each instance
//of CACHE pointed to by array pointers
}
return out;
}
Anytime memory is created on the heap, it needs to be freed. This method will free the CACHE object memory:
void freeCashe(CACHE **a, int nset)
{
int i;
for(i=0; i<nset; i++)
{
if(a[i])free(a[i]);
}
if(a)free(a);
}
Calling these functions as shown below, will create an array of pointers, each pointing to an instance of CACHE where you can use them as intended, then free all of the memory when finished:
int main(void)
{
int cachesize = 20;
int blocksize = 20;
int numset = 10;
//move the calculation out of creation function
//to simplify freeing object later.
int numcache = (int)((cachesize/blocksize)*numset);
CACHE **a = createCache(numcache, numset);
/// use a, then free a
freeCashe(a, numset);
return 0;
}
Your function needs to allocate the memory on the heap rather than the stack. You will need to allocate space on the heap for your array of pointers, and for what they point too.
struct cache ** createCache(int numset, int blocksize, int cachesize){
cache ** out;
int numcache = (int)((cachesize/blocksize)*numset);
size_t headerSize = sizeof(*out)*numset;
size_t bodySize = sizeof(**out)*numcache;
out = malloc(headerSize + (bodySize*numset));
if (out == NULL) {
/* Should probably output some message about being
* insufficient memory here. */
return NULL;
}
int i,j;
for (i=0; i < numset; i++){
/* need to assign our point */
out[i] = (cache*)(((char*)out)+(headerSize+bodySize*i));
for (j=0; j < numcache; j++){
out[i][j].tag = "0";
out[i][j].vaild = 0;
out[i][j].data ="0";
}
}
return out;
}
/* importantly, you want a way to free your allocated memory */
void destroyCache(cache ** ptr) {
free(ptr);
}
PS: You don't have to typedef your struct if you reference it with the struct keyword.
You are wanting a pointer pointer type to be returned, but in order to do that you need to dynamically allocate it. Local stack allocations (i.e. struct cache[x][y]) won't work. You will either get an error or your program will crash when attempting to use the 2D array.
The solution is to either pre-allocate space and pass it in to the function or allocate in the function itself.
Allocation In Function Example:
struct cache ** createCache(int numset, int blocksize, int cachesize){
int numcache = (int)((cachesize/blocksize)*numset);
struct cache **out = malloc(sizeof(struct cache *) * numset); // This line changed.
int i,j;
for (i=0; i < numset; i++){
out[i] = malloc(sizeof(struct cache) * numcache); // This line added.
for (j=0; j < numcache; j++){
out[i][j].tag = malloc(sizeof(char)); // This line added.
out[i][j].data = malloc(sizeof(char)); // This line added.
strcpy(out[i][j].tag, "0");
out[i][j].vaild = 0;
strcpy(out[i][j].data, "0");
}
}
return out;
}

Malloc-ating inside a Function vs malloc-ating in Main

I have a struct that contains an int pointer
struct mystruct {
int *myarray;
};
I want to make a function that mallocates for mystruct and also initializes myarray. But, when I try to access an element of myarray, I get a seg. fault
void myfunction(struct mystruct *s, int len) {
s = malloc(sizeof(mystruct));
s->myarray = malloc(sizeof(int) * len);
int i;
for (i=0; i<len; i++) {
s->myarray[i] = 1;
}
}
main() {
struct mystruct *m;
myfunction(m, 10);
printf("%d", m->myarray[2]); ////produces a segfault
}
However, mallocating m in main seemed to solve my problem.
Revised Code:
void myfunction(struct mystruct *s, int len) {
int i;
s->myarray = malloc(sizeof(int) * len);
for (i=0; i<len; i++) {
s->myarray[i] = 1;
}
}
main() {
struct mystruct *m = malloc(sizeof(mystruct)); //this was in myfunction
myfunction(m,10);
printf("%d", m->myarray[2]); ///Prints out 1 like I wanted
}
Why did the 2nd attempt work and why did the first attempt not work?
The problem is that the first version assigns the result of malloc to a parameter, which effectively a local variable; the assigned value vanishes when the function returns
So, an alternative is to pass to the function a pointer to the location where you want to store the result of malloc. This is named pps in the code below. At the beginning of the function we do the malloc and assign to a local variable s. Then we do things with s. Then, just before the function exits, we assign the local variable s to the location pointed to by the parameter pps. *pps = s;
void myfunction(struct mystruct **pps, int len) { // note double "**"
struct mystruct *s = malloc(sizeof(mystruct);
s->myarray = malloc(sizeof(int) * len);
int i;
for (i=0; i<len; i++) {
s->myarray[i] = 1;
}
*pps = s; // now pass the alloc'ed struct back to main through parameter pps
}
Now, back in main we pass &m to the function. This passes a pointer to m to the function. When the function returns, the local variable m holds the value returned by malloc and passed through the parameter pps.
main() {
struct mystruct *m;
myfunction(&m, 10); // PASS THE ADDRESS OF m, not m itself
printf("%d", m->myarray[2]); // this will work now
}

Modifying a structure array through a pointer passed to a function

I am trying to pass a structure array pointer and a pointer to a structure array pointer into a function and then have it modified rather than using a return.
This example code is indeed pointless, its just a learning example for me.
Basically I want to create array[0]...array[1]..array[2] and so on and have a pointer that points to these while using a different index...such as array_ref[2] points to array[0] and array_ref[3] points to array[1].
The code below compiles, but immediately crashes. Any suggestions?
typedef struct unit_class_struct {
char *name;
char *last_name;
} person;
int setName(person * array, person ***array_ref) {
array[0].name = strdup("Bob");
array[1].name = strdup("Joseph");
array[0].last_name = strdup("Robert");
array[1].last_name = strdup("Clark");
*array_ref[2] = &array[0];
*array_ref[3] = &array[1];
return 1;
}
int main()
{
person *array;
person **array_r;
array = calloc (5, sizeof(person));
array_r = calloc (5, sizeof(person));
setName(array,&array_r);
printf("First name is %s %s\n", array_r[2]->name, array_r[2]->last_name);
printf("Second name is %s %s\n", array_r[3]->name, array_r[3]->last_name);
return 0;
}
You are allocating an array of structures but declaring an array of pointers.
Calloc() and malloc() return a void * object that can be assigned to everything. So, even with -Wall your program will compile with no warnings.
However, when it runs, it tries to deal with what you said was an array of pointers, in fact, an array of pointers to pointers to pointers. None of these pointers are ever created. All you start with are one-level pointers to an array of objects. Depending on what you really want, you may need something more like...
array_ref[2] = &array[0];
array_ref[3] = &array[1];
return 1;
}
int main()
{
person *array, *array_r_real;
person **array_r;
array = calloc(5, sizeof(person));
array_r_real = calloc(5, sizeof(person));
array_r = calloc(5, sizeof(struct unit_class_struct *));
int i;
for (i = 0; i < 5; ++i)
array_r[i] = &array_r_real[i];
setName(array, array_r);

Resources