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.