让我们想到一个二维数组;看起来像这样:
[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。
感谢您的帮助!
注意:我不需要任何其他方法来解决问题,只是想知道是否有关键字或短语来帮我解决问题。
答案 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)
让我说,没有价值意味着:“未定义的值,我想知道”,如果你没有初始化它,那就是未知值。