1

I want to grow an array at runtime (without predining the length with a macos)

I have the following questions

  1. is it possible to do it with an array?
  2. If not shall I use a pointer to int?

I tried the following code (and expecting 012 as output) but get 000

#include <stdlib.h>
#include <stdio.h>

int main()
{
    int *arr = NULL; 
    size_t n = 0; 
    for (int i = 0; i < 3; ++i) { 
        arr = realloc(arr, (n + 1) * sizeof *arr); 
        arr[n++] = i; 
        printf("%d", *arr);
    } 
}
Chris
  • 26,361
  • 5
  • 21
  • 42
ecjb
  • 5,169
  • 12
  • 43
  • 79
  • 3
    Your `realloc` code is fine (simple but fine). You want: `printf(" %d",arr[n - 1]);` to print the _current_ element rather than [always] the first. – Craig Estey Feb 21 '23 at 21:40
  • 1
    *arr is the first element in arr – stark Feb 21 '23 at 21:41
  • 1
    ... or `printf( "%d: %d and n = %d\n", i, arr[i], n );` It helps to have a reference showing, instead of a black box. (PS: Kudos for using `realloc()` without the typical first `malloc()`. Well done!) AND... Don't forget the `free()` to be clean... `:-)` – Fe2O3 Feb 21 '23 at 21:42
  • 3
    Suggestion: calls to `realloc` aren't free. Grow your array by factors of two rather than incrementing it by one each time to minimize reallocations. – Chris Feb 21 '23 at 21:44
  • @ecjb Detail, in C an array cannot change size once it is defined. _Allocation_ size for memory to hold an array can change. – chux - Reinstate Monica Feb 21 '23 at 22:01
  • 1
    one more thing, you should check the return value of `realloc` to make sure it succeeded before trying to write to the memory (you currently hope) it gave you. – yano Feb 21 '23 at 22:06
  • 1
    @yano Worthy of an "answer" demonstrating that the original pointer should not be overwritten by the function call??? – Fe2O3 Feb 21 '23 at 22:19
  • 1
    @Chris: Using a growth factor of 1.5 instead of 2 may actually be better. See this question for further information: [What is the ideal growth rate for a dynamically allocated array?](https://stackoverflow.com/q/1100311/12149471) – Andreas Wenzel Feb 21 '23 at 22:27
  • 1
    @Fe2O3 [already answered](https://stackoverflow.com/questions/21006707/proper-usage-of-realloc), but perhaps this could be integrated into the answer below. – yano Feb 21 '23 at 22:30

2 Answers2

3

OP's mostly has it.

It is just printing the first element each time.

    // printf("%d", *arr);
    printf("%d", arr[n-1]);

is it possible to do it with an array?

No. In C an array cannot change size once it is defined.

The memory size allocated and referenced by a pointer can change though.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
1

The way you reallocate the array is fine, albeit inefficient. The reason you do not get the expected output is you output the first element 3 times.

It is recommended to allocate arrays in a single shot if you know the final length in advance, in other cases, where large arrays need to be reallocated on the fly, it is recommended to reallocate using increasing sizes following a geometric progression:

Here is an example using the golden ratio:

#include <stdlib.h>
#include <stdio.h>

int main() {
    char *arr = NULL; 
    size_t size = 0;
    size_t pos = 0;
    int c;
    while ((c = getchar()) != EOF) {
        if (pos + 1 > size) {
            // increase size by a ratio of 1.625
            // with an offset to handle the initial case without a test
            size_t new_size = size + (size >> 1) + (size >> 3) + 32;
            char *new_arr = realloc(arr, sizeof(*arr) * new_size);
            if (new_arr == NULL) {
                fprintf(stderr, "cannot reallocate array for %zu bytes\n", new_size);
                free(arr);
                return 1;
            }
            arr = new_arr;
            size = new_size;
        }
        arr[pos++] = c;
    }
    if (arr == NULL) {
        fprintf(stderr, "empty file\n");
        return 1;
    }
    arr[pos] = '\0';
    char *new_arr = realloc(arr, sizeof(*arr) * (pos + 1));
    if (new_arr != NULL) {
        arr = new_arr;
        size = pos + 1;
    }
    /* more code to handle full buffer */
    free(arr);
    return 0;
}
chqrlie
  • 131,814
  • 10
  • 121
  • 189
  • `size + (size >> 1) + (size >> 3)` that's fancy, i feel like to have found a gold coin. Just out of curiosity, why the number `32`. Just arbitrary? Doesn't look like to have any later implications (disregarding the fact, that it functions as initial value if `size == 0`). – Erdal Küçük Feb 22 '23 at 03:09
  • @ErdalKüçük: correct, `+ 32` is just a simple offset to handle the initial case without branches. – chqrlie Feb 22 '23 at 06:42