2

I have the following structure

typedef struct h{
        int key;
        float data;
        char name[20];
}heaparr;

I would like to dynamically allocate memory for each element of

heaparr *heap;

To dynamically allocate memory for each element, I have used

heap[i]=(heaparr*)malloc(sizeof(heaparr));

but every time I compile the code, I get an assignment type mismatch error. How do I resolve the situation? Thanks in advance.

trincot
  • 317,000
  • 35
  • 244
  • 286
Ice_giant
  • 181
  • 1
  • 2
  • 6
  • 1
    You are confused. `heaparr *head;` declares a **single** pointer to which you can allocate 1-block of memory. If you want to individually allocate then use `heaparr **head;` and allocate some number of pointers, e.g. `head = malloc (somenum * sizeof *head);` and then you can allocate for each pointer `head[i] = malloc (sizeof *head[i]);` (but don't allocate more that `somenum-1` unless you `realloc` more pointers first. – David C. Rankin Jul 20 '18 at 04:32
  • Or you can use a fixed-number of pointers and allocate individually as @TheCrow explains below (but note -- you are limited to that fixed number). – David C. Rankin Jul 20 '18 at 04:38
  • Learn about [flexible array member](https://en.wikipedia.org/wiki/Flexible_array_member)s. They probably are relevant for your issue – Basile Starynkevitch Jul 20 '18 at 04:49

4 Answers4

3

You can only allocate dynamically through pointers. If you want to dynamically allocate each element of an array, then each element must be a pointer.

[EDIT] Thank to @David C. Rankin to point me that in this particular example I declared in the stack an array of 10 pointers, to make the code simpler. You can create a predefined-size array with any number of elements, but it comes with the limitation that you cannot realloc the heap data once the limit is reached. You can always create an array dynamically.

#include <stdlib.h>

typedef struct h {
    int key;
    float data;
    char name[20];
} heaparr;

int main()
{
    heaparr *heap[10];
    int i;
    for (i = 0; i < 10; ++i) {
        heap[0] = malloc(sizeof(heaparr));
    }

    return 0;
}
  • Ok, edited. I just wanted to follow the code flow of the question. Thanks. –  Jul 20 '18 at 04:34
  • Sure, you may also want to make clear you declare an *array of pointers* (`heaparr *[10]`), so you are limited to `10-pointers` and cannot `realloc` `heap` once the limit is reached. (perfectly valid way, but it comes with that limitation) – David C. Rankin Jul 20 '18 at 04:36
3

As a follow-on to the answer by TheCrow, if you did want to allocate for each heap[i] in a way that allows you to handle and unknown number of struct, then you can use a pointer-to-pointer to heaparr (e.g. heaparr **heap;) and then allocate some number of pointers initially and allocate for each struct as it is read from input.

The scheme is straight forward. You keep two counter variables. One representing the number of pointers allocated, the second representing the number used. When the number of pointers used equals the number allocated, you simply realloc more pointers before attempting to allocate/fill your next pointer.

The following is a simple example that reads data from stdin and expects each line to contain "key data name". There are initially 2 pointers allocated and the number of pointers are reallocated as needed by doubling the current number allocated when all pointers currently allocated have been filled, e.g.

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

/* if you need constants, #define them or use a global enum */
enum { NPTR = 2, MAXNM = 20, MAXC = 128 };

typedef struct {
    int key;
    float data;
    char name[MAXNM];
} heaparr;

int main (void) {

    char buf[MAXC] = "";    /* read buffer */
    size_t  n = 0,          /* current struct filled */
            nptr = NPTR;    /* initial/current number of pointers */
    heaparr **heap = NULL;  /* pointer-to-pointer to heaparr */

    /* allocate/validate nptr to heap */
    if (!(heap = malloc (nptr * sizeof *heap))) {
        perror ("malloc-heap");
        return 1;
    }

    while (fgets (buf, MAXC, stdin)) {          /* read each line */
        heaparr tmp = { .key = 0 };             /* tmp struct */
        if (sscanf (buf, "%d %f %19[^'\n']",    /* parse line/validate */
                    &tmp.key, &tmp.data, tmp.name) != 3) {
            fprintf (stderr, "error: failed conversion line %zu.\n", n);
            continue;       /* just read next line on conversion failure */
        }
        if (n == nptr) {    /* check if realloc needed */
            /* always relloc to a temporary pointer to avoid mem-leak */
            void *tmpheap = realloc (heap, nptr * 2 * sizeof *heap);
            if (!tmpheap) { /* validate realloc */
                perror ("realloc-tmpheap");
                break;  /* don't exit, original data still valid in heap */
            }
            heap = tmpheap; /* assign new block to heap */
            nptr *= 2;      /* update current pointers allocated */
        }
        if (!(heap[n] = malloc (sizeof *heap[n]))) { /* allocate heap[n] */
            perror ("malloc-heap[n]");
            break;
        }
        *heap[n++] = tmp;   /* assign tmp to heap[n], increment n */
    }

    for (size_t i = 0; i < n; i++) {    /* output all values */
        printf ("%3d %5.1f   %s\n", heap[i]->key, heap[i]->data, 
                                    heap[i]->name);
        free (heap[i]);     /* don't forget to free each struct */
    }
    free (heap);            /* don't forget to free pointers */

    return 0;
}

(4 structs worth of data are read below to require an realloc above)

Example Input File

$ cat dat/intfloatstr.txt
1 1.1 my
2 2.2 dog
3 3.3 has
4 4.4 fleas

Example Use/Output

$ ./bin/dynallocstruct <dat/intfloatstr.txt
  1   1.1   my
  2   2.2   dog
  3   3.3   has
  4   4.4   fleas

Memory Use/Error Check

In any code you write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.

It is imperative that you use a memory error checking program to insure you do not attempt to access memory or write beyond/outside the bounds of your allocated block, attempt to read or base a conditional jump on an uninitialized value, and finally, to confirm that you free all the memory you have allocated.

For Linux valgrind is the normal choice. There are similar memory checkers for every platform. They are all simple to use, just run your program through it.

$ valgrind ./bin/dynallocstruct <dat/intfloatstr.txt
==8846== Memcheck, a memory error detector
==8846== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==8846== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==8846== Command: ./bin/dynallocstruct
==8846==
  1   1.1   my
  2   2.2   dog
  3   3.3   has
  4   4.4   fleas
==8846==
==8846== HEAP SUMMARY:
==8846==     in use at exit: 0 bytes in 0 blocks
==8846==   total heap usage: 6 allocs, 6 frees, 160 bytes allocated
==8846==
==8846== All heap blocks were freed -- no leaks are possible
==8846==
==8846== For counts of detected and suppressed errors, rerun with: -v
==8846== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

Always confirm that you have freed all memory you have allocated and that there are no memory errors.

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
0

You can allocate memory to each array index with the help of pointers by taking the size of the subscript and start a loop with the size of array indexes required.

Also no need to typecast the return of the malloc. Find the code snippet as mentioned below:

typedef struct h
{    
 int key;
 float data;
 char name[20];
}heaparr;

int main()
{
  int     size = 4;
  int     iLoop = 0;
  heaparr *heap[size];

  for (iLoop = 0; iLoop < size; iLoop++)
  {
    heap[iLoop] = malloc(sizeof(heaparr));
  } 
return 0;
}

Hope this will clear your doubt.

AnkitK
  • 61
  • 2
-1

I think Below code is suite for You...

int main
{
    ///In Main Function you need to allocate the memory for structure format  
     heaparr *heap;
     int num,i; //How many structures you want it?
     printf("Enter the size");
     scanf("%d",&num);
     heap=malloc(num*sizeof(struct heaparr));
     for(i=0;i<num;i++)
       scanf("%d %f %s",&heap[i].key,&heap[i].data,heap[i].name);//access members and store data
    for(i=0;i<num;i++)
       printf("%d %f %s",heap[i].key,heap[i].data,heap[i].name);//print the data

return 0;
}
hariGS
  • 60
  • 1
  • 2
  • 14
  • 1
    There is no need to cast the return of `malloc`, it is unnecessary. See: [Do I cast the result of malloc?](http://stackoverflow.com/q/605845/995714). `scanf (... &heap[i].name);` should be `heap[i].name` (`name` is already a pointer.) If you don't validate the **return** of `scanf` -- you are inviting *Undefined Behavior*. Avoid answering with `"Try ...."`. It makes it appear you are unsure about the answer. – David C. Rankin Jul 20 '18 at 05:09
  • Next time i will recover my faults..thanking You @DavidC.Rankin – hariGS Jul 20 '18 at 05:52
  • Not a big deal. I'm just trying to help, and help make sure the answers are as informative as they can be. I didn't downvote because you are still relatively new. Always remember when answering, you step into the roll of teacher. You want to be a good one, and not one we can all remember for other reasons `:)` – David C. Rankin Jul 20 '18 at 05:55
  • 1
    Nice answer, but it can be improved. A clear answer must come with clear code. Indentation and spacing are good programming practices to reach that. A ugly code may be down-voted even when it's useful, or a less-useful code may be up-voted and even accepted as the right answer just because it's more pretty. –  Aug 29 '18 at 19:33