2

I'm having some troubles with pointers.

This is their declaration (in main):

int *dot_positions = (int *)malloc(sizeof(int));
char *str = (char *)malloc((MAX_N + 1) * sizeof(char));

Where MAX_N is 100, and is the limit of the string. dot_positions[0] = -1;

I add a value to the first position of 'dot_position', then, in runtime, I call the following function in order to add other values.

int add_dot_to_array(int *array, int position, int array_len) {
    array = (int *)realloc(array, array_len + 1);
    array[array_len] = position;
    return array_len + 1;
}

At the end of the main(), I free the pointers:

free(str); 
free(dot_positions); 

But this causes the crash of my program. I'm using Orwell Dev-C++ with Mingw on a Windows x64 machine. I'm also sure that those pointer are not NULL. What's wrong? Thanks in advance!

Eimantas
  • 48,927
  • 17
  • 132
  • 168
Gnufabio
  • 1,505
  • 4
  • 16
  • 26
  • In add_dot_to_array, you're passing a pointer by value - so the function has its own local pointer (that points to the same array as the calling pointer). After calling realloc the local pointer is updated, but not the original pointer at the call site. – Duncan Smith Oct 25 '13 at 11:39
  • In C, it is not helpful, and can be harmful, to cast the result of `malloc()`. – Pascal Cuoq Oct 25 '13 at 11:47

4 Answers4

6

You're losing the address realloc() returns, since you're not re-setting the pointer in the caller's environment. This causes that pointer (from the original malloc()) to go stale, and freeing it crashes.

To fix this, make it add_dot_to_array(int **array, int position, int array_len) so you can change the caller's pointer. Also make sure you don't realloc() on each addition, as that will kill performance.

Also, don't cast the return value of malloc() in C, and don't "scale" string allocations by sizeof (char).

Community
  • 1
  • 1
unwind
  • 391,730
  • 64
  • 469
  • 606
1

In add_dot_to_array, you're passing a pointer by value - so the function has its own local pointer (that points to the same array as the calling pointer). After calling realloc the local pointer is updated, but not the original pointer at the call site.

Try passing a pointer to a pointer (eg **, so that the original pointer gets updated too).

int add_dot_to_array(int **array, int position, int array_len) {

and call like:

add_dot_to_array(&dot_positions, ...
Duncan Smith
  • 530
  • 2
  • 10
0

As unwind says,

int add_dot_to_array(int *array, int position, int array_len) {
    array = (int *)realloc(array, array_len + 1);
    array[array_len] = position;
    return array_len + 1;
}

works wrong - and does so in several ways.

  1. You don't return the new array to the caller.
  2. You don't check whether realloc() is successful.

Better:

int add_dot_to_array(int ** parray, int position, int * array_len) {
    int * new_array = realloc(*parray, (array_len + 1) * sizeof(*new_array)); // correct size!
    if (!new_array) return -1;
    *parray = new_array;
    new_array[(*array_len)++] = position;
    return 0;
}

which is called with

int result = add_dot_to_array(&my_pointer, pos, &my_saved_length);

and a proper result checking.

Note that it is not optimal to resize the buffer for every single element added.

Better way: maintain an alloced_size and a used_size. The used_size is incremented on every addition, and only if it reaches the alloced_size, the realloc() happens. In this case, it is advisable to realloc more than only one additional element.

glglgl
  • 89,107
  • 13
  • 149
  • 217
  • Shouldn't it be: *new_array[(*array_len)++] = position? – Gnufabio Oct 25 '13 at 12:04
  • 1
    @Gnufabio No. `*newarray` dereferences the pointer and makes it a "sole" integer. With bearing in mind that `*newarray` and `newarray[0]` are the same, as well as `*(newarray + x)` and `newarray[x]`, it is as I wrote in the code above. However, `(*parray)[(*array_len)++]` would be an alternative. – glglgl Oct 25 '13 at 12:47
-1

For retaining the new address do this

int add_dot_to_array(int ** array, int position, int array_len) 
{
    *array = (int *)realloc(*array, array_len + 1);
    *array[array_len] = position;
    return array_len + 1;
}

//For calling the function 
add_dot_to_array(&dot_positions,1,1);
kunal
  • 956
  • 9
  • 16
  • 1
    In C casting `malloc/calloc/realloc` is not necessary nor recommended: : http://stackoverflow.com/a/605858/694576 – alk Oct 25 '13 at 12:08
  • 1
    It should be `(*array)[array_len] = ...`. – alk Oct 25 '13 at 12:14
  • It will at least not work as intended, as the `[]` operator binds tighter than the `*`. – alk Oct 25 '13 at 14:11