Expanding an array of ints using realloc crashes! - c

I'm trying to expand an array of ints on the heap using realloc but the programme is crashing when I use my custom function "ExpandArrayOfInts" but works fine when I write the expander code within main.
Here is the code (file: main.c) with #defines for both approaches.
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
int ExpandArrayOfInts(int* arrayToExpand, int expandBy, int inArraySize, int* outArraySize);
int main (int argc, char** argv)
{
#if 1//CODE THAT WORKS
int arraySize = 10;
int* arrayDnmc = NULL;
int* arrayDnmcExpndd;
for (int i = 0; i< 10; ++i)
{
arrayDnmcExpndd = (int*)realloc(arrayDnmc, (arraySize + (i * 10)) * sizeof(int));
if (arrayDnmcExpndd != NULL)
{
arrayDnmc = arrayDnmcExpndd;
memset(arrayDnmc, 0, (arraySize + (i * 10)) * sizeof(int));
}
else
{
printf("Failed to (re)alloc memory for arrayDnmc!\n");
free(arrayDnmc);
return -1;
}
}
free(arrayDnmc);
#else //CODE THAT DOESN'T WORK (Which I'm trying to make it work)
int maxSize = 100;
int arraySize = 10;
int* arrayDnmc = NULL;
arrayDnmc = (int*)malloc(arraySize * sizeof(int));
if (arrayDnmc != NULL)
{
memset(arrayDnmc, 0, arraySize * sizeof(int));
}
else
{
printf("malloc failure!\n");
return -1;
}
while (arraySize < maxSize)
{
if (0 != ExpandArrayOfInts(arrayDnmc, 5, arraySize, &arraySize))
{
printf("Something went wrong.\n");
break;
}
//do something with the new array
printf("new size: %i\n", arraySize);
}
free(arrayDnmc);
#endif
return 0;
}
int ExpandArrayOfInts(int* arrayToExpand, int expandBy, int inArraySize, int* outArraySize)
{
int newSize = inArraySize + expandBy;
int* arrayTemp = (int*)realloc(arrayToExpand, newSize * sizeof(int));
if (arrayTemp != NULL)
{
arrayToExpand = arrayTemp;
*outArraySize = newSize;
return 0;
}
return -1;
}
The part that doesn't work gives the following output:
new size: 15
new size: 20
and then I get the crash message:
"Windows has triggered a breakpoint in c_cplusplus_mixing.exe.
This may be due to a corruption of the heap, which indicates a bug in c_cplusplus_mixing.exe or any of the DLLs it has loaded.
This may also be due to the user pressing F12 while c_cplusplus_mixing.exe has focus.
The output window may have more diagnostic information."
The call stack doesn't seem very meaningful (at least for a novice like myself).
Call Stack:
ntdll.dll!775c542c()
[Frames below may be incorrect and/or missing, no symbols loaded for ntdll.dll]
ntdll.dll!7758fdd0()
ntdll.dll!7755b3fc()
Note, I'm using visual studio 2008 and running Debug build. (Release doesn't work either).
Could anyone please point me to where I'm going wrong! and please let me know if more details are needed.
Many thanks in advance,
Hasan.

The problem is that ExpandArrayOfInts is receiving a pointer to an int instead of a pointer to the pointer that has to reallocate. It should look like this:
int ExpandArrayOfInts(int** arrayToExpand, int expandBy, int inArraySize, int* outArraySize)
and then you would call it like this:
ExpandArrayOfInts(&arrayDnmc, 5, arraySize, &arraySize))
I'd recommend you to look for questions related to pointers in stackoverflow so that you get a better understanding of them.

From the realloc() documentation on my system:
realloc() returns a pointer to the
newly allocated memory, which is
suitably aligned for any kind of
variable and may be different from
ptr, or NULL if the request fails.
Your ExpandArrayOfInts() declaration and implementation does not allow realloc to modify the actual pointer in main() - it implicitly assumes that its value cannot change. When realloc() moves the memory area and does return a different pointer, it calls free() on the pointer it was called with. The rest of your program, though, goes on using the original value which is now invalid, hence the crash.
You should use a pointer-to-a-pointer to pass the memory area pointer by reference, instead:
int ExpandArrayOfInts(int** arrayToExpand, int expandBy, int inArraySize, int* outArraySize)
.
.
.
*arrayToExpand = (int*)realloc(*arrayToExpand, newSize * sizeof(int));

