Is there an equivalent solution similar to this implementation I've written in bash? Normally, I've always handled dynamic allocation like so:
(I like the second implementation because it's flexible and I don't need to know exactly how many inputs I need, I can input them as is. How can I accomplish a similar approach in C?
C Implementation:
double* get_data(int* data_size)
{
double* data_set = NULL;
int size = get_size();
int i;
*data_size = size;
data_set = malloc(size * sizeof(double));
for(i = 0; i < size; i++)
{
printf("Enter statistical data: ");
scanf("%lf", &data_set[i]);
}
return data_set;
}
Bash Implementation:
data_set=()
while IFS= read -r -p 'Enter statistical data (empty line to quit):' input; do
[[ $input ]] || break
data_set+=("$input")
done
The simplest solution is to use C++. But that's not what you're asking, so I'll leave it there.
The following, although it looks awful at first glance, is actually usually pretty efficient (depending on your C library's implementation of realloc
, but it's a common idiom in GNU code so the realloc
implementation is usually well-adapted to it):
double* get_data(size_t *size_p) {
size_t n = 0;
double* data = NULL;
double val;
while (get_a_datum(&val)) {
double* newdata = realloc(data, (n + 1) * sizeof *data);
if (newdata == NULL) { free(data); report(error); }
data = newdata;
data[n++] = val;
}
if (size_p) *size_p = n;
return data;
}
If you're not happy with that approach, you can roll your own exponential realloc, where you track the size of the allocated vector and, if it is about to be exceeded, double it. That's more code, though, and it's highly likely that realloc
will do precisely that for you.
The trouble with scanf("%lf", &data_set[i]);
is that scanf()
skips leading white space, including blank lines, silently.
Since you want to terminate on an empty line, the obvious solution seems to be to use fgets()
or getline()
to read a line and then use sscanf()
to read the data when the line is not empty.
Hence:
char line[4096];
while ((fgets(line, sizeof(line), stdin) != 0)
{
if (line[0] == '\n')
break;
if (sscanf(line, "%lf", &data_set[i++]) != 1)
...format error...
}
Note that each I/O function is checked. If you enter a blank or two on an otherwise empty line, they'll go into the 'format error' code. You can make the test for 'blank line' more sensitive if you wish (consider using strspn()
and strlen()
, for example).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With