更改数组的未定义值

时间:2013-08-11 01:19:03

标签: c arrays element undefined

让我们想到一个二维数组;看起来像这样:

[1] [2] [3] [4] [未定义] [未定义] [未定义]

[5] [6] [7] [8] [未定义] [未定义] [未定义]

[9] [0] [1] [2] [未定义] [未定义] [未定义]

我可以用这样的for循环更改未定义的值吗?

for (i=0;i<7;i++)
{    for (j=0;j<3;j++)

    {
    if (Arr[i][j]=="the value of undefined, which I wonder")
    Arr[i][j]=0;
    }
}

我记得在C#上使用NULL关键字,但这显然不适用于C。

感谢您的帮助!

注意:我不需要任何其他方法来解决问题,只是想知道是否有关键字或短语来帮我解决问题。

4 个答案:

答案 0 :(得分:2)

如果数组的元素是浮点类型,则可以使用NaN来指示它们未设置为数字(在大多数C实现中;这不是在所有C实现中,但是很常见)。您必须初始化数组以包​​含NaN;它们(通常)默认不会放在那里。

如果数组的元素有另一种类型,则必须选择一个值来指定该元素尚未分配,这可能会导致使用该数组的问题。

#include <math.h>之后,您可以使用以下命令测试C实现是否支持NaN:

#if defined NAN
    // NaNs are supported.
#else
    #error "This program requires support for NaNs."
#endif

您可以使用以下代码测试对象x是否为NaN

if (isnan(x)) …

您可以使用以下命令将对象设置为NaN:

x = NAN;

答案 1 :(得分:1)

除了Eric的答案之外,还有其他几种方法可以处理C中的这种情况,带来不同程度的额外包袱和精神上的悲伤。也就是说:这些是表达表示域中未定义或未设置值的值的方法。我们不是在谈论实际的不确定值,如果你在没有初始化的情况下分配数组然后访问它,你通常会从C实现中获得这些值。

方法1: NaN(非数字)值,如Eric的解决方案中所示。适用于您操作浮动的特定情况, NaN不可能在您的域中用作合法的定义的值。如果您正在存储字符,则空字符'\0'也可能是未定义的合理选择。

方法2:指针。 C确实有NULL,就像C#一样。但是,它仅适用于您操作指针类型的值。所以,而不是:

int a[3];
a[0] = 1;
a[1] = 2;
a[2] = 0; /* blech -- I really want this to mean 'undefined',
             but what if I really needed 0 as a numeric value
             in my array? In that case, this doesn't work! */

我可以这样做:

#include <stdlib.h>

int* integer_new(int i) {
    int* result = (int*) malloc(sizeof(int));
    *result = i;
    return result;
}

int* a[3];
a[0] = integer_new(1);
a[1] = integer_new(2);
a[2] = NULL;

现在您有一个可以轻松测试并与普通整数值区分开的值。理论上,这是C#代码幕后发生的事情,我相信。但是你可以很快看到它们的缺点:你现在拥有一堆堆分配的对象,你现在必须管理它们,并在完成它们时适当地释放它们。

如果你正在处理类似 flyweight 模式的事情,那么这里有一个改进,其中这些值是堆栈分配的或在其他地方预先分配的。在这种情况下,您可以只获取这些值的地址,将它们粘贴在数组中,而不必自己堆分配它们。但是你还是要面对额外的间接层。

方法3:可能的模式(我从Haskell窃取)。像这样:

typedef struct maybe_int_ {
    int has_value; /* 1 if yes, 0 if no */
    int value;
} maybe_int;

maybe_int maybe_nothing(void) {
    maybe_int result;
    result.has_value = 0;
    return result;
}

maybe_int maybe_just(int i) {
    maybe_int result;
    result.has_value = 1;
    result.value = i;
    return result;
}

maybe_int a[3];
a[0] = maybe_just(1);
a[1] = maybe_just(2);
a[2] = maybe_nothing();

这对堆栈来说效果更好,所以它通常比指针方式有所改进,但你仍然需要处理更多的记账。

方法4:联盟。与方法3类似,但如果您的数组中有多种值,则可以执行类似的操作:

typedef enum {
    BOXED_TYPE_UNDEFINED,
    BOXED_TYPE_INT,
    BOXED_TYPE_FLOAT
} boxed_type;

typedef struct boxed_ {
    boxed_type type;
    union {
        int int_value;
        float float_value;
    } u;
} boxed;

boxed boxed_undefined(void) {
    boxed result;
    result.type = BOXED_TYPE_UNDEFINED;
    return result;
}

boxed boxed_int(int i) {
    boxed result;
    result.type = BOXED_TYPE_INT;
    result.u.int_value = i;
    return result;
}

boxed boxed_float(float f) {
    boxed result;
    result.type = BOXED_TYPE_FLOAT;
    result.u.float_value = f;
    return result;
}

boxed a[3];
a[0] = boxed_int(1);
a[1] = boxed_float(2.0f);
a[2] = boxed_undefined();

如果您已经使用了union和类型鉴别器,那么这个解决方案可能特别容易实现。

所有这些解决方案有什么共同之处? sentinel值的想法:您存储在数组中的某些值,保证不会用于您域中的任何其他值,因此您可以自由地将其解释为未定义的值。如您所见,有很多方法可以将哨兵值注入您的域名。

这是一个不涉及哨兵值的解决方案。 方法5:跳出框。

int a[3];
unsigned char adef[3];
a[0] = 1; adef[0] = 1;
a[1] = 2; adef[1] = 1;
adef[2] = 0; /* I would set a[2] = 0 here as well
                because I dislike uninitialized
                array values! */

如果您真的无法以任何允许您定义标记值的方式清除域中的值,那么只需在其他位置存储值的额外“定义”。我自己从来没有采取过这种做法,但我发现一个单独的相关数据表的一般技术确实会不时地派上用场。

答案 2 :(得分:0)

如果不将它们初始化为某个值,则C中的数组具有未定义的值;这意味着它可以是0 0 0 0 0 900000 0 0 0 0 0等。

是的,有一个未定义的值,但根据名称,它很好...未定义 - 因为没有设定值。

你可以像你一样覆盖它们。 。更好的方法是使用memset

它未被定义的原因是你只是获得了一大块内存 - 任何东西都可能在这个记忆中坐着(有价值)。

编辑:ok,除非你静态初始化数组当然。

答案 3 :(得分:0)

让我说,没有价值意味着:“未定义的值,我想知道”,如果你没有初始化它,那就是未知值。