I'm trying to create a simple dynamic array of structures, but I'm unsure about how to go about doing it.
I have
n = 1;
typedef struct {
char wordName [50];
int counter;
}Words;
Words * array;
And now I want to reallocate it in this loop.
if(strlen(token) > 6){
array = (Words*)realloc(array, sizeof(Words)*n++);
strcpy(array->wordName, token);
//printf("%s ", array->wordName);
array++;
}
I can add data to the structure, it prints it all out in a loop just fine. But when I add array++, I get:
realloc(): invalid pointer
Am I accessing the data incorrectly? Or do I not even have any more pointers beyond the head?
array++; causes array to advance by sizeof (a_pointer) so it now no longer points to address first returned by realloc(). That means any future attempt to realloc() with the new address of array will result in the error "Invalid pointer, pointer was not initially allocated with call to malloc, calloc or realloc".
Further, if array is not initialized NULL, then you cannot use realloc() for the initial allocation. Initializing n = 1; mixes a count with and index. Always keep the count so it is the next index to be filled. For 0 you can use an if / else or ternary, e.g.
n = 0;
...
if (n) { /* if n > 0 (not 1st allocation, use realloc) */
/* always realloc using a temporary pointer */
void *tmp = realloc (array, (n + 1) * sizeof *array);
if (!tmp) { /* validate EVERY allocation */
/* handle error, return */
}
array = tmp; /* assign reallocated block to array */
n += 1; /* increment count */
}
else { /* initial allocation */
array = malloc (sizeof *array);
if (!array) { /* validate EVERY allocation */
/* handle error, return */
}
n += 1; /* increment count */
}
/* rest of your strcpy here
* VALIDATE strlen(token) > 0 AND < 50
*/
/* note: you can consolidate both n += 1; here. duplicated for clarity */
You always call realloc() with a temporary pointer because when (not if) realloc() fails it returns NULL which will overwrite the address pointing to the allocated block of memory creating a memory leak. e.g. never do:
pointer = realloc (pointer, size);
Instead, by using a temporary pointer, if realloc() fails, pointer (your array) will still point to the last allocated and still valid block of memory allowing you to use what is stored there AND allowing you to free() that block of memory when you are done with it.
Note, you can use a ternary, but it is much less readable:
Words *array = NULL;
size_t n = 0;
...
void *tmp = realloc (array, sizeof *array * n ? n + 1 : 1);
if (!tmp) { /* validate EVERY allocation */
/* handle error, return */
}
array = tmp;
n += 1;
/* rest of your strcpy here
* VALIDATE strlen(token) > 0 AND < 50
*/
In C, there is no need to cast the return of malloc (or calloc or realloc), it is unnecessary. See: Do I cast the result of malloc?
Related
I wondered if I have a memory leak, I don't know whether I should use free() when realloc fails or it does that automatically.
for example, I have a dynamic array of chars, each time I'm reaching the end of it from input, I'm adding more memory using realloc.
I'm saving the last address just in case the realloc fails.
int cntan = 0;
char *p = (char *)malloc(MEM_SIZE * sizeof(char));
char *q = p; /*backup pointer*/
int c;
long current = 0, last = MEM_SIZE - 1;
while ((c = getchar()) != EOF)
{
if (current >= last) /* if reached last bit */
{
q = p;
p = (char *)realloc(q, last + (MEM_SIZE * sizeof(char))); /* attempting to add more bits */
if (p == NULL)
{
printf("Memory allocation failed, printing only stored values \n");
return q;
}
last += MEM_SIZE;
}
p[current] = c;
++current;
if (isalnum(c)) /* checking if current char is alpha-numeric */
cntan++;
}
in this example, I wonder I should free(p) if p==NULL
whole code if someone interested: Pastebin
You should free() the original pointer, not the one returned by realloc(). Passing NULL to free() won’t do anything.
To clarify: the pointer returned by realloc() on success may not be the same as the original pointer.
Other problems with code:
Length unknown
return q; returns the pointer, yet the caller lacks information about how big an allocation (current).
Conceptually wrong size calculation
Scaling by sizeof(char)applies to the sum. Makes no difference in this case as sizeof char is always 1.
// last + (MEM_SIZE * sizeof(char))
(last + MEM_SIZE) * sizeof(char)
Missing malloc() check
Code checks the return value of realloc(), but misses checking malloc().
Note: cast not needed. Consider:
// p = (char *)realloc(q, last + (MEM_SIZE * sizeof(char)));
p = realloc(q, sizeof q[0] * (last + MEM_SIZE));
How can I free an array of pointers where each pointer points to an address of a string which I allocated inside of a function?
I created a simple array of pointers, *pointers[], inside my main and I'm passing it to readline which returns the amount of lines I have read.
The purpose of this is to store all the lines of the input separated by '\n'. Each line is stored in a pointer in the array of pointers.
So after readline is called and it returns, I can printf("%s", pointers[0]) which will show the first line the user typed in.
The way I assign a line to each pointer in my array is inside readline by allocating a char pointer, *p, to have MAXLENGTH sizes and passing the current address of p to the respective pointer. After each assignment is done, I jump to the next free address of p.
Finally, my question is if I have to free (and how) my array of pointers after the readline routine is complete and I have printed all the lines stored.
I'll leave the two functions, main and readline, here for you.
#define NUMOFLINES 5
#define MAXLENGTH 1000
void main(void) {
char *pointers[NUMOFLINES]; // Array of pointers to string
int nlines; // Number of pointers read
nlines = readlines(pointers);
writelines(pointers, nlines);
/* FAILED ATTEMPT TO FREE THE ARRAY OF POINTERS */
for(int i = 0 ; i < nlines ; i++)
free(pointers[i]);
}
int readlines(char *pointers[]) {
char line[MAXLENGTH];
char *p;
int iptr, len;
/* ALLOCATE P */
p = malloc(sizeof(char) * MAXLENGTH);
for(iptr = 0 ; iptr < NUMOFLINES && (len = get_line(line)) > 0 ; iptr++)
{
strcpy(p, line); // copy the line to the array, ending in len-th position
pointers[iptr] = p; // Pass current adress 'p' to the respectively index of pointers
p += len+1; // Next free adress in array p
}
return iptr;
}
As you can see I tried to free by going through each pointer and calling free(pointer[i], but all I get is
malloc(): corrupted top size
Aborted (core dumped)
Do I need to call free?
Thanks in advance.
You are calling malloc() only 1 time, but you are calling free() multiple times. Every char* in your array points within that single malloc()'ed memory block. You can only call free() 1 time on the starting address of that block. Calling free() on addresses inside the block is undefined behavior.
Also, the memory block you are allocating with malloc() is not nearly large enough, assuming each string that get_line() outputs can be up to MAXLENGTH characters. You are only allocating enough memory for the maximum length of 1 single line, so as soon as your reading loop has copied MAXLENGTH characters into the allocated block, you are advancing your p pointer beyond the bounds of the block, causing subsequent strcpy()'s to write into and corrupt random memory.
If you want to stay with a single malloc() and sub-divide it, try something more like this instead:
#define NUMOFLINES 5
#define MAXLENGTH 1000
int main(void) {
char *pointers[NUMOFLINES], *buffer;
int nlines = readlines(pointers, &buffer);
if (nlines < 0) return -1;
writelines(pointers, nlines);
free(buffer);
return 0;
}
int readlines(char *pointers[], char **buffer) {
*buffer = malloc(sizeof(char) * (NUMOFLINES * MAXLENGTH));
if (*buffer == NULL) return -1;
int iptr, len;
char *p = *buffer;
for(iptr = 0; (iptr < NUMOFLINES) && ((len = get_line(p)) > 0); ++iptr)
{
pointers[iptr] = p;
p += len + 1;
}
return iptr;
}
Otherwise, I suggest you allocate a separate buffer for each pointer in the array, eg:
#define NUMOFLINES 5
#define MAXLENGTH 1000
int main(void) {
char *pointers[NUMOFLINES];
int nlines = readlines(pointers);
if (nlines < 0) return -1;
writelines(pointers, nlines);
for(int i = 0; i < nlines; ++i)
free(pointers[i]);
return 0;
}
int readlines(char *pointers[]) {
char line[MAXLENGTH], *p;
int iptr, len;
for(iptr = 0; (iptr < NUMOFLINES) && ((len = get_line(line)) > 0); ++iptr)
{
p = malloc(sizeof(char) * (len + 1));
if (p == NULL) {
for(int j = 0; j < iptr; ++j) free(pointers[j]);
return -1;
}
memcpy(p, line, sizeof(char) * len);
p[len] = '\0';
pointers[iptr] = p;
}
return iptr;
}
You only call malloc once, so you should only call free once.
After readlines returns, pointers[0] points to the start of the memory you allocated, while the remaining array members point someplace within that same block of memory. That means there's only one pointer to free.
So instead of this:
for(int i = 0 ; i < nlines ; i++)
free(pointers[i]);
Just do this:
free(pointers[0]);
To reiterate, you should only pass to free a pointer value that was returned from malloc (or realloc or calloc).
You don't need to free the other pointers you maintain within your buffer. If you do a single
p = malloc(sizeof(char) * MAXLENGTH);
then you need a single
free(p);
The malloc and free have to match exactly 1-to-1 and be called with the same addresses.
Since you want to modify p, you should do:
char* original = malloc(sizeof(char) * MAXLENGTH);
p = original;
and, once done:
free(original)
void *copy_elements(void *ele_src[], int ele_cnt, size_t ele_size)
{
/*
* Allocate buffer for ele_cnt objects, each of ele_size bytes
* and copy from locations designated by ele_src
*/
void *result = malloc(ele_cnt * ele_size);
if (result == NULL)
/* malloc failed */
return NULL;
void *next = result;
int i;
for (i = 0; i < ele_cnt; i++) {
/* Copy object i to destination */
memcpy(next, ele_src[i], ele_size);
/* Move pointer to next memory region */
next += ele_size;
}
return result;
}
The above code has a vulnerability issue. Under some ele_cnt and ele_size values, the code might crash. I suspect it has to do with unsigned - signed conversion that happens with malloc and memcpy but I'm not sure how to exploit this properly. Any help would be thankful!
There are multiple issues with the posted code:
since ele_cnt is defined with a signed type, one should test if the value passed is negative or zero and return NULL without attempting to allocate a huge amount of memory, which may cause a runtime error.
for defensive coding, ele_size should not be zero either.
next += ele_size; is invalid as next has void * type. Some compilers allow it as an extension, but the code is not portable.
copying the elements one at a time is inefficient, a single call to memcpy suffices.
Here is a modified verion:
#include <stdlib.h>
#include <string.h>
void *copy_elements(const void *ele_src[], int ele_cnt, size_t ele_size)
{
/*
* Allocate buffer for ele_cnt objects, each of ele_size bytes
* and copy from locations designated by ele_src
*/
void *result;
if (ele_cnt <= 0 || ele_size == 0) {
/* invalid arguments */
return NULL;
}
if ((result = malloc(ele_cnt * ele_size)) == NULL) {
/* malloc failure */
return NULL;
}
/* copy all elements with a single call to memcpy */
return memcpy(result, ele_src, ele_cnt * ele_size);
}
I think the problems is next += ele_size is not as you suppose. When you adding pointer, it automatically multiply with offset. You can print next value in for loop so you can check if it true using printf("%p", next)
Okay, imagine I have a char**, would this be the correct way to allocate memory?
I mean: allocate memory for the char** itself and then for each char*...
char** fraseUsuario = NULL;
int length = 100, i = 0;
fraseUsuario = (char **) malloc(sizeof (char*)); //Not pretty sure
for (i = 0; i < 3; i++) {
fraseUsuario[i] = (char *) malloc(length * sizeof (char));
if (fraseUsuario[i] == NULL) {
printf("error\n");
return -1;
}
gets(fraseUsuario[i]);
}
for (i = 0; i < 3; i++) {
printf("%s\n", fraseUsuario[i]);
free(fraseUsuario[i]);
}
And btw, how exactly does free() work? I mean, when I call it at the end, with the debugger it seems as if it does "nothing", if "Hello" is stored in the array, it will continue to be stored there after the free call... is that the normal behavior?
What do you mean allocate memory for the char ** itself? You allocate memory for a variable on the stack when you define it. The following statement defines (allocates memory) fraserUsuario and initializes it to NULL.
char **fraseUsuario = NULL;
I think what you probably meant is how to dynamically allocate an array of char **, i.e., pointer to a pointer to a character. Then you again dynamically allocate an array for each element of the previous allocated array. Do not use gets. It's deprecated and unsafe to use. Use fgets instead. Also, please don't cast the result of malloc. You don't get any benefit and you can run into error if you forget to include the header stdlib.h which contains its prototype. Here's how you do it.
char **fraseUsuario = NULL;
int max_string_len = 100 + 1; // maximum string length. +1 for null byte
int num_string = 3; // number of strings to read
int i, j;
fraseUsuario = malloc(num_string * sizeof *fraseUsuario);
if(fraseUsuario == NULL) { // check for NULL
// handle the case
printf("not enough memory\n");
return -1;
}
for(i = 0; i < num_string; i++) {
fraseUsuario[i] = malloc(max_string_len * sizeof(char));
if(fraseUsuario[i] == NULL) { // check for NULL
printf("not enough memory\n");
for(j = 0; j < i; j++)
free(fraseUsuario[j]); // free memory before returning
free(fraseUsuario); // free memory before returning
return -1;
}
if(fgets(fraserUsuario[i], max_string_len, stdin) == NULL) {
// reading string failed
*fraserUsuario[i] = '\0'; // empty string
}
}
for(i = 0; i < 3; i++) {
printf("%s\n", fraseUsuario[i]);
free(fraseUsuario[i]); // free memory allocated for strings
}
free(fraseUsuario); // free memory allocated for pointers to strings
fraseUsuario = NULL;
When you call free on a memory address which you got by a call to malloc, the memory block is returned to the free pool on the heap. This memory block can then later be reused by malloc. Once you free memory, you have given up your ownership of it. It no longer belongs to you and attempting to use it is illegal and will result in undefined behaviour and likely segfault.
You only allocate memory for one char* but use three.
To fix this do:
#define STR_MAXIMUM (3)
...
size_t length = 100, i = 0; /* No need to use a signed type.
size_t is meant as index and size type. */
char ** fraseUsuario = malloc(STR_MAXIMUM * sizeof(*fraseUsuario));
for (i = 0; i < STR_MAXIMUM; ++i)
{
fraseUsuario[i] = malloc(length * sizeof(*fraseUsuario));
...
Also add error checking to system calls.
Also^2: Do not use gets() as there is no way for the compiler or the machine to prevent the buffer passed in from overflowing. Use fgets() instead.
fgets(fraseUsuario[i], length, stdin);
Can I return an array that is created dynamically (using malloc) inside a function back to its caller?
I know that returning a statically allocated array is wrong because the stack unwinds as the function returns and variable is no longer valid but what about a dynamically allocated variable?
Returning anything allocated with malloc is fine, as long as whoever uses your function takes care of free()ing it when they're done. malloc allocates on the heap which is essentially global within your program.
As others have noted, you can in fact return a char pointer.
However, another common method is for the caller to pass in the pointer for the method to fill along with a length parameter. This makes it so the function responsible for allocating the memory will also be the same function responsible for freeing the memory, which can make memory leaks easier to see. This is what functions such as snprintf and strncpy do.
/* Performs a reverse strcpy. Returns number of bytes written if dst is
* large enough, or the negative number of bytes that would have been
* written if dst is too small too hold the copy. */
int rev_strcpy(char *dst, const char *src, unsigned int dst_len) {
unsigned int src_len = strlen(src); /* assumes src is in fact NULL-terminated */
int i,j;
if (src_len+1 > dst_len) {
return -(src_len+1); /* +1 for terminating NULL */
}
i = 0;
j = src_len-1;
while (i < src_len) {
dst[i] = src[j];
++i;
++j;
}
dst[src_len] = '\0';
return src_len;
}
void random_function() {
unsigned int buf_len;
char *buf;
int len;
const char *str = "abcdefg";
buf_len = 4;
buf = malloc(buf_len * sizeof(char));
if (!buf) {
/* fail hard, log, whatever you want */
return;
}
/* ...whatever randomness this function needs to do */
len = rev_strcpy(buf, str, buf_len);
if (len < 0) {
/* realloc buf to be large enough and try again */
free(buf);
buf_len = -len;
buf = malloc(buf_len * sizeof(buf));
if (!buf) {
/* fail hard, log, whatever you want */
return;
}
len = rev_strcpy(buf, str, sizeof(buf));
}
/* ... the rest of the randomness this function needs to do */
/* random_function has allocated the memory, random_function frees the memory */
free(buf);
}
This can lead to some overhead though if you don't know how big a buffer you'll need and need to call the function twice, but often the caller has a good idea to how large the buffer needs to be. Also it requires a little more logic to ensure the function doesn't overrun the given buffer. But it keeps the responsibility of freeing the memory with whatever is allocating the memory, while also allowing the option to pass local stack memory.
Example just returning the char*:
/* Performs a reverse strcpy. Returns char buffer holding reverse copy of
* src, or NULL if memory could not be allocated. Caller is responsible
* to free memory. */
char* rev_strcpy(const char *src) {
unsigned int src_len = strlen(src); /* assumes src is in fact NULL-terminated */
char *dst;
int i,j;
dst = malloc((src_len+1) * sizeof(char));
if (!dst) {
return NULL;
}
i = 0;
j = src_len-1;
while (i < src_len) {
dst[i] = src[j];
++i;
++j;
}
dst[src_len] = '\0';
return dst;
}
void random_function() {
char *buf;
const char *str = "abcdefg";
/* ...whatever randomness this function needs to do */
buf = rev_strcpy(str);
if (!buf) {
/* fail hard, log, whatever you want */
return;
}
/* ... the rest of the randomness this function needs to do */
/* random_function frees the memory that was allocated by rev_strcpy */
free(buf);
}
Yes you can. Just malloc() the array inside your function and return the pointer.
BUT, the caller needs to understand it needs to be freed at some point, or you'll have a memory leak.
You can certainly return an array allocated with malloc, but you have to make sure the caller of the function eventually releases the array with free; if you don't free a malloc'd array, the memory remains "in use" until program exit.