I am trying to decrease the size of a malloc array, but it is throwing -1073741819 (0xC0000005) when I realloc a smaller size for the malloc.
typedef struct {
float reproduce_prob;
int mature;
int life;
int age;
char *direction;
int X;
int Y;
} slug;
slug *slugs = (slug *) malloc(sizeof(slug) * (slugCount + 1));
int slugCount = 0;
if (slugCheck(theGrid, frogs[i])) {
int pos = feedFrog(frogs[i], slugs, slugCount);
for (int z = pos; z < slugCount - 1; z++) {
slugs[z] = slugs[z + 1];
}
slugCount--;
slugs = realloc(slugs, sizeof(slugs) * (slugCount + 1));
frogs[i].initHung = 0;
}
the slugCount is not zero.
It is good practice to use obects not types in the sizeofs. Also it is good to have distinct and meaningful type and variable names to avoid this kind mistakes. I would call slug slugType or slug_type.
in this line you do not allocate enough space (assuming that the slug structure is larger than the pointer) as sizeof(slugs) is giving the size of the pointer to slug:
slugs = realloc(slugs, sizeof(slugs) * (slugCount + 1));
You also incorrectly use realloc as realloc may fail and you will have memory leak
slug *tmp;
tmp = realloc(slugs, sizeof(*tmp) * (slugCount + 1));
if(tmp)
{
slugs = tmp;
}
else
{
/* error handling */
}
As a side note: do not cast the result of malloc family functions. If Your code does not compile it means that you use C++ compiler to compile the C language code. It is not a good idea as C & C++ are different languages even if syntax looks similar.
How does this code compile?
slug *slugs = (slug *) malloc(sizeof(slug) * (slugCount + 1));
int slugCount = 0;
The compiler should be yelling at you for using slugCount before it has been defined.
If this code is building it means you’ve already defined slugCount in an enclosing scope, and its value may not be zero. That’s one problem.
You should always check the result of malloc, calloc, and realloc. Are you certain that neither the malloc nor realloc call have returned NULL?
This line is suspicious:
slugs = realloc(slugs, sizeof(slugs) * (slugCount + 1));
sizeof(slugs) gives you the size of the pointer, not the slug type - you haven’t extended your array by one element, you’ve shrunk it by a whole helluva lot. You might want to change that to
slug *tmp = realloc( slugs, sizeof *slugs * (slugCount + 1) );
You should always assign the result of realloc to a temporary variable. realloc will return NULL if it can’t satisfy the request and leave the original buffer in place. However, if you assign that NULL result back to your original pointer, you will lose your only reference to that memory.
Related
I need to allocate an array of integers within a function and then return it. The problem is that I don't know how much memory I need to allocate: it may be sizeof(int)*3 as it may be more memory than I got.
Since allocating a big chunk of memory that could be redundant or not enough, is not a nice solution I am going to use realloc for the first time.
Now I need to use it in a loop like that
for(i = 3; (res[i] = res[i-3] - res[i-2] - res[i-1]) >= 0; i++) {
res = realloc( res, sizeof(long long) * (i+2) );
}
Is it allowed to store the address returned from realloc in the same pointer given as argument?
And is that a good way to create an array of size defined at execution time?
Storing the address returned from realloc in the same pointer given as argument is allowed, but is not a good way because it will prevent from freeing the allocated memory when realloc fails.
It is good to first store the result to another pointer, and assign that to the original variable after checking if the pointer is not NULL.
for(i = 3; (res[i] = res[i-3] - res[i-2] - res[i-1]) >= 0; i++) {
long long* new_res = realloc( res, sizeof(long long) * (i+2) );
if (new_res == NULL) {
/* handle error (print error message, free res, exit program, etc.) */
} else {
res = new_res;
}
}
I'm very sorry if this is a duplicate question, but I have looked at various other answers and they do not seem to apply to my code.
I have defined a struct Coord which is simply an x and y limited to 4 bits each.
typedef struct {
unsigned int x:4;
unsigned int y:4;
} Coord;
I am using an array of Coords by doing Coord* snakeArr = malloc(2 * sizeof(Coord)); and keeping track of the array's size with int snakeArrSize = 2;. I have made this function to mimic the unshift() javaScript function.
void unshiftCoord(Coord *arr, Coord value, int *arrSize) {
// Debugging
printf("%li\n", (*arrSize + 1) * sizeof(Coord));
fflush(stdout);
// Allocate an extra slot in the array
arr = realloc(arr, (*arrSize + 1) * sizeof(Coord));
// Shift everything over
for (int i = *arrSize; i > 0; i--) {
arr[i] = arr[i - 1];
}
// Set the first value in the array
arr[0] = value;
// Update arrSize variable
*arrSize += 1;
}
This works perfectly fine but for some reason it gives the "invalid next size" error when I call the function for the 5th time. Here is the output of my program:
12
16
20
24
28
realloc(): invalid next size
Aborted (core dumped)
As you can see when the new size is increased to 28, realloc() fails.
One solution I came across was to use aSan. I did this with -fsanitize=address in my compiler flags, and I get this right when I run: ERROR: AddressSanitizer: heap-use-after-free... and a really long message. If you need it, I put it in this google doc.
After successful
arr = realloc(arr, (*arrSize + 1) * sizeof(Coord));
*arrSize += 1;
arr has *arrSize element, so arr[*arrSize] is out-of-range and you cannot use that to store something.
The loop
for (int i = *arrSize; i > 0; i--) {
should be
for (int i = *arrSize - 1; i > 0; i--) {
Also results of realloc() shouldbe checked to avoid dereferencing NULL.
And there is one more critical point: the argument arr is a copy of what is passed, so modification to that won't affect what is passed. Therefore, if realloc() returns new buffer, it will get lost and original invalidated arr will be used in later process.
To avoid this, a pointer to variable should be passed instead of arr and modification of the variable should be done via the pointer.
I have a function
populateAvailableExtensions(const char** gAvailableExtensions[], int gCounter)
which take a pointer to an array of strings and the number of elements in the array as parameters.
I allocate initial memory to that array using malloc(0). Specs say that it will either return a null pointer or a unique pointer that can be passed to free().
int currentAvailableExtensionCount = gCounter;
This variable will store number of string in gAvailableExtensions.
Inside this for loop
for (int i = 0; i < availableExtensionCount; ++i)
I have this piece of code
size_t sizeOfAvailableExtensionName =
sizeof(availableExtensionProperties[i].name);
reallocStatus = realloc(*gAvailableExtensions, sizeOfAvailableExtensionName);
memcpy(&(*gAvailableExtensions)[currentAvailableExtensionCount],
&availableExtensionProperties[i].name,
sizeOfAvailableExtensionName);
++currentAvailableExtensionCount;
where
availableExtensionProperties[i].name
returns a string.
This is how that struct is defined
typedef struct Stuff {
char name[MAX_POSSIBLE_NAME];
...
...
} Stuff;
realloc(*gAvailableExtensions, sizeOfAvailableExtensionName);
should add memory of size sizeOfAvailableExtensionName to *gAvailableExtensions de-referenced array.
memcpy(&(*gAvailableExtensions)[currentAvailableExtensionCount],
&availableExtensionProperties[i].name,
sizeOfAvailableExtensionName);
should copy the string (this sizeOfAvailableExtensionName much memory) from
&availableExtensionPropterties[i].name
address to
&(*gAvailableExtensions)[currentAvailableExtensionCount]
address.
But I don't think the code does what I think it should because I'm getting this error
realloc(): invalid next size
Aborted
(core dumped) ./Executable
EDIT: Full code
uint32_t populateAvailableExtensions(const char** gAvailableExtensions[], int gCounter) {
int currentAvailableExtensionCount = gCounter;
void* reallocStatus;
uint32_t availableExtensionCount = 0;
vkEnumerateInstanceExtensionProperties(
VK_NULL_HANDLE, &availableExtensionCount, VK_NULL_HANDLE);
VkExtensionProperties availableExtensionProperties[availableExtensionCount];
vkEnumerateInstanceExtensionProperties(
VK_NULL_HANDLE, &availableExtensionCount, availableExtensionProperties);
for (int i = 0; i < availableExtensionCount; ++i) {
size_t sizeOfAvailableExtensionName =
sizeof(availableExtensionProperties[i].extensionName);
reallocStatus = realloc(*gAvailableExtensions, sizeOfAvailableExtensionName);
memcpy(&(*gAvailableExtensions)[currentAvailableExtensionCount],
availableExtensionProperties[i].extensionName,
sizeOfAvailableExtensionName);
++currentAvailableExtensionCount;
}
return currentAvailableExtensionCount;
}
This is how an external function calls on that one,
uint32_t availableExtensionCount = 0;
availableExtensions = malloc(0);
availableExtensionCount = populateAvailableExtensions(&availableExtensions);
and
const char** availableExtensions;
is declared in header file.
EDIT 2: Updated the code, now gCounter holds the number of elements in gAvailableExtensions
This loop is totally messy:
for (int i = 0; i < availableExtensionCount; ++i) {
size_t sizeOfAvailableExtensionName =
sizeof(availableExtensionProperties[i].extensionName);
reallocStatus = realloc(*gAvailableExtensions, sizeOfAvailableExtensionName);
memcpy(&(*gAvailableExtensions)[currentAvailableExtensionCount],
availableExtensionProperties[i].extensionName,
sizeOfAvailableExtensionName);
++currentAvailableExtensionCount;
}
I assume the only lines that does what you expect them to do, are the lines for (int i = 0; i < availableExtensionCount; ++i) and ++currentAvailableExtensionCount;
First, the typical way to use realloc is like this:
foo *new_p = realloc(p, new_size);
if (!new_p)
handle_error();
else
p = new_p;
The point is that realloc will not update the value of p if a reallocation happens. It is your duty to update 'p'. In your case you never update *gAvailableExtensions. I also suspect that you don't calculate sizeOfAvailableExtensionCount correctly. The operator sizeof always return a compile time constant, so the realloc doesn't actuall make any sense.
The memcpy doesn't actally make any sense either, since you are copying the string into the memory of a pointer array (probably with an additional buffer overflow).
You said that *gAvailableExtensions is a pointer to an array of pointers to strings.
That means that you have to realloc the buffer to hold the correct number of pointers, and malloc memory for each string you want to store.
For this example, I assume that .extensionName is of type char * or char[XXX]:
// Calculate new size of pointer array
// TODO: Check for overflow
size_t new_array_size =
(currentAvailableExtensionCount + availableExtensionCount) * sizeof(*gAvailableExtensions);
char **tmp_ptr = realloc(*gAvailableExtensions, new_array_size);
if (!tmp_ptr)
{
//TODO: Handle error;
return currentAvailableExtensionCount;
}
*gAvailableExtensions = tmp_ptr;
// Add strings to array
for (int i = 0; i < availableExtensionCount; ++i)
{
size_t length = strlen(availableExtensionProperties[i].extensionName);
// Allocate space for new string
char *new_s = malloc(length + 1);
if (!new_s)
{
//TODO: Handle error;
return currentAvailableExtensionCount;
}
// Copy string
memcpy (new_s, availableExtensionProperties[i].extensionName, length + 1);
// Insert string in array
(*gAvailableExtensions)[currentAvailableExtensionCount] = new_s;
++currentAvailableExtensionCount;
}
If you can guarantee that the lifetime of availableExtensionProperties[i].extensionName is longer than *gAvailableExtensions, you can simplify this a little bit by dropping malloc and memcpy in the loop, and do:
char *new_s = availableExtensionProperties[i].extensionName;
(*gAvailableExtensions)[currentAvailableExtensionCount] = new_s;
Some harsh words at the end: It seems like you have the "Infinite number of Monkeys" approach to programming, just hitting the keyboard until it works.
Such programs will just only give the illusion of working. They will break in spectacular ways sooner or later.
Programming is not a guessing game. You have to understand every piece of code you write before you move to the next one.
int currentAvailableExtensionCount =
sizeof(*gAvailableExtensions) / sizeof(**gAvailableExtensions) - 1;
is just a obfuscated way of saying
int currentAvailableExtensionCount = 0;
I stopped reading after that, because i assume that is not what you intend to write.
Pointers in c doesn't know how many elements there are in the sequence they are pointing at. They only know the size of a single element.
In your case *gAvailableExtensions is of type of char ** and **gAvailableExtensions is of type char *. Both are pointers and have the same size on a typical desktop system. So on a 64 bit desktop system the expression turns into
8/8 - 1, which equals zero.
Unless you fix this bug, or clarify that you actually want the value to always be zero, the rest of the code does not make any sense.
Using what I have learned here: How to use realloc in a function in C, I wrote this program.
int data_length; // Keeps track of length of the dynamic array.
int n; // Keeps track of the number of elements in dynamic array.
void add(int x, int data[], int** test)
{
n++;
if (n > data_length)
{
data_length++;
*test = realloc(*test, data_length * sizeof (int));
}
data[n-1] = x;
}
int main(void)
{
int *data = malloc(2 * sizeof *data);
data_length = 2; // Set the initial values.
n = 0;
add(0,data,&data);
add(1,data,&data);
add(2,data,&data);
return 0;
}
The goal of the program is to have a dynamic array data that I can keep adding values to. When I try to add a value to data, if it is full, the length of the array is increased by using realloc.
Question
This program compiles and does not crash when run. However, printing out data[0],data[1],data[2] gives 0,1,0. The number 2 was not added to the array.
Is this due to my wrong use of realloc?
Additional Info
This program will be used later on with a varying number of "add" and possibly a "remove" function. Also, I know realloc should be checked to see if it failed (is NULL) but that has been left out here for simplicity.
I am still learning and experimenting with C. Thanks for your patience.
Your problem is in your utilisation of data, because it points on the old array's address. Then, when your call realloc, this area is freed. So you are trying to access to an invalid address on the next instruction: this leads to an undefined behavior.
Also you don't need to use this data pointer. test is sufficient.
(*test)[n-1] = x;
You don't need to pass data twice to add.
You could code
void add(int x, int** ptr)
{
n++;
int *data = *ptr;
if (n > data_length) {
data_length++;
*ptr = data = realloc(oldata, data_length * sizeof (int));
if (!data)
perror("realloc failed), exit(EXIT_FAILURE);
}
data [n-1] = x;
}
but that is very inefficient, you should call realloc only once in a while. You could for instance have
data_length = 3*data_length/2 + 5;
*ptr = data = realloc(oldata, data_length * sizeof (int));
Let's take a look at the POSIX realloc specification.
The description says:
If the new size of the memory object would require movement of the object, the space for the previous instantiation of the object is freed.
The return value (emphasis added) mentions:
Upon successful completion with a size not equal to 0, realloc() returns a pointer to the (possibly moved) allocated space.
You can check to see if the pointer changes.
int *old;
old = *test;
*test = realloc(*test, data_length * sizeof(int));
if (*test != old)
printf("Pointer changed from %p to %p\n", old, *test);
This possible change can interact badly because your code refers to the "same" memory by two different names, data and *test. If *test changes, data still points to the old chunk of memory.
What is the right way to malloc memory ? And what is the difference between them ?
void parse_cookies(const char *cookie, cookie_bank **my_cookie, int *cookies_num)
{
*my_cookie = malloc(sizeof(cookie_bank) * 1);
*my_cookie = (cookie_bank *)malloc(sizeof(cookie_bank) * 1);
my_cookie = (cookie_bank **)malloc(sizeof(cookie_bank) * 1);
///
}
I'm trying to malloc array of cookie_bank structs function.
I'm assuming that you want the function to allocate memory for an array and passing the result via a pointer parameter. So, you want to write T * x = malloc(...), and assign the result to a pointer argument, *y = x:
cookie_bank * myarray;
parse_cookies(..., &myarray, ...);
/* now have myarray[0], myarray[1], ... */
So the correct invocation should be, all rolled into one line,
parse_cookies(..., cookie_bank ** y, ...)
{
*y = malloc(sizeof(cookie_bank) * NUMBER_OF_ELEMENTS);
}
Your second example is the most correct. You don't need the *1 obviously.
*my_cookie = (cookie_bank *)malloc(sizeof(cookie_bank) * 1);
Your first example is also correct, although some compilers/flags will cause a complaint about the implicit cast from void*:
*my_cookie = malloc(sizeof(cookie_bank) * 1);
It you want to allocate more than one entry you'd generally use calloc() because it zeros the memory too:
*my_cookie = (cookie_bank*)calloc(sizeof(cookie_bank), 1);
your third example is just wrong:
my_cookie = (cookie_bank **)malloc(sizeof(cookie_bank) * 1);
This will overwrite the local my_cookie pointer, and the memory will be lost on function return.
I just would like to recommend you to read some C textbook. It seems to me that you do not have clear understanding on how pointers work in C language.
Anyway, here is some example to allocate memory with malloc.
#include <stdlib.h>
void parse_cookies(const char *cookie, cookie_bank **my_cookie, int *cookies_num)
{
if (cookies_num == NULL || *cookies_num == 0) {
return;
}
if (my_cookie == NULL) {
my_cookie = (cookie_bank**)malloc(sizeof(cookie_bank*) * *cookies_num);
}
for (int i = 0; i < *cookies_num; i++) {
*my_cookie = (cookie_bank*)malloc(sizeof(cookie_bank));
my_cookie++;
}
}
Of course, this example does not cover any error handling. Basically, my_cookie is pointer to pointer which means my_cookie is just pointer to point memory location where it holds array of pointers. The first malloc allocate the memory using size of pointer and requested number of cookie structure. Then second malloc actually allocate memory for each structure.
The problem of this function is that it can easily cause memory leak unless using this very carefully.
Anyway, it is important to understand how C pointer works.