The Sheyx
The Sheyx

Reputation: 11

Allocating memory for pointer struct which has pointer members

I am trying to read and print using struct pointer which has pointer members. So I am trying to read and print array of double struct pointers. I tried the folowing but it is giving me error saying "Access violation writing location (somewhere in memory)"

How can I allocate memory dynamically for this?

#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif

#include <stdio.h>
#include<string.h>
#include <stdlib.h>

typedef struct template{
char *name;
int  *birthdate;
int *phoneNum;

} detailsOf;

void inputValue(detailsOf **person, int maxSize);

int main() {

detailsOf **person;
int maxSize = 0, menu = 0;

printf("Max:");
scanf("%d", &maxSize);


person = (detailsOf **)malloc(maxSize * sizeof(detailsOf **));
if (person == NULL) {
    printf("Failed to allocate");
    exit(0);
}
for (int i = 0; i < maxSize; i++) {
    person[i]->name = (char *)calloc(21, sizeof(char ));
    person[i]->birthdate = (int *)calloc(8, sizeof(int ));
    person[i]->phoneNum = (int *)calloc(16, sizeof(int ));
}

inputValue(person, maxSize);

for (int i = 0; i < maxSize; i++) {
    free(person[i]);
    for (int j = 0; j < 21; j++) {
        free(person[i]->name[j]);
    }
    for (int j = 0; j < 15; j++) {
        free(person[i]->phoneNum[j]);
    }
    for (int j = 0; j < 8; j++) {
        free(person[i]->birthdate[j]);
    }
}
    return 0;
}
void inputValue(detailsOf **person, int maxSize) {
    for (int i = 0; i < maxSize; i++) {
        printf("Name of %d", i + 1);
        scanf("%s", person[i]->name);
          for (int j = 0; j < 8; j++) {
             printf("Birth %d:", i + 1);
             scanf("%d", person[i]->birthdate[j]);
     } 
     for (int k = 0; k < 8; k++) {
         printf("Phone %d:", i + 1);
         scanf("%d", person[i]->phoneNum[k]);
      }
   }
    printf("SUCCESS\n");
}

Upvotes: 0

Views: 1155

Answers (3)

Sridhar Nagarajan
Sridhar Nagarajan

Reputation: 1105

person = (detailsOf **)malloc(maxSize * sizeof(detailsOf **));

This allocates an array of double pointers to type detailsOf with array size as maxSize.

sizeof(detailsOf**) is the size of an address, it does not give you the size of your user-defined datatype detailsOf.

Also, double pointer means, it is an address location which will store the address of another pointer which points to the memory location of detailsOf

/* if you want to use double pointer then */
detailsOf **dptr;  // two dimensional array of detailsOf */
detailsOf *sptr;   /* one dimentional array of detailsOf */

/* This allocates the memory for storing 3 detailsOf struct data */
sptr = malloc(3 * sizeof(detailsOf)); 
dptr = &sptr;

/* Now to access double ptr */
for (int i = 0; i < 3; ++i) {
    dptr[0][i].birthdate = malloc(3 * sizeof(int));
}

for (int i = 0; i < 3; ++i) {
    dptr[0][i].birthdate[0] = i; 
    dptr[0][i].birthdate[1] = i + 10; 
    dptr[0][i].birthdate[2] = i + 1990; 
}

for (int i = 0; i < 3; ++i) {
    printf("%d\\", dptr[0][i].birthdate[0]); 
    printf("%d\\", dptr[0][i].birthdate[1]); 
    printf("%d\n", dptr[0][i].birthdate[2]); 
}

/* Not to free the double pointer,
 * you have to free the inner pointer first then the outer pointers
 * Easy to remember is to free in reverse order of your allocation order
 */
for (int i = 0; i < 3; ++i) {
    free(dptr[0][i].birthdate);
    free(dptr[0]);
    /* free(dptr); this is not needed in this example because
     * dptr is pointer to address of a local variable,
     * but if it points to address of another array of detailOf* 
     * then this free is needed
     */ 
}

In your case, you have just an array of pointer and not an array of double pointers.

Upvotes: 0

David C. Rankin
David C. Rankin

Reputation: 84541

Rule is simple -- a pointer is uninitialized until it has had a valid address assigned to it, or memory has been allocated within which to store things and the starting address for the new block of memory assigned to it.

You allocate maxSize pointers for person, but then fail to allocate a struct for each person[i] before allocating for name, etc..

So you must allocate a struct, e.g. pointer[i] = malloc (sizeof *pointer[i]) before attempting to allocate person[i]->name = calloc(21, sizeof(char ));, ...

Also note, if you allocate based on the size of the derefernced pointer -- you will never get your allocation wrong, (your allocation of person is only correct as the result of happy-accident), instead, e.g.

person = malloc (maxSize * sizeof *person);
...
person[i] = malloc (sizeof *person[i]);

(and note a [] or -> counts as a dereference)

person[i]->name = calloc (21, sizeof *person[i]->name);

There is no need to cast the return of malloc, it is unnecessary. See: Do I cast the result of malloc?

Upvotes: 0

Gaurav Sehgal
Gaurav Sehgal

Reputation: 7542

person = (detailsOf **)malloc(maxSize * sizeof(detailsOf **));

should be

person = malloc(maxSize * sizeof(detailsOf *));

Then, this allocated memory to hold pointers to detailsOf but you never allocate memory for each detailsOf

for(int i=0; i<maxSize; i++)
{
   person[i]=malloc(sizeof(detailsOf));
}

Also your freeing of memory should be

for (int i = 0; i < maxSize; i++)
{
    free(person[i]->name);
    free(person[i]->phoneNum);
    free(person[i]->birthdate);
    free(person[i]);
}
free(person);

Remember while freeing just match your free calls with malloc calls.

Upvotes: 2

Related Questions