0

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");
}
melpomene
  • 84,125
  • 8
  • 85
  • 148
The Sheyx
  • 11
  • 3
  • Please ignore the menu variable. – The Sheyx May 24 '18 at 04:21
  • Who upvotes these questions? There's no apparent debugging effort, just a chunk of code and a memory access error (at minimum I'd expect the information you'd get from a debugger, i.e. "it crashes in line X because pointer Y is invalid"). This isn't even a [mcve]: It's incomplete (the program requires input, which is not provided) and not minimal (OP says "*please ignore the menu variable*" instead of just removing it from the code if it doesn't matter). – melpomene May 24 '18 at 04:40
  • @melpomene I think it is the person answering to insure the question isn't deleted after they answer. – David C. Rankin May 24 '18 at 04:43
  • @DavidC.Rankin If you are hinting at me, then i want to humbly let know, its not me. – Gaurav Sehgal May 24 '18 at 04:46
  • Oh no, no, I was suggesting it may have been me `:)` But @melpomene has a good point. There have been a rash of questions, that fail to meet the MCVE standards or that are duplicates many times over that have been upvoted. Unexplained. – David C. Rankin May 24 '18 at 04:47
  • 1
    sorry for that. it is my first time posting question here and i am a beginner so even though I ve been tryin to solve it since yesterday. i couldn't figure it out why. Debugger just said what i mentioned in the descr. Anyways, Sorry @melpomene for the time you spent glancing over my chunk of code – The Sheyx May 24 '18 at 04:55

3 Answers3

2
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.

Gaurav Sehgal
  • 7,422
  • 2
  • 18
  • 34
0

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?

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
0
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.

Sridhar Nagarajan
  • 1,085
  • 6
  • 14