首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >数组的大小

数组的大小
EN

Stack Overflow用户
提问于 2009-12-09 23:08:29
回答 6查看 1.8K关注 0票数 1

这个问题是关于C++的

我一直认为C++中数组的名称只是一个指针,所以我认为

代码语言:javascript
运行
复制
int ar[10];
cout << sizeof(ar);

会给我和sizeof(int *)一样的效果。但是它给出了40,所以它是整个数组的实际大小。当数组大小由变量给定时,它也会得到40:

代码语言:javascript
运行
复制
int n = 10;
int ar[n]

我想复制一个包含数组的类。如果它是用操作符new分配的,那么我应该在一个复制构造函数中手动复制这个数组。但是固定大小的数组呢?class是只包含指向数组的指针,还是包含整个数组?简单的memcpy(...)在这里安全吗?

编辑:另一个示例:

代码语言:javascript
运行
复制
int n;
cin >> n;
int ar[n];
cout << sizeof(ar);

它输出n*4。我在linux上使用g++。

我甚至试过这个:

代码语言:javascript
运行
复制
class Test {
public:
    int ar[4];
};

代码语言:javascript
运行
复制
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;

它提供了:

代码语言:javascript
运行
复制
A: 20
B: 10
C: 10

因此数组被存储为类的一部分,并且可以用memcpy复制。但是它安全吗?

EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2009-12-09 23:32:54

一次只看一个:

我想复制一个包含数组的类。

好吧,举个例子:

代码语言:javascript
运行
复制
class Foo
{
    int arr[20];
};

如果它被分配了运算符

,那么我应该在一个复制构造函数中手动复制这个数组。

好了,现在混乱开始了。在上面的例子中,数组实际上是对象的一部分。如果int是4字节,sizeof(Foo)会给你80。

另一种方法是使用指向数组的指针,如果数组需要更改大小,这将非常有用:

代码语言:javascript
运行
复制
class Bar
{
    int *arr;
};

在这种情况下,sizeof(Bar)是指针的大小(通常是4或8字节),复制对象会复制指针。这被称为“浅层复制”。如果你想要一个“深度拷贝”,即一个拷贝将复制数组的内容,而不仅仅是对象,那么你需要一个拷贝构造函数。

第三种选择是使用vector,正如wheaties建议的那样:

代码语言:javascript
运行
复制
class Bob
{
    std::vector<int> arr;
};

这在内部的工作方式与Bar相同,并且可以调整vector的大小,但是vector模板会为您处理深层复制,因此您不需要复制构造函数。

如果需要一个固定大小的数组,我推荐使用Foo,因为它的大小在编译时是已知的,否则推荐使用BobBar的案例在很大程度上只是在重新发明轮子。

是简单的memcpy(...)这里安全吗?

对于Foo是安全的。如果你想要一个浅拷贝,对Bar来说是安全的。对Bob不安全。

这个故事的寓意是,将变量存储在对象中就像将其存储在函数块或全局中一样:如果指定一个数组([N]而不是*),大小最好在编译时确定,并将存储放在那里。

票数 5
EN

Stack Overflow用户

发布于 2009-12-09 23:27:11

数组不是指针。当/如果将数组名称作为参数传递给函数时,数组的名称将“衰减”为指针--但是sizeof是语言中内置的运算符,而不是函数,因此只要将数组应用于实际的数组,sizeof(array)就会生成数组的实际大小(与作为参数传递的数组名称相反,然后在传递给函数时对指针使用sizeof(),该指针将衰减到该指针。

至于复制一个包含数组的类,如果它真的是一个数组,比如:

代码语言:javascript
运行
复制
class X { 
    int x[10];
};

然后,您不需要做任何事情就可以复制它--编译器可以/将生成一个复制数组内容的复制构造函数。如果(且仅当)您确实有一个指针,并且自己分配空间,那么您是否需要编写一个复制ctor来执行“深度复制”(即,在新对象中分配空间,并复制指针指向的数据)。但是,您通常应该使用std::vector,它在内部完成所有这些工作,因此您不必担心。

票数 8
EN

Stack Overflow用户

发布于 2009-12-09 23:10:51

注释:在标准C (C89)中,应该只能使用文字或常量来初始化数组。因此,编译器不会产生混淆。

回答:如果你以“堆栈方式”初始化一个数组--也就是不使用new或malloc。该类将封装数组的大小。数组的基数是一个指针,因为编译器在内部使用指针算法来解析访问运算符[]

如果使用new或malloc,则必须使用用于分配内存的变量作为所分配内存大小的最终度量。您可以将memcpy()与数组基址指针一起使用,因为无论将其分配到何处,它仍然是指向数组基址内存位置的指针。

答案2:问题编辑

是的,使用相同类型和相同大小的常量大小的数组来执行此操作是完全安全的,但不要使用动态分配的资源执行此操作,除非您正在跟踪它们的类型和大小。只需避免使用您正在采用的方法,而使用容器类。

注意:我回避了你关于堆分配内存的sizeof操作符的观点,因为我不能说出行为是什么。我是老派,我永远不会在动态资源上使用sizeof,因为它依赖于运行时机制,谁知道不同的编译器供应商包括什么运行时机制。

但是,我知道这一点,在C++中由new (在大多数编译器上)分配数组时,它会在数组底部放置一个整数--物理上是这样。这个整数表示后面的数组的大小。这就是为什么你必须使用析构运算符,这个运算符不同于标准的delete,因为它会导致编译器吐出一个循环,该循环反复调用你的项目上的析构函数。如果C++编译器供应商将一个整数放在数组的底部,那么他们可能会在运行时使用它来为sizeof运算符提取它。我不知道标准是怎么说的,我怀疑它是这样工作的。

测试: Visual Studio 2008

代码语言:javascript
运行
复制
#include "stdafx.h"
#include <iostream>


int _tmain(int argc, _TCHAR* argv[])
{
    int x;
    int *y=new int[5];
    int z[5];
    std::cout << sizeof(x);
    std::cout << " " <<  sizeof(y);
    std::cout << " " << sizeof(z);
    return 0;
}

输出:

4 4 20

只有在数组是硬编码的情况下,才能在运行时确定数组的大小--例如,z。x是int,y是指针,两者的行为都是这样的。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1874493

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档