数组的大小
这个问题是关于 C++ 的,
我一直认为 C++ 中数组的名称只是一个指针,所以我认为这
int ar[10];
cout << sizeof(ar);
会给我与 sizeof(int *)
相同的结果。但它给出了 40 - 所以它是整个数组的实际大小。当数组大小由变量给出时,它也给出 40:
int n = 10;
int ar[n]
我想复制一个包含数组的类。如果它是用运算符 new 分配的,那么我应该在复制构造函数中手动复制该数组。但是恒定大小的数组又如何呢?类只包含一个指向数组的指针,还是包含整个数组?简单的 memcpy(...)
这里安全吗?
编辑: 另一个例子:
int n;
cin >> n;
int ar[n];
cout << sizeof(ar);
它打印 n*4。我在 Linux 上使用 g++。
我什至尝试了这个:
class Test {
public:
int ar[4];
};
并且
Test a, b, c;
a.ar[0] = 10;
b = a;
memcpy(&c, &a, sizeof(a));
a.ar[0] = 20;
cout << "A: " << a.ar[0] << endl;
cout << "B: " << b.ar[0] << endl;
cout << "C: " << c.ar[0] << endl;
它给出了:
A: 20
B: 10
C: 10
所以数组被存储为类的一部分,并且可以使用 memcpy 进行复制。但这安全吗?
This question is about C++
I always thought that name of an array in C++ is only a pointer, so I thought that
int ar[10];
cout << sizeof(ar);
will give me the same as sizeof(int *)
. But it gives 40 - so it is real size of whole array. It also gives 40 when array size is given by variable:
int n = 10;
int ar[n]
I want to copy a class that contains an array. If it would be allocated with operator new
then I should manualy copy this array within a copy constructor. But how about constant sized arrays? Does class contains only a pointer to an array, or does it contains whole array? Is simple memcpy(...)
safe here?
EDIT:
Another example:
int n;
cin >> n;
int ar[n];
cout << sizeof(ar);
and it prints n*4. I'm using g++ on linux.
I even tried this:
class Test {
public:
int ar[4];
};
and
Test a, b, c;
a.ar[0] = 10;
b = a;
memcpy(&c, &a, sizeof(a));
a.ar[0] = 20;
cout << "A: " << a.ar[0] << endl;
cout << "B: " << b.ar[0] << endl;
cout << "C: " << c.ar[0] << endl;
and it gives:
A: 20
B: 10
C: 10
So array is stored as a part of a class and can be copied with memcpy. But is it safe?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
数组不是指针。当/如果将数组作为参数传递给函数时,数组的名称会“衰减”为指针 - 但
sizeof
是语言中内置的运算符,而不是函数,因此sizeof(array)
只要应用于实际数组,就会生成数组的实际大小(而不是作为参数传递数组的名称,然后使用sizeof()
在传递给函数时衰减到的指针上,就复制包含数组的类而言,如果它确实是一个数组,例如:
那么您不需要执行任何操作即可复制它 - - 编译器可以/将生成一个复制构造函数来复制数组的内容如果(且仅当)您实际上有一个指针,并自己分配空间,您是否需要编写一个复制构造函数来执行“深度复制”。 “(即在新对象中分配空间,并复制指针指向的数据)。但是,您通常应该使用
std::vector
,而不是这样做,它在内部完成所有这些操作所以你不用担心。An array is not a pointer. The name of an array "decays" to a pointer when/if you pass it as a parameter to a function -- but
sizeof
is an operator built into the language, not a function, sosizeof(array)
yields the actual size of the array as long as it's applied to the actual array (as opposed to the name of the array being passed as a parameter, then usingsizeof()
on the pointer that it decayed to when it was passed to the function.As far as copying a class that contains an array, if it's really an array, like:
Then you don't need to do anything for it to be copied -- the compiler can/will generate a copy constructor that copies the contents of the array. If (and only if) you actually have a pointer, and allocate the space yourself, do you need to write a copy ctor to do a "deep copy" (i.e. allocate space in the new object, and copy the data pointed TO by the pointer). Rather than doing this, however, you should normally use an
std::vector
, which does all that internally so you don't have to worry about it.一次服用这些:
好的,例如:
好的,现在混乱开始了。在上面的示例中,数组实际上是对象的一部分。如果
int
是 4 个字节,则sizeof(Foo)
将为您提供 80。另一种方法是使用指向数组的指针,如果数组需要更改大小,这会很有用:
在这种情况下,sizeof(Bar) 是指针的大小(通常为 4 或 8 字节) ),复制对象也会复制指针。这称为“浅复制”。如果您想要一个“深层复制”,即复制将复制数组的内容而不仅仅是对象,那么您需要一个复制构造函数。
第三种替代方法是使用
vector
,正如 wheaties 所建议的:这在内部工作原理与
Bar
情况相同,并且vector
可以调整大小,但是vector
模板会为您处理深层复制,因此您不需要复制构造函数。如果您需要固定大小的数组(其大小在编译时已知),我建议使用
Foo
情况,否则建议使用Bob
情况。Bar
案例几乎只是重新发明轮子。对于
Foo
来说是安全的。如果您想要浅拷贝,对于Bar
来说是安全的。对于Bob
来说不安全。这个故事的寓意是,将变量存储在对象中就像将其存储在功能块或全局中一样:如果您指定一个数组(
[N]
而不是*
),大小最好在编译时确定,然后你就可以将存储放在那里。Taking these one at a time:
Okay, so for example:
Okay, now the confusion sets in. In the above example, the array is actually part of the object.
sizeof(Foo)
would give you 80 ifint
is 4 bytes.An alternative would be to have a pointer to an array, which is useful if the array needs to change size:
In that case,
sizeof(Bar)
is the size of a pointer (usually 4 or 8 bytes), and copying the object copies the pointer. This is called a "shallow copy". If you wanted a "deep copy", i.e. a copy would duplicate the array's contents and not just the object, then you need a copy constructor.The third alternative is to use
vector
, as wheaties recommends:This internally works the same as the
Bar
case, and thevector
can be resized, but thevector
template takes care of the deep copy for you, so you don't need a copy constructor.I'd recommend the
Foo
case if you need a fixed-size array, where the size is known at compile time, and theBob
case otherwise. TheBar
case is pretty much just reinventing the wheel.Safe for
Foo
. Safe forBar
if you want a shallow copy. Unsafe forBob
.The moral of the story is that storing a variable in an object works just like storing it in a function block or global: if you specify an array (
[N]
instead of*
), the size had better be determined at compile time, and you get the storage placed right there.实际上
ar
是一个数组,这就是sizeof()找到实际大小的原因。 C/C++ 中的数组有一个指针值(指针表达式或右值)。Actually
ar
is an array, that is why sizeof() finds the actual size. An array in C/C++ has a pointer value (pointer expression or rvalue).注释: 在标准 C (C89) 中,您应该只能使用文字或 const 来初始化数组。所以编译器不会感到困惑。
答案:如果你以“栈上方式”初始化一个数组——即不使用new或malloc。该类将封装数组的大小。数组的基数是指针,因为编译器在内部使用指针算术来解析访问运算符
[]
。如果您使用 new 或 malloc,则必须使用用于分配内存的变量作为您分配的内存大小的最终度量。您可以将 memcpy() 与数组基指针一起使用,因为无论它分配在哪里,它仍然是指向数组基内存位置的指针。
答案 2:问题编辑后
是的,使用相同类型和相同大小的常量大小的数组来执行此操作是完全安全的,但不要使用动态分配的资源执行此操作,除非您正在跟踪它们类型和尺寸。只需避免您正在采用的方法并使用容器类即可。
注意:我回避了您对堆分配内存上的
sizeof
运算符的观点,因为我无法说出其行为是什么。我是老派,我永远不会在动态资源上使用 sizeof,因为它取决于运行时机制,谁知道不同的编译器供应商包含哪些运行时机制。然而,我知道,当一个数组被 C++ 中的 new (在大多数编译器上)分配时,它会在数组的底部放置一个物理上的整数。这个整数表示接下来的数组。这就是为什么您必须使用
delete []
运算符,该运算符与标准delete
不同,因为它会导致编译器吐出一个循环,该循环反复调用项目的析构函数。如果 C++ 编译器供应商将一个整数放在数组的底部,那么他们可能会在运行时使用它来为 sizeof 运算符提取它。 我不知道标准对此有何规定,并且我怀疑它是否可以这样工作。测试:Visual Studio 2008
输出:
4 4 20
您只能在运行时确定数组的大小(如果数组是硬编码的)——即,就像 z 的情况一样。 x 是一个 int ,y 是一个指针,两者的行为都是如此。
Comment : in standard C (C89) you should only be able to initialize an array with a literal or a const. So there is no confusion for the compiler.
Answer : If you initialize an array in the "on the stack way" -- i.e., without using new or malloc. The class would encapsulate the size of the array. The base of an array is a pointer because the compiler uses pointer arithmetic internally to resolve the access operator
[]
.If you use new or malloc, then you must use variable that you used to allocate memory as the definitive measure of the size of the memory you allocated. you may use
memcpy()
with the array base pointer, as irrespective of where it is allocated, it is still a pointer to the base memory location of the array.answer 2: after question edits
Yes it is perfectly safe to do that with const-sized arrays of the same type and of the same size, but do not do it with dynamically allocated resources unless you are tracking their types and sizes. Just avoid the approach you are taking and go with a container class.
Note : I have evaded your point on the
sizeof
operator on heap allocated memory as I cannot say what the behaviour is. I am old-school and I would never use sizeof on dynamic resources as it depends on runtime machinery, and who knows what runtime machinery different compiler vendors include.However, I know this, that when an array is alloced by new (on most compilers) in C++ it places a integer -- physically -- at the base of the array. This integer represents the size of the array that follows. This is why you must use the
delete []
operator, this operator differs from standarddelete
because it causes the compiler to spit out a loop which itteratively calls the destructor on your items. If a C++ compiler vendor place an integer at the base of an array than they might use this at runtime to extract it for the sizeof operator. I have no idea what the standard says about it, and I doubt it works this way.TEST: Visual Studio 2008
OUTPUT:
4 4 20
You can only determine the size of an array at runtime if its hard-coded -- i.e., like in the case of z. x is an int and y is a pointer both behave as such.
你研究过STL的向量吗?它的行为类似于数组,具有可调整的大小,并且包含一个返回数组大小的函数“size()”。
Have you looked into STL's vector. That behaves similar to an array, has adjustable size, and contains a function "size()" which returns the size of the array.
sizeof(ar)
仅起作用,因为ar
的声明此时对编译器可见。数组大小不会被存储,并且在运行时永远不可用,如果您将 ar 传递给函数并执行 sizeof(ar) ,您将得到 4 >。所以基本上你的编译器足够聪明,可以查看上面的几行。
sizeof
是一个编译器关键字,它将在编译时中提供大小。因此,编译器必须能够知道或推断出您正在查看的 var 的大小,以给出正确的大小。REEDIT::
sizeof
是一个编译时常量(C99 可变长度数组除外),编译器可以在其中添加运行时计算。然而,这是 C++ 的编译器扩展,因为 C99 不是 C++ 标准的一部分。sizeof(ar)
only works because the declaration ofar
is visible to the compiler at that point.Array sizes are not stored and never available in runtime, if you pass
ar
to a function and dosizeof(ar)
there you'll get4
. So its basically that your compiler is smart enough to look a couple of lines above.sizeof
is a compiler keyword that will deliver a size in compile time. So the compiler must be able to know, or deduce, the size of the var you are looking at to give the proper size.REEDIT: :
sizeof
is a compile-time constant [except for C99 variable-length arrays] where the compiler can add runtime computation. This however is a compiler extension to C++ as C99 is not part of the C++ standard.