-1

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

[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

4 回答 4

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;
于 2013-08-11T01:32:16.003 回答
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# 代码幕后发生的事情。但是您很快就会看到缺点:您现在有一堆堆分配的对象,而以前没有,现在您必须管理它们,当您使用它们时适当地释放它们。

如果您正在处理诸如元模式之类的东西,其中这些值是堆栈分配的或在其他地方预分配的,则可以对此进行改进。在这种情况下,您可以只获取这些值的地址,将它们粘贴到数组中,而不必自己进行堆分配。但是您仍然必须应对额外的间接层。

方法 3: maybe 模式(我从 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();

如果您已经在使用联合加类型鉴别器,那么此解决方案可能特别容易实现。

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

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

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! */

如果您真的不能以任何允许您定义哨兵值的方式处理域中的值,那么只需将值的额外“定义性”存储在其他地方即可。我自己从来不用求助于这个,但我发现单独的相关数据表的一般技术确实有时会派上用场。

于 2013-08-11T03:53:25.347 回答
0

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

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

你可以像你正在做的那样覆盖它们。. 更好的是使用memset

它未定义的原因是您只是获得了一大块内存 - 任何东西都可能(价值明智)位于该内存中。

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

于 2013-08-11T01:21:54.803 回答
0

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

于 2013-08-11T01:23:32.847 回答