typedef struct {
char *word;
} STR;
int main()
{
STR *arr=(STR*)malloc(5*sizeof(*arr));
STR[2].word=(char*)malloc(200*sizeof(char));
STR[2].word=(char*)
#include <stdio.h>
#include <stdlib.h>
typedef struct{
char *word;
}STR;
int main(){
STR *arr=(STR*)malloc(5*sizeof(STR));
arr[2].word=(char*)malloc(200*sizeof(char));
if(realloc(arr[2].word, 400*sizeof(char))==NULL){
/* increasing char array size from 200 to 400 failed. 200 char array was unchanged */
printf("increasing array size not OK\n");
}
else{
printf("increasing array size OK\n");
}
free(arr[2].word);
free(arr);
return 0;
}
This seems redundant. But, if you are trying to create an array of strings using your structure, where the third element is malloc'd as a 199 character string and then realloced as a 399 character string, you would do it like so:
STR *arr = (STR*)malloc(5*sizeof(STR));
arr[2].word = (char*)malloc(200*sizeof(char));
arr[2].word = (char*)realloc(arr[2].word,400*sizeof(char));
Your primary problem is you are using the typedef
name STR
where you should be using the variable name arr
when allocating and reallocating arr[2].word
.
Do NOT cast the return of malloc
, it is unnecessary. See: Do I cast the result of malloc? for thorough explanation. All you need to allocate an array of 5 STR
is:
STR *arr = malloc (5 * sizeof (*arr)); /* allocate array of 5 STR */
(note: the parenthesis are optional with sizeof
, so it could also be properly written):
STR *arr = malloc (5 * sizeof *arr); /* allocate array of 5 STR */
After you declare STR *arr = malloc (5 * sizeof (*arr))
, you allocate word
as follows:
arr[2].word = malloc (200 * sizeof *(arr[2].word));
NOT
STR[2].word = malloc (200 * sizeof *(arr[2].word));
You must validate every allocation. E.g.:
STR *arr = malloc (5 * sizeof (*arr)); /* allocate array of 5 STR */
if (!arr) {
fprintf (stderr, "error: virtual memory exhausted.\n");
return 1; /* or handle error as appropriate */
}
Never realloc
using the pointer itself, if realloc
fails, you have lost the pointer to your original data and cannot free the memory. Instead use a simple temporary variable:
void *tmp = realloc (arr[2].word, 400 * sizeof *(arr[2].word));
if (!tmp) {
fprintf (stderr, "error: realloc() virtual memory exhausted.\n");
return 1;
}
arr[2].word = tmp;
In any code your 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. Get in the habit of tracking and freeing all memory you allocate rather than relying on it being done by exit. This will pay dividends when you begin writing more complex code that allocates memory within functions in your code. In this case, you would need:
free (arr[2].word); /* free allocated memory */
free (arr);
Putting those pieces together, you could do:
typedef struct {
char *word;
} STR;
int main (void)
{
STR *arr = malloc (5 * sizeof (*arr)); /* allocate array of 5 STR */
if (!arr) { /* validate allocation */
fprintf (stderr, "error: virtual memory exhausted.\n");
return 1; /* or handle error as appropriate */
}
/* allocate/validate arr[2].word */
if (!(arr[2].word = malloc (200 * sizeof *(arr[2].word)))) {
fprintf (stderr, "error: virtual memory exhausted.\n");
return 1; /* or handle error as appropriate */
}
/* realloc/validate using temporary variable */
void *tmp = realloc (arr[2].word, 400 * sizeof *(arr[2].word));
if (!tmp) {
fprintf (stderr, "error: realloc() virtual memory exhausted.\n");
return 1;
}
arr[2].word = tmp;
free (arr[2].word); /* free allocated memory */
free (arr);
return 0;
}
Example Use/Valgrind Output
It is imperative that you use a memory error checking program to insure you haven't written beyond/outside your allocated block of memory, attempted to read or base a jump on an uninitialized value and finally to confirm that you have freed all the memory you have allocated.
For Linux valgrind
is the normal choice. There are many subtle ways to misuse a pointer or new block of memory. Using a memory error checker allows you to identify any problems and validate proper use of of the memory you allocate rather than finding a problem exists through a segfault
. There are similar memory checkers for every platform. They are all simple to use, just run your program through it.
For example, compiling your code and saving the executable as ./bin/alloc
, you would then make basic use of valgrind
simply by running valgrind
with your program as the first argument:
$ valgrind ./bin/alloc
==8949== Memcheck, a memory error detector
==8949== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==8949== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==8949== Command: ./bin/alloc
==8949==
==8949==
==8949== HEAP SUMMARY:
==8949== in use at exit: 0 bytes in 0 blocks
==8949== total heap usage: 3 allocs, 3 frees, 640 bytes allocated
==8949==
==8949== All heap blocks were freed -- no leaks are possible
==8949==
==8949== For counts of detected and suppressed errors, rerun with: -v
==8949== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Always confirm All heap blocks were freed -- no leaks are possible and equally important ERROR SUMMARY: 0 errors from 0 contexts. (note: some OS's do not provide adequate memory exclusion files (the file that excludes system and OS memory from being reported as in use) which will cause valgrind
to report that some memory has not yet been freed despite the fact you have done your job and freed all blocks you allocated and under your control.)
Look it over and let me know if you have any questions.
(note: C favors lower-case names, reserving all-caps for constants and macros. It's just style, so it is up to you.)