Related

After creating an array through dynamic allocation, a problem occurs when changing the memory size through realloc in C

I am practicing C language.
I wanted to use dynamic allocation to use only the size of the string I input as memory and check whether the input string was properly saved.
So, I wrote the following code using malloc and realloc functions.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void str_copy(char* str_array_f) {
void* tmp;
char buf;
unsigned char arr_size = 1;
unsigned char arr_cur = 0;
while ((buf = getchar())) {
if (buf == '\n') {
break;
}
str_array_f[arr_cur++] = (char)buf;
tmp = realloc(str_array_f, ((arr_size++) * sizeof(char)) + sizeof(char));
if (tmp != 0) {
str_array_f = tmp;
}
else {
printf("memory leak error occur! \n");
break;
}
}
str_array_f[arr_size - 1] = 0x00;
}
void main() {
int contiune = 1;
while (contiune) {
char* str_array = malloc(sizeof(char) + sizeof(char));
printf("Please type something : ");
str_copy(str_array);
printf("'str_array' have this : %s \n", str_array);
printf("-------------------------------------------------\n");
if (str_array[0] == '1') {
contiune = 0;
}
free(str_array);
}
}
And, as a result of the performance,
The following problems have occurred.
Strange values sometimes appear from the 5th character of the intermittently printed value
(To reproduce this issue, it is recommended to remove the while loop and try repeatedly)
In the case of repeatedly receiving a value by using the while loop, an error occurs after 4 repetitions.
If the allocated memory of tmp, which is a void type pointer, is released after line 22(e.g., 'free(tmp);'), when executed, no output and an error occurs immediately.
For the above 3 problems, I am not sure what is the cause and how to fix it.
Please let me know if there is a solution.
And, if there is a bad coding method in my code in terms of efficiency or various aspects, I would appreciate it if you let me know.
*Programming execution environment : Visual studio 2019
to explain what you're doing wrong I'm going to use a minimal example here
void change_x(int x) {
x = 2;
}
int main() {
int x = 1;
change_x(x);
printf("%i\n", x); // it'll print 1 not 2
return 0;
}
here the integer x is copied when the function is called and changing it won't really change the x in main. similarly you are doing in your code that str_array_f = tmp; it really won't change the str_array but the copied value. and you're trying to free a pointer that was reallocated before.
the fix for the example above is not to pass the value x instead pass the address of x (which is equivalent to pass by reference in other languages)
void change_x(int* x) {
*x = 2;
}
int main() {
int x = 1;
change_x(&x);
printf("%i\n", x); // it'll print 1 not 2
return 0;
}
and for your code
void str_copy(char** str_array_f) {...} // change the parameter
*str_array_f = tmp; // de reference and use it.
str_copy(&str_array); // call with it's address
And one more thing, don't reallocate more often it's not efficient. instead just just allocate your "array" type with a minimum size and when it's filled reallocate it with the size of 2 times of it (or 1.5 if you like)

Error with `realloc()` with arraylist-like struct with two arrays

