繁体   English   中英

当所有值都有效时如何终止可变长度数组?

[英]How to terminate variable length array when all values are valid?

我将一组单精度浮点值传递给 C 中的 function。 function 不知道数组的大小,我想保持这种状态,主要是因为虽然底层数组当然是固定长度的,但我不会总是完全填充它,所以我需要无论如何都能找到终点。 对于字符串,您使用空终止符,但在此实现中,所有可能的值都可能有效。 我能做的最好的事情是像“代码字”那样按顺序使用多个值来标记结尾,比如 ASCII 'STOP'? 这就留下了在有效数据数组中巧合地拥有该代码字的可能性......

你会看到数组/大小对在 C 中传递了很多,这确实是可靠地做到这一点的唯一方法。 即使是 NUL 终止的 C 字符串,通常也会发送一个长度参数,以确保您不会无意中离开数组的末尾并进入其他 memory。

这种方法还允许您使用子字符串或数组的子集,而不是致力于使用整个事物,即您基本上试图解决的问题。 拥有终结者既是福也是祸,任何曾尝试与有害的缓冲区溢出错误作斗争的人都可以证明这一点。

在您的情况下, function 签名应如下所示:

void process(float* v, size_t n)

其中v是要处理的浮点值数组, n是要使用的浮点数。 n应小于或等于v数组中的许多有效条目。

如果你经常传递这种东西,你甚至可以将它封装在一个定义数据和大小的简单结构中。 然后,您可以使用一些简单的分配器/填充器工具。

例如:

struct float_array {
  float* values;
  size_t size;
};

然后您可以在其中定义如下内容:

struct float_array* make_float_array(size_t n);
void free_float_array(struct float_array* f);

您不需要传递数组最大长度,只需传递当前用于此调用的长度以及指针即可。

您可以通过这种方式使用 NAN,假设这不是您的数据集的有效值:

#include <math.h>

float average(float *array)
{
    float sum = 0.0; // Declare this as double for better precision
    size_t index = 0;

    // x == NAN will return false for all x including NAN, so we need
    // the function isnan()
    while(! isnan(array[index])) 
        sum += array[index++];
    return sum/index;
}

由于您可能希望对许多功能执行此操作,因此我建议编写 function 来计算长度:

size_t farray_length(float *array)
{
    size_t len = 0;
    while(! isnan(array[len])) len++;
    return len;
}

但是在 C 中解决这些问题的通常方法是将尺寸作为单独的参数发送。

float average(float *array, size_t size) 
{
    float sum = 0.0;
    for(size_t i=0; i<size; i++)
        sum += array[i];
    return sum/size;
}

第三种方法(例如,如果您使用不希望用户直接弄乱的对象编写库时可能很有用)是声明一个结构。

struct float_array {
    float *array;
    size_t size;
}

float average(float_array array) {
    ...

对于字符串,您使用空终止符,但在此实现中,所有可能的值都可能有效。

如果所有值都有效,则无法实现标记值。 就这么简单(这就是为什么EOF是一个溢出char类型的 integer 值)。

function 不知道数组的大小,我想保持这种状态......

假设NaN是无效值,您可以使用isnan()来测试标记值。

但是, NaN是否是有效值...

无论如何,我需要能够找到结局。

剩下的唯一选择是实际将数组长度与数组一起传递。

如果您不能将数组长度作为单独的参数添加,您可以(可能)将数组的长度存储为第一个成员 - 使用结构(推荐)或使用类型双关语(不要在家里尝试这个,除非你知道你在做什么)。

IE

typedef struct float_array_s {
  unsigned int len;
  float f[];
};

static unsigned int float_array_len(float_array_s * arr) { return arr->len; }
static float float_array_index(float_array_s * arr, unsigned int index) { return arr->f[index]; }

如果您可以简单地将有效数组长度的长度与数组一起传递,那么实际上没有理由使用计算周期。

编辑(类型双关语)

我强烈建议避免这种方法,因为类型长度可能会导致难以检测到错误。 然而...

通过使用相同的字节(内存)来存储 integer,可以将数组的长度存储在第一个float成员中。

请注意,如果unsigned intfloat长(它可能是这样,即使它们通常具有相同的字节大小),这可能会崩溃(或者最糟糕的是,静默失败)。

IE

#include "math.h"
#include "stdint.h"
#include "stdio.h"

/* Returns the member at `index`. */
static float float_array_index_get(float *arr, unsigned int index) {
  return arr[index + 1];
}
/* Sets the member at `index` to `val. */
static void float_array_index_set(float *arr, unsigned int index, float val) {
  arr[index + 1] = val;
}
/* Returns the array's length. */
static unsigned int float_array_length_get(float *arr) {
  if (sizeof(unsigned int) > sizeof(float)) {
    fprintf(
        stderr,
        "ERROR: (%s:%d) type size overflow, code won't work on this system\n",
        __FILE__, __LINE__);
  }
  union {
    float f;
    unsigned int i;
  } pn;
  pn.f = arr[0];
  return pn.i;
}
/* Sets the array's length. */
static void float_array_length_set(float *arr, unsigned int len) {
  if (sizeof(unsigned int) > sizeof(float)) {
    fprintf(
        stderr,
        "ERROR: (%s:%d) type size overflow, code won't work on this system\n",
        __FILE__, __LINE__);
  }
  union {
    float f;
    unsigned int i;
  } pn;
  pn.i = len;
  arr[0] = pn.f;
}
/* Pushes a member to the array, increasing it's length. */
static void float_array_index_push(float *arr, float val) {
  unsigned int len = float_array_length_get(arr);
  float_array_index_set(arr, len, val);
  float_array_length_set(arr, len + 1);
}
/* Pops a member from the array...
 * ... returning nan if the member was nan or if the array is empty.
 */
static float float_array_index_pop(float *arr) {
  unsigned int len = float_array_length_get(arr);
  if (!len)
    return nan("");
  float_array_length_set(arr, len);
  return float_array_index_get(arr, len);
}

附言

我希望你会坚持使用简单的func(float * arr, size_t len) ,因为你看到了为了避免传递数组的长度而需要多少额外的代码。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM