The problem is that you are accessing outside of the bounds of temp
because you don't specify when to stop in the loop.
For a dynamic array, when you don't know the number of elements before hand, you can use realloc
:
#include <stdio.h>
#include <stdlib.h>
void push(int **arr, size_t *size, int value)
{
int *ptr = realloc(*arr, sizeof(*ptr) * (*size + 1));
if (ptr == NULL)
{
free(*arr);
perror("push");
exit(EXIT_FAILURE);
}
ptr[*size] = value;
*size += 1;
*arr = ptr;
}
int main(void)
{
int temp[10] = {1, 2, 0, 0, 5, 6, 0, 8, 0, 0};
int *arr = NULL;
size_t size = 0;
for (size_t i = 0; i < sizeof temp / sizeof temp[0]; i++)
{
if (temp[i])
{
push(&arr, &size, temp[i]);
}
}
for (size_t i = 0; i < size; i++)
{
printf("%d\n", arr[i]);
}
free(arr);
}
Notice that even if it ilustrates the use of a growable array, this example is considered bad code, a more robust design will take care of the size and is able to manage the allocation and deallocation by itself:
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
int *data;
size_t size;
} dyn_array;
dyn_array *create_dyn_array(void)
{
dyn_array *arr = calloc(1, sizeof *arr);
if (arr == NULL)
{
perror("create_dyn_array");
exit(EXIT_FAILURE);
}
return arr;
}
void destroy_dyn_array(dyn_array *arr)
{
free(arr->data);
free(arr);
}
void push_dyn_array(dyn_array *arr, int value)
{
int *ptr = realloc(arr->data, sizeof(*ptr) * (arr->size + 1));
if (ptr == NULL)
{
destroy_dyn_array(arr);
perror("push_dyn_array");
exit(EXIT_FAILURE);
}
ptr[arr->size++] = value;
arr->data = ptr;
}
int main(void)
{
int temp[10] = {1, 2, 0, 0, 5, 6, 0, 8, 0, 0};
dyn_array *arr = create_dyn_array();
for (size_t i = 0; i < sizeof temp / sizeof temp[0]; i++)
{
if (temp[i])
{
push_dyn_array(arr, temp[i]);
}
}
for (size_t i = 0; i < arr->size; i++)
{
printf("%d\n", arr->data[i]);
}
destroy_dyn_array(arr);
}
This is better, but still not perfect because we are limited to a fixed type (int
), with some extra memory we can adapt our code to support any type (using the generic type void *
), as an optimization, the dynamic array grows by a factor of 2 instead of calling realloc
on each iteration:
#include <stdio.h>
#include <stdlib.h>
/* Begin - This API is supposed to be in a header */
typedef struct
{
void **data;
size_t room;
size_t size;
} dynarray;
dynarray *dynarray_create(void)
{
dynarray *array = calloc(1, sizeof *array);
if (array == NULL)
{
return NULL;
}
array->data = malloc(sizeof(void *));
if (array->data == NULL)
{
free(array);
return NULL;
}
array->room = 1;
return array;
}
void *dynarray_push(dynarray *array, void *data)
{
if (data == NULL)
{
return NULL;
}
if (array->size == array->room)
{
array->room *= 2;
void *ptr = realloc(array->data, array->room * sizeof(void *));
if (ptr == NULL)
{
return NULL;
}
array->data = ptr;
}
array->data[array->size++] = data;
return data;
}
void *dynarray_get(dynarray *array, size_t index)
{
return array->data[index];
}
size_t dynarray_size(dynarray *array)
{
return array->size;
}
void dynarray_destroy(dynarray *array, void (*func)(void *data))
{
if (func != NULL)
{
for (size_t i = 0; i < array->size; i++)
{
func(array->data[i]);
}
}
free(array->data);
free(array);
}
/* End API */
int main(void)
{
int temp[10] = {1, 2, 0, 0, 5, 6, 0, 8, 0, 0};
dynarray *array = dynarray_create();
if (array == NULL)
{
perror("dynarray_create");
exit(EXIT_FAILURE);
}
for (size_t i = 0; i < sizeof temp / sizeof temp[0]; i++)
{
if (temp[i])
{
if (dynarray_push(array, &temp[i]) == NULL)
{
perror("dynarray_push");
exit(EXIT_FAILURE);
}
}
}
size_t size = dynarray_size(array);
for (size_t i = 0; i < size; i++)
{
int *data = dynarray_get(array, i);
printf("%d\n", *data);
}
dynarray_destroy(array, NULL);
}