As part of a personal project, I'm trying to create a dynamic array of 2-tuples that show a) the line in a program and b) the number of bytecode tokens associated with that line. I've implemented this as a struct of arrays:
typedef struct{
int count; // Number of elements
int capacity; // total capacity of arraylist
int* lines;
int* lineCount;
}
this is based on the example from the codebase, as such:
int count;
int capacity;
uint8_t* bytes;
My problem comes from re-allocation - I have several helper functions/macros for growing and re-allocating the array lists memory - here particularly the macro GROW_ARRAY and reallocate(), as described below. When I try and re-allocate lines, it works fine, but I get a segmentation fault and realloc(): invalid old size several times when I attempt to reallocate lineCount after it
I'm using the code base from Bob Nystrom's Crafting Interpreters, especially this first part here https://craftinginterpreters.com/chunks-of-bytecode.html#challenges. Most of the code comes from there, albeit tinkered with some of having added
Mostly, I've added a lot of checks and been running this with all the debug features in gcc I can find. Notably, realloc(): invalid old size has stop appearing as I've tinkered with the code some.
EDIT: Added main function that should reproduce behavior
int main() {
LineArray lines;
// Initialize to 0 / NULL
initLineArray(&lines);
updateLineArray(&lines, 0, 1);
}
// the structure I'm using
typedef struct {
int capacity;
int count;
int* lines;
int* lineCount;
} LineArray;
/* Note LineArray has already been initialized earlier with
capacity=0;
count=0;
lines=NULL;
lineCount=NULL;
*/
void updateLineArray(LineArray* array, int line, int count) {
// IF line in `lines` -- update it
int index = containsLine(array, line);
if (index != -1) { // IF Index is not Error Code
// I think I fixed a bug here?
array->lineCount[index] += count;
return;
}
//ELSE -- add line to end (naturally appends); then increment
else {
//Check to see if array would be overgrown
if (array->capacity < array->count + 1) {
//IF yes, regrow array
int old_capacity = array->capacity;
array->capacity = GROW_CAPACITY(old_capacity);
// Reallocate arrays.
array->lines = GROW_ARRAY(array->lines, int, old_capacity,
array->capacity);
array->lineCount = GROW_ARRAY(array->lineCount, int, old_capacity,
array->capacity);
}
// Properly update the lines
array->lines[array->count] = line;
array->lineCount[array->count] = count;
array->count++;
return;
}
}
//The memory management functions/macros I'm using here
#define GROW_CAPACITY(capacity) \
((capacity) < 8 ? 8 : (capacity) * 2)
#define GROW_ARRAY(previous, type, oldCount, count) \
(type*) reallocate(previous, sizeof(type) * (oldCount), \
sizeof(type) * (count))
void* reallocate(void* previous, size_t oldSize, size_t newSize) {
// If size is null, erase it and get null_pointer
if (newSize == 0) {
free(previous);
return NULL;
}
// reallocate the data into a new size
// is Oldsize is zero :: malloc(data, newSize)
return realloc(previous, newSize);
}

Append function for C with dynamic memory allocation

Following this question, I'm trying to modify the code provided in this blog post to create an append function using dynamic memory allocation. This is what I have so far:
#include <stdio.h>
#include <stdlib.h>
typedef struct intlist_ {
int size;
int* list;
} intlist;
void append(intlist* arr, int value){
realloc((*arr).list, sizeof((*arr).list) + sizeof(int));
(*arr).size = (*arr).size + 1;
(*arr).list[(*arr).size -1] = value;
}
int main() {
intlist arr;
arr.size = 4;
arr.list = malloc(arr.size * sizeof(int));
arr.list[0] = 0;
arr.list[1] = 5;
arr.list[2] = 3;
arr.list[3] = 64;
append(&arr, 12);
for (int ii = 0; ii < arr.size; ii++)
printf("%d, ", arr.list[ii]);
free(arr.list);
return 0;
}
However the result I get is wrong:
clang version 7.0.0-3~ubuntu0.18.04.1 (tags/RELEASE_700/final)
main.c:10:3: warning: ignoring return value of function declared with
'warn_unused_result' attribute [-Wunused-result]
realloc((*arr).list, sizeof((*arr).list) + sizeof(int));
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
0, 5, 3, 64, 0, 5, 3, 64, 12,
I'm using this online compiler for testing where you can also see the latest versions of the above code. I would appreciate if you could help me know where is my mistake and how I can solve it. Thanks for your support in advance.
P.S. You may a final version of the code here in this Gist.
Close, but:
sizeof((*arr).list) wont give you the size of the array. Instead it will give you the size of a int*.
realloc invalidates the original pointer, and continuing to use it is undefined behaviour. Use the returned value instead.
So change your realloc line to use the stored list size instead, and update the pointer with the return value:
(*arr).list = realloc((*arr).list, ((*arr).size + 1) * sizeof(int));
Couple of other tips:
ptr-> is the same as (*ptr). but easier to read. I suggest changing all your (*arr).size and (*arr).list to arr->size and arr->list.
realloc, like its brethren, is not guaranteed to succeed. You should check the return value for null to catch errors.
The clang warning is (as often is the case) helpful - checking the return value would have solved a couple of issues.
Wrong size allocated. sizeof((*arr).list) is the size of a pointer, not int.
Return value not used. realloc() returns the new pointer.
No NULL check
Rather than use the error prone ptr = some_alloc(sizeof(type) * n), use
ptr = some_alloc(sizeof *ptr * n)
void append(intlist *arr, int value){
int *new_ptr = realloc(arr->list, sizeof *(arr->list) * (arr->size + 1u));
if (new_ptr == NULL) {
fprintf(stderr, "Out of memory\n");
exit (EXIT_FAILURE);
}
arr->list = new_ptr;
arr->list[arr->size] = value;
arr->size++;
}

