统计信息的动态输入

时间:2013-10-11 15:00:04

标签: c bash

是否存在类似于我在bash中编写的此实现的等效解决方案?通常情况下,我总是这样处理动态分配:

(我喜欢第二个实现,因为它很灵活,我不需要确切知道我需要多少输入,我可以按原样输入它们。我怎样才能在C中实现类似的方法?

C实施:

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实施:

data_set=()
while IFS= read -r -p 'Enter statistical data (empty line to quit):' input; do
  [[ $input ]] || break
  data_set+=("$input")
done

3 个答案:

答案 0 :(得分:4)

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

以下内容虽然看起来很糟糕,但实际上通常非常有效(取决于你的C库的realloc实现,但它是GNU代码中常见的习惯用法,因此realloc实现是通常很适应它):

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很可能会为您做到这一点。

答案 1 :(得分:3)

scanf("%lf", &data_set[i]);的问题在于scanf()以静默方式跳过前导空格,包括空白行。

由于您希望在空行上终止,显而易见的解决方案似乎是使用fgets()getline()来读取一行,然后使用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()strlen()。)

答案 2 :(得分: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;