If the user does not specify the number of values in advance, you can't allocated the array accurately in advance. You have to guess at the allocation. If that turns out to be too small, then you have to be able to reallocate the array without losing the original data.
Two tools from the Standard C Library help here: malloc and realloc(), plus a third: free() to be used when the array is no longer needed.
... declarations:
double *pvalues = NULL;
int max_values;
int values_used;
... in your init code:
max_values = 100;
pvalues = (double*) malloc(max_values * sizeof(double));
if (pvalues == NULL) { print error and die...not enough memory }
values_used = 0;
...after reading a double named new_value that needs to be stored in the array:
if (values_used >= max_values) /* if the array is full */
{
max_values = 2*max_values; /* double array size */
double *newptr = (double*) realloc(pvalues, max_values*sizeof(double));
if (newptr == NULL) { print error and die ... not enough memory }
}
pvalues = newptr;
pvalues[values_used++] = new_value;
...at the end of the program:
/* free the data buffer, if it's been allocated */
if (pvalues != NULL) free(pvalues);
That pattern: "add to the array until it fills up, then reallocate to a larger size when it fills up" is used a lot, especially in C where you have to write a lot of your own data structure handling. In C++ you have a vector<> type that does all of this, and a bit more, for you. Ditto for Java's ArrayList<>, also found in C#.
Note that no copying is necessary when using realloc(). realloc() does that for you, either by excpanding the current allocation in place, or by a new malloc() and copying the data. If a new memory block is allocated, the old is freed after copying the data.
The reason for newptr is to get into the habit of NOT overwriting the pointer you are trying to reallocate until you verify that return from realloc() is not NULL. If the reallocation fails, realloc() dos not free the old memory. In this exercise, you don't need to worry about recovery. Just print a message and return a nonzero value. If the recovery action is to not halt the program, you need to remember the original array address so you can reuse it or free it.
Everything you need should be in