2010-02-23 136 views
1

考虑到这一点:C++数组初始化

typedef struct 
{ 
int x; 
int y; 
} Coordinate; 

Coordinate places[100]; 
  • 是对自动分配的100个坐标存储器?或者当您初始化数组的每个元素时,它是否一次分配一个?

  • 如果您处理未初始化的数组部分,会发生什么情况?这是否会触发错误?

+0

当您声明位置时,会自动分配内存。如果你超出范围,你可能会导致分段错误。 – Beta 2010-02-23 13:55:07

+2

因为这是C++标记的,所以你不需要使用C typedef习惯用法。改为使用'struct Coordinate {...};'。这在C++中定义了一个名为'Coordinate'的类型。 – Clifford 2010-02-23 14:00:18

+0

@贝塔,这是一个答案,而不是评论。你为什么不把它放在答案中? – paxdiablo 2010-02-23 14:01:12

回答

0

1 /是的,有一个分配。在块的末尾调用析构函数并解除分配。

2 /使用默认构造函数初始化数组的所有元素(如果没有默认构造函数,则为编译时错误)。如果默认构造函数没有初始化某些东西,那么如果该对象是数组的一部分或者没有定义,那么它是相同的行为(即,如果它们被读取会导致未定义行为的未定义值)

+0

只是为了澄清。所有的100个对象都是一次分配的(或者在编译时,如果数组是全局的),并立即调用默认构造函数(或者当程序启动时,如果数组是全局的)。 根据访问类型,访问数组的未初始化部分(而不是越界部分)可能会或可能不会触发错误。我相信标准要求它是未定义的行为。通常情况下,读取未初始化的int不会触发错误,而通常会取消引用指针。 – Ari 2010-02-23 14:00:37

0

第一:是,区域是保留,但其内容是无效的,直到区域被正确初始化
第二:很多事情都可能发生,一个是ACCES违反或没有,但让你的系统的误动作

+0

对第二部分的轻微更正...解决未初始化的数组部分不会导致访问冲突,因为内存已分配 - 它可能只是填充垃圾数据,这可能会导致错误的行为。 – 2010-02-23 14:16:26

0

的内存分配会自动在栈上,所以你必须小心你的阵列有多大。每个操作系统都有不同的堆栈大小,但仍有一定的限制。通常每个线程/进程有少量KB。

当您访问数组的未初始化成员时,您将读取先前从另一个堆栈框架或之前存在于该存储器页面中的任何垃圾。因此,它被认为是一个良好的习惯,用memset或数组初始值设定项来初始化数组。

0

在你的例子中,所有的实例都是一次分配的 - 所有零到99的项都是有效的。如果你在构造函数中使用了一个类型,那么将会构造所有的100个类型。

编辑 - 正如其他人所指出的,仅仅因为它的构建并不意味着任何初始化。 “int”的默认构造函数将其保持原样(这是您的工作,可以将其初始化为任何您想要的)。 “struct”的默认构造函数为其成员调用构造函数。也就是说,构建在这里没有多大意义 - 但是内存已经分配并准备好供你使用(初始化和)使用。

第一个未初始化的“数组的一部分”不是数组的一部分 - 它超出了界限。例如...

Coordinate mistake = places [100]; // Above the upper bound 

这是“未定义”行为。您可能会遇到崩溃(某种与处理器相关的内存异常)。您的程序可能会继续愉快地工作,并不知道它使用了无效的垃圾数据。在上述情况下,由于发生的事情相当明显,您可能会收到编译器警告 - 但通常情况并非如此。

如果以越界 - 数组索引,你可能会破坏其他变量或你的函数的返回地址,或任何事情,让你的整个程序的行为从该点起是未定义。这是最大的安全漏洞和“漏洞利用”类别之一的基础。

std :: vector是另一种创建数组的方法。它不会立即分配所有项目 - 它是一个允许(并管理)调整大小的动态数组。但是,它不会超出基本的C风格数组。

0

1)内存分配为一个连续的块。 2)如果静态地实例化(即不是auto变量),则存储器应该被初始化为0,否则它将被初始化并且内容应该是未定义的。访问这些未定义的值不会触发任何错误,如果您读取垃圾数据并对其执行操作,行为将完全由非确定性内容确定,以及您的代码如何处理它。

如果你想自动初始化,你可以定义一个默认的构造函数。在C++中,结构实际上与类相同(区别在于默认的成员可见性和继承),并且可以具有成员函数,构造函数和析构函数。

2

如何保留内存取决于声明数组声明的位置。如果它是在全局范围内声明的(即在一个函数之外),那么800个字节(假设一个整数是32位长)可以立即用于整个程序。如果它在函数内部,则这800字节被分配到堆栈上,并且在函数退出时不可访问。

因此,在问题1中:是的,整个100个坐标在与声明相同的范围内可用。

问题2:您可以随时访问所有100个元素,但其内容将被初始化。因此,立即写入所有100个索引是安全的,只是在你初始化它们之前不要读取它们。

如果你想初始化所有这些(说0,0),那么作出这一声明,而不是:

struct Coordinate 
{ 
    int x; 
    int y; 

    Coordinate() : x(0), y(0) { } 
}; 
当然

,在C这只能++。如果您使用C语言编写代码,那么您无法自动初始化数组中的元素。

在0到99范围外读取会导致未定义的行为。充其量,运行时会检测到给你一个运行时错误。在最坏的情况下,你会破坏内存,直到程序结束后才会知道错误在哪里。所以要小心,并确保你的指数在界限内。

通常的做法是提供一个访问数组的函数(不要直接访问数组),并且您可以执行断言检查以测试数组索引。

祝你好运

+0

小提示:如果在全局范围声明数组,则即使没有Coordinate()构造函数,int值也将被初始化为0。 – MtnViewMark 2010-02-23 14:16:51

+0

也在本地范围内,但使用“静态”存储类,保证了零初始化。 – Clifford 2010-02-24 05:05:55

+0

关于“通用实践”段落,由于这是C++,因此使用'at()'成员函数而不是'[]'运算符访问的'std :: vector'类型通常会更好(或至少少C类)解决方案,因为如果索引超出边界,它会引发异常。 – Clifford 2010-02-24 05:10:44

0

基于类型的数组行为不会有任何差异。 因此,一旦创建数组并且未初始化的变量会包含一些垃圾数据,就会完成内存分配。

要初始化数组的所有元素,可以使用默认构造函数将它们初始化为需要的值或带有默认参数的构造函数,其中值可以初始化为未提供值时所需的值。

例如:

struct Coordinate 
{ 
    int x; 
    int y; 

    Coordinate (int x1 = 0, int y1 = 0) : x(x1), y(y1) { } 
}; 

这适用于阵列和阵列中的所有值将被initiliazed到零(0)。

,用来初始化基本数据类型的数组的所有元素为零(0)

int places[100] = { 0 }; 

没有验证它是否工作为用户定义的类型,虽然。你可以试试看。