选择一个元素数组而不是一个对象的原因是什么?
Reason for choosing an array of one element instead of one object?
我想知道是否有理由使用由一个元素对象组成的数组,而不是只使用一个对象。
喜欢,f.e。
int a[1] = {10};
而不仅仅是
int a = 10;
当然这两种情况在后面的代码中访问10
的值的上下文是有很大区别的,通过使用a
:
- 当
a
声明为数组时,如
int a[1] = {10};
a
衰减为指向 a
数组的第一个元素对象的指针,因此 a
计算为类型 int*
,当 a
后面程序会用到。
- 当
a
声明为某个对象的标识符时,如
int a = 10;
a
属于 int
.
类型
如果我们想将 10
的值传递给一个函数,我们必须注意这一点并且 必须 区分这两种用法。
但这并没有回答我为什么使用一种方式而不是另一种方式的问题。
- C and/or C++ 中是否有任何地方需要一个数组而不是一个对象?
- 内存中分配的大小是否存在物理差异?
- C 和 C++ 在这方面有什么不同吗?
- 是否有理由选择一个元素数组而不是一个对象数组?
使用 C 和 C++ 标记的原因:我使用两种语言标记对其进行标记,因为这两种语句在 C 和 C++ 中均有效,而在实际情况下,我不知道两种语言之间有什么区别.如有差异,敬请谅解。
感谢您的帮助。
您不应声明由一个对象组成的数组。如果您需要单个变量,则将其声明为这样。但是要回答你的问题,你会想写这样的东西:
int a[1];
可能是为了方便使用以指针作为参数的函数。以函数 memset()
声明为:
为例
void * memset (void *ptr, int value, size_t num );
如果您声明了一个变量并想在其上使用 memset()
,您必须将其命名为:
int a;
memset(&a, val, sizeof(int));
而如果您将 a
声明为 int a[1]
,那么您会称它为:
memset(a, val, sizeof(int));
然而,前者用于做一些奇怪或不寻常的事情!
Are there any places in C and/or C++, where an array is needed instead of just one object?
我想你大多会遇到一个 C 风格的数组,其中一个对象作为一个对象上的递归函数的最终情况。如果您有一个以类似 C 的方式接受数组的函数 (f(int* array, int length)
),您可以使用它仅将函数应用于一个输入,而无需提供另一个重载。但是你可以用 int a = 42; f(&a, 1);
.
做同样的事情
Is there are physical difference in the size of the allocation in memory?
没有。 int a[1] = {42}
和 int a = 42
对堆栈执行完全相同的操作。
Do C and C++ differ in this context?
没有。
Why do I use an array of one element instead of just one object?
编译时大小为 1 的数组(就像您在上面所做的那样)可能很少使用。有区别
int a[1] = {42};
// and
int b = 42;
int *a = &b;
因为数组不是指针,而只是衰减到一个。但是 使用 它们的差别很小。使用它们的最显着区别(thx @Scheff)应该是您可以在 int a[1]
上使用 std::begin(a)
和 std::end(a)
,但不能在 int *a
上使用。这只是 C++ 中的一个区别。请注意,一旦数组衰减为指针,它就会消失。然后分别用 a
和 a+1
替换它们。
我可以想象,如果想在堆栈上初始化一个对象并直接有一个指向它的指针(而不是真正使用该值本身),那会做 int a[1] = {42};
,因为它有点更短。但我自己从未见过,我实际上会认为这是糟糕的风格。我认为这在 C++ 代码中并不常见,因为原始指针本身并不常见。
我其实更经常看到长度为0的数组,用法见here。由于那些 在旧版本的 C 中在技术上似乎是非法的,在 C 中是无效的(thx for the comments),可以使用长度为 1 的数组来合法。但据我所知,大多数编译器几乎永远都实现了 0 长度数组,因此大多数人可能会忽略它并使用 0 长度数组。
没有理由使用 int a[1];
而不是 int a;
。在需要时使用 &a
将指针传递给它。如果您编写它,其他人会对 int a[1];
感到非常困惑 - 它看起来像一个错误。
那么您可能会问为什么在语言中甚至需要它?
这很简单。假设您想要一个大小为 N
的固定数组,例如 int a[N];
而您不知道 N
的值。这可以是宏、constexpr 计算的结果或模板的参数。因此 int a[1]
需要支持才能工作。
Are there any places in C and/or C++, where an array is needed instead of just one object?
Why do I use an array of one element instead of just one object?
有许多函数可以处理数组,它们接受一个指针参数。但是,正如 machine_1 已经指出的那样,您可以轻松获取指向常规 object 的指针并将其传递给函数。
但在某些情况下它确实有所作为。在 C++ 中,如果您想使用 range-for 来迭代多个 object,您可以这样写:
int a[1] = {42};
for (auto &value: a)
...
但是你不能写:
int a = 42;
for (auto &value: a)
...
上面的例子本身看起来很傻,但是当你使用模板定义泛型函数时,它就会成为一个真正的问题。所以有时候你想在长度为 1 的数组中存储一个值,只是为了更容易使用这些函数。
在C99及以后的版本中,但在C++中不行,你也可以使用flexible array members。这些成员像数组一样工作,但它们不占用 space,就好像它们的长度为零一样。考虑有一个带有 header 和可变数据量的网络数据包。表示数据包的结构可能如下所示:
struct packet {
address_t source;
address_t destination;
size_t length;
char data[]; // flexible array member
};
可以像这样为这样的结构分配内存:
size_t data_length;
...
struct packet *pkt = malloc(sizeof(*pkt) + data_length);
然后可以像这样读写数据部分:
for (size_t i = 0; i < data_length; i++)
pkt->data[i] = ...;
这里不需要 data[]
数组,因为您也可以通过 ((char *)pkt + sizeof(*pkt))[i]
之类的方式访问数据,在结构末尾使用数组成员可以编写更多内容紧凑、可读且安全的代码。
可以使用长度为 1 的数组来完成 similar trick in C++。
Is there are physical difference in the size of the allocation in memory?
没有
Do C and C++ differ in this context?
没有
有时为常见情况编写的函数意味着采用数组,例如在 C 中,您可能有类似的东西:
#define CULL_OBJECTS(objs) {\
for(int i = 0; i < sizeof(objs)/sizeof(objs[0]); ++i)\
{\
++culled_objects;\
cull_subobjects(objs[i]);\
}\
或者在 C++ 中:
template<typename T>
void CullObjects(T& objs)
{
for(int i = 0; i < sizeof(objs)/sizeof(objs[0]); ++i)
{
++culled_objects;
cull_subobjects(objs[i]);
}
}
可以通过传递 Obj objArr[1000]
或 Obj obj[1]
来调用。
在我看来,为一个对象声明一个数组是没有意义的。我强烈建议使用基本的:a = 10 ;
我想知道是否有理由使用由一个元素对象组成的数组,而不是只使用一个对象。
喜欢,f.e。
int a[1] = {10};
而不仅仅是
int a = 10;
当然这两种情况在后面的代码中访问10
的值的上下文是有很大区别的,通过使用a
:
- 当
a
声明为数组时,如
int a[1] = {10};
a
衰减为指向 a
数组的第一个元素对象的指针,因此 a
计算为类型 int*
,当 a
后面程序会用到。
- 当
a
声明为某个对象的标识符时,如
int a = 10;
a
属于 int
.
如果我们想将 10
的值传递给一个函数,我们必须注意这一点并且 必须 区分这两种用法。
但这并没有回答我为什么使用一种方式而不是另一种方式的问题。
- C and/or C++ 中是否有任何地方需要一个数组而不是一个对象?
- 内存中分配的大小是否存在物理差异?
- C 和 C++ 在这方面有什么不同吗?
- 是否有理由选择一个元素数组而不是一个对象数组?
使用 C 和 C++ 标记的原因:我使用两种语言标记对其进行标记,因为这两种语句在 C 和 C++ 中均有效,而在实际情况下,我不知道两种语言之间有什么区别.如有差异,敬请谅解。
感谢您的帮助。
您不应声明由一个对象组成的数组。如果您需要单个变量,则将其声明为这样。但是要回答你的问题,你会想写这样的东西:
int a[1];
可能是为了方便使用以指针作为参数的函数。以函数 memset()
声明为:
void * memset (void *ptr, int value, size_t num );
如果您声明了一个变量并想在其上使用 memset()
,您必须将其命名为:
int a;
memset(&a, val, sizeof(int));
而如果您将 a
声明为 int a[1]
,那么您会称它为:
memset(a, val, sizeof(int));
然而,前者用于做一些奇怪或不寻常的事情!
Are there any places in C and/or C++, where an array is needed instead of just one object?
我想你大多会遇到一个 C 风格的数组,其中一个对象作为一个对象上的递归函数的最终情况。如果您有一个以类似 C 的方式接受数组的函数 (f(int* array, int length)
),您可以使用它仅将函数应用于一个输入,而无需提供另一个重载。但是你可以用 int a = 42; f(&a, 1);
.
Is there are physical difference in the size of the allocation in memory?
没有。 int a[1] = {42}
和 int a = 42
对堆栈执行完全相同的操作。
Do C and C++ differ in this context?
没有。
Why do I use an array of one element instead of just one object?
编译时大小为 1 的数组(就像您在上面所做的那样)可能很少使用。有区别
int a[1] = {42};
// and
int b = 42;
int *a = &b;
因为数组不是指针,而只是衰减到一个。但是 使用 它们的差别很小。使用它们的最显着区别(thx @Scheff)应该是您可以在 int a[1]
上使用 std::begin(a)
和 std::end(a)
,但不能在 int *a
上使用。这只是 C++ 中的一个区别。请注意,一旦数组衰减为指针,它就会消失。然后分别用 a
和 a+1
替换它们。
我可以想象,如果想在堆栈上初始化一个对象并直接有一个指向它的指针(而不是真正使用该值本身),那会做 int a[1] = {42};
,因为它有点更短。但我自己从未见过,我实际上会认为这是糟糕的风格。我认为这在 C++ 代码中并不常见,因为原始指针本身并不常见。
我其实更经常看到长度为0的数组,用法见here。由于那些 在旧版本的 C 中在技术上似乎是非法的,在 C 中是无效的(thx for the comments),可以使用长度为 1 的数组来合法。但据我所知,大多数编译器几乎永远都实现了 0 长度数组,因此大多数人可能会忽略它并使用 0 长度数组。
没有理由使用 int a[1];
而不是 int a;
。在需要时使用 &a
将指针传递给它。如果您编写它,其他人会对 int a[1];
感到非常困惑 - 它看起来像一个错误。
那么您可能会问为什么在语言中甚至需要它?
这很简单。假设您想要一个大小为 N
的固定数组,例如 int a[N];
而您不知道 N
的值。这可以是宏、constexpr 计算的结果或模板的参数。因此 int a[1]
需要支持才能工作。
Are there any places in C and/or C++, where an array is needed instead of just one object?
Why do I use an array of one element instead of just one object?
有许多函数可以处理数组,它们接受一个指针参数。但是,正如 machine_1 已经指出的那样,您可以轻松获取指向常规 object 的指针并将其传递给函数。
但在某些情况下它确实有所作为。在 C++ 中,如果您想使用 range-for 来迭代多个 object,您可以这样写:
int a[1] = {42};
for (auto &value: a)
...
但是你不能写:
int a = 42;
for (auto &value: a)
...
上面的例子本身看起来很傻,但是当你使用模板定义泛型函数时,它就会成为一个真正的问题。所以有时候你想在长度为 1 的数组中存储一个值,只是为了更容易使用这些函数。
在C99及以后的版本中,但在C++中不行,你也可以使用flexible array members。这些成员像数组一样工作,但它们不占用 space,就好像它们的长度为零一样。考虑有一个带有 header 和可变数据量的网络数据包。表示数据包的结构可能如下所示:
struct packet {
address_t source;
address_t destination;
size_t length;
char data[]; // flexible array member
};
可以像这样为这样的结构分配内存:
size_t data_length;
...
struct packet *pkt = malloc(sizeof(*pkt) + data_length);
然后可以像这样读写数据部分:
for (size_t i = 0; i < data_length; i++)
pkt->data[i] = ...;
这里不需要 data[]
数组,因为您也可以通过 ((char *)pkt + sizeof(*pkt))[i]
之类的方式访问数据,在结构末尾使用数组成员可以编写更多内容紧凑、可读且安全的代码。
可以使用长度为 1 的数组来完成 similar trick in C++。
Is there are physical difference in the size of the allocation in memory?
没有
Do C and C++ differ in this context?
没有
有时为常见情况编写的函数意味着采用数组,例如在 C 中,您可能有类似的东西:
#define CULL_OBJECTS(objs) {\
for(int i = 0; i < sizeof(objs)/sizeof(objs[0]); ++i)\
{\
++culled_objects;\
cull_subobjects(objs[i]);\
}\
或者在 C++ 中:
template<typename T>
void CullObjects(T& objs)
{
for(int i = 0; i < sizeof(objs)/sizeof(objs[0]); ++i)
{
++culled_objects;
cull_subobjects(objs[i]);
}
}
可以通过传递 Obj objArr[1000]
或 Obj obj[1]
来调用。
在我看来,为一个对象声明一个数组是没有意义的。我强烈建议使用基本的:a = 10 ;