Dynamic array allocated, but cannot use it

I would love to use this code as a dynamic array. Unfortunately, I cannot figure out why the program does not use the allocated memory. Is there something wrong with the parameters of the AddToArray function, maybe?
It is possible to copy and paste this code directly into the IDE and compile, to take a look at the output. The memory seems to be allocated but not used?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
float x;
float y;
} DATA;
int AddToArray (DATA item,
DATA **the_array,
int *num_elements,
int *num_allocated)
{
if(*num_elements == *num_allocated)
{ // Are more refs required?
// Feel free to change the initial number of refs
// and the rate at which refs are allocated.
if (*num_allocated == 0)
{
*num_allocated = 3; // Start off with 3 refs
}
else
{
*num_allocated *= 2;
}// Double the number of refs allocated
// Make the reallocation transactional by using a temporary variable first
void *_tmp = realloc(*the_array, (*num_allocated * sizeof(DATA)));
// If the reallocation didn't go so well, inform the user and bail out
if (!_tmp)
{
printf("ERROR: Couldn't realloc memory!\n");
return(-1);
}
// Things are looking good so far, so let's set the
*the_array = (DATA*)_tmp;
}
(*the_array)[*num_elements] = item;
*num_elements++;
return *num_elements;
}
int main()
{
DATA *the_array = NULL;
int num_elements = 0; // To keep track of the number of elements used
int num_allocated = 0; // This is essentially how large the array is
// Some data that we can play with
float numbers1[4] = {124.3,23423.4, 23.4, 5.3};
float numbers2[4] = { 42, 33, 15, 74 };
int i;
// Populate!
for (i = 0; i < 4; i++)
{
DATA temp;
temp.x = numbers1[i];
temp.y = numbers2[i];
if (AddToArray(temp, &the_array, &num_elements, &num_allocated) == -1)
return 1; // we'll want to bail out of the program.
}
for (i = 0; i < 4; i++)
{
printf("(x:%f,y:%f)\n", the_array[i].x, the_array[i].y);
}
printf("\n%d allocated, %d used\n", num_allocated, num_elements);
// Deallocate!
free(the_array);
// All done.
return 0;
}
In your code, you need to change
*num_elements++;
to
(*num_elements)++;
because, without the explicit parenthesis, the ++ is having higher precedence over * operator. What you want is to increment the value stored in the address, not the other way around.
Check about operator precedence here.
try
(*num_elements)++;
in function
AddToArray()
The bug in your code is that the pointer is incremented, not the value.
..
(*the_array)[*num_elements] = item;
(*num_elements)++;
..
Is this some kind of programming assignment? The code can be improved in many areas here.
There are lots of good algorithms for this kind of problem that are well written and optimized, I suggest that you some research in that area.

Strange behaviour on Realloc: invalid next size [duplicate]

