4

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
4

3 回答 3

4

最简单的解决方案是使用 C++。但这不是你要问的,所以我把它留在那里。

以下内容,虽然乍一看很糟糕,但实际上通常非常有效(取决于您的 C 库reallocrealloc.

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;
}

如果您对这种方法不满意,您可以滚动您自己的指数 realloc,您可以在其中跟踪分配的向量的大小,如果即将超出,则将其加倍。不过,那是更多的代码,而且很可能realloc会为您做到这一点。

于 2013-10-11T15:07:45.807 回答
3

问题scanf("%lf", &data_set[i]);在于它会scanf()默默地跳过前导空格,包括空白行。

由于您想在空行上终止,因此显而易见的解决方案似乎是使用fgets()orgetline()读取一行,然后sscanf()在该行不为空时使用 读取数据。

因此:

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...
}

请注意,检查每个 I/O 功能。如果您在其他空行上输入一个或两个空格,它们将进入“格式错误”代码。如果您愿意,可以使“空白行”的测试更加敏感(例如,考虑使用strspn()and strlen())。

于 2013-10-11T15:14:02.947 回答
1

根据需要重新分配。

double* data_set = NULL;
int size = 0;
int i = 0;
for(;;) {
    printf("Enter statistical data: ");
    double d;
    // See @Jonathan Leffler for good idea on using blank line to terminate input
    if (1 == scanf("%lf", &d)) {
      break;
    }
    data_set = realloc(data_set, ++size * sizeof(double));
    if (data_set == NULL) handle_error();
    data_set[size-1] = d;
}
*data_size = size;
return data_set; 
于 2013-10-11T15:12:34.007 回答