This question already has an answer here:
free char*: invalid next size (fast) [duplicate]
(1 answer)
Closed 8 years ago.
I know there are tons of other realloc questions and answers and I have read almost all of them, but I still couldn't manage to fix my problem.
I decided to stop trying when I accidentaly discovered a very strange behaviour of my code.
I introduced a line to try something, but although I don't use the value of newElems in main, the line changes the behaviour.
When the line is commented, the code fails at first realloc. Including the line, the first realloc works. (it still crashes on the second one).
Any ideas on what might be happening?
int main(int argc, char** argv) {
Pqueue q = pqueue_new(3);
Node a = {.name = "a"}, b = {.name = "b"},
c = {.name = "c"}, d = {.name = "d"};
push(& q, & a, 3);
// the next one is the strange line: as you can see, it doesn't modify q
// but commenting it out produces different behaviour
Pqueue_elem* newElems = realloc(q.elems, 4 * q.capacity * sizeof *newElems);
push(& q, & b, 5);
push(& q, & c, 4);
char s[5];
Node* n;
for (int i = 1; i <= 65; ++i) {
sprintf(s, "%d", i);
n = malloc(sizeof *n);
n->name = strdup(s);
push(& q, n, i);
}
Node* current = NULL;
while ((current = pop(& q))) {
printf("%s ", current->name);
}
return 0;
}
and the push function:
void push(Pqueue* q, Node* item, int priority) {
if (q->size >= q->capacity) {
if (DEBUG)
fprintf(stderr, "Reallocating bigger queue from capacity %d\n",
q->capacity);
q->capacity *= 2;
Pqueue_elem* newElems = realloc(q->elems,
q->capacity * sizeof *newElems);
check(newElems, "a bigger elems array");
q->elems = newElems;
}
// append at the end, then find its correct place and move it there
int idx = ++q->size, p;
while ((p = PARENT(idx)) && priority > q->elems[p].priority) {
q->elems[idx] = q->elems[p];
idx = p;
}
// after exiting the while, idx is at the right place for the element
q->elems[idx].data = item;
q->elems[idx].priority = priority;
}
The pqueue_new function:
Pqueue pqueue_new(unsigned int size) {
if (size < 4)
size = 4;
Pqueue* q = malloc(sizeof *q);
check(q, "a new queue.");
q->capacity = size;
q->elems = malloc(q->capacity * sizeof *(q->elems));
check(q->elems, "queue's elements");
return *q;
}
realloc will change the amount of memory that is allocated, if needed. It is also free to move the data to another place in memory if that's more efficient (avoiding memory fragmentation).
The function, then, returns a new pointer to the new location in memory where your data is hiding. You're calling realloc, and allocating (probably) four times as much memory as before, so it's very likely that that allocated memory is situated elsewhere in memory.
In your comment, you said realloc works like free + malloc. Well, in some cases it can behave similarly, however: realloc and free are different functions, that do different tasks. Both are functions that manage the dynamic memory, so yes, obviously there are similarities, and in the case of realloc, sometimes they can seem to be doing the same thing, however: As I explained here, realloc and free are fundamentally different functions
However, by not assigning the return value of realloc to q.elems, you're left with a pointer to a memory address that is no longer valid. The rest of your program can, and probably does, exhibit signs of undefined behaviour, then.
Unless you show some more code, I suspect this will take care of the problem:
//change:
Pqueue_elem* newElems = realloc(q.elems, 4 * q.capacity * sizeof *newElems);
//to
q.elems = realloc(q.elems, 4 * q.capacity * sizeof *newElems);
Or better yet, check for NULL pointers:
Pqueue_elem* newElems = realloc(q.elems, 4 * q.capacity * sizeof *newElems);
if (newElems == NULL)
exit( EXIT_FAILURE );// + fprintf(stderr, "Fatal error...");
q.elems = newElems;//<-- assign new pointer!
Looking at your pqueue_new function, I would suggest a different approach. Have it return the pointer to Pqueue. You're working with a piece of dynamic memory, treat it accordingly, and have your code reflect that all the way through:
Pqueue * pqueue_new(size_t size)
{//size_t makes more sense
if (size < 4)
size = 4;
Pqueue* q = malloc(sizeof *q);
check(q, "a new queue.");
q->capacity = size;
q->elems = malloc(q->capacity * sizeof *(q->elems));
check(q->elems, "queue's elements");
return q;
}
Alternatively, pass the function a pointer to a stack variable:
void pqueue_new(Pqueue *q, size_t size)
{
if (q == NULL)
{
fprintf(stderr, "pqueue_new does not do NULL pointers, I'm not Chuck Norris");
return;//or exit
}
if (size < 4)
size = 4;
check(q, "a new queue.");
q->capacity = size;
q->elems = malloc(q->capacity * sizeof *(q->elems));
check(q->elems, "queue's elements");
}
//call like so:
int main ( void )
{
Pqueue q;
pqueue_new(&q, 3);
}
Those would be the more common approaches.
Thank you all for the suggestions! I wouldn't have solved it without them,
The strange behaviour was caused by an off by one error. I was reallocating the queue only when q->size >= q->capacity, but since q was indexed from 0, it meant that before realloc I was writing in a forbidden location (q->elems[q->size]), which messed everything up.

Resources