动态与静态内存分配
Dynamic vs Static memory allocation
因此您可以使用 "new" 运算符在 运行 时动态分配内存。但是下面的情况呢:
#include <iostream>
using namespace std;
int main ()
{
int size;
cin >> size;
int a[size];
}
这里数组的大小不可能在编译时就知道,而是在运行时确定的。这与动态分配的内存有何不同?
这个问题的部分原因是 this 页上的声明:
There is a substantial difference between declaring a normal array and allocating dynamic memory for a block of memory using new. The most important difference is that the size of a regular array needs to be a constant expression, and thus its size has to be determined at the moment of designing the program, before it is run, whereas the dynamic memory allocation performed by new allows to assign memory during runtime using any variable value as size.
这在 C 中是合法的,但在 C++ 中不是。然而,一些 C++ 编译器允许它作为扩展。 This question covers that part in more detail.
它不同于典型的动态内存分配,因为内存是在堆栈(而不是堆)上分配的,并且具有自动存储持续时间(意味着它会在作用域结束时自动释放)。当执行退出包含 a
的范围时,它将自动被释放。通过 new
/malloc
.
分配的内存不是这种情况
它仍然是动态内存分配的一种形式(很明显,因为内存必须在堆栈上动态分配),但它不是人们在使用该术语时通常指的动态内存分配类型。
ISO C99 允许可变长度自动数组,作为扩展,GCC 在 C90 模式和 C++ 中接受它们。这些数组的声明方式与任何其他自动数组一样,但长度不是常量表达式。存储在声明点分配,并在包含声明的块作用域退出时释放。例如:
FILE *
concat_fopen (char *s1, char *s2, char *mode)
{
char str[strlen (s1) + strlen (s2) + 1];
strcpy (str, s1);
strcat (str, s2);
return fopen (str, mode);
}
跳出或突破数组名称的范围会释放存储空间。不允许跳入范围;你收到一条错误消息。
作为扩展,GCC 接受可变长度数组作为结构或联合的成员。例如:
void
foo (int n)
{
struct S { int x[n]; };
}
您可以使用函数 alloca 来获得类似于可变长度数组的效果。函数 alloca 在许多其他 C 实现中可用(但不是全部)。另一方面,可变长度数组更优雅。
这两种方法之间还有其他区别。 Space 用 alloca 分配的函数一直存在到包含函数 returns。一旦数组名称的作用域结束,可变长度数组的 space 就会被释放。 (如果您在同一个函数中同时使用可变长度数组和 alloca,释放可变长度数组也会释放最近分配给 alloca 的任何东西。)
您还可以使用变长数组作为函数的参数:
struct entry
tester (int len, char data[len][len])
{
/* ... */
}
数组的长度在分配存储时计算一次,并在数组范围内记住,以防您使用 sizeof 访问它。
如果你想先传递数组再传递长度,你可以在参数列表中使用前向声明——另一个GNU扩展。
struct entry
tester (int len; char data[len][len], int len)
{
/* ... */
}
分号前的'int len'是一个参数前向声明,它的作用是在解析数据声明时使名称len已知。
您可以在参数列表中写入任意数量的此类参数前向声明。它们可以用逗号或分号分隔,但最后一个必须以分号结尾,后面是“真正的”参数声明。每个前向声明必须与参数名称和数据类型中的“真实”声明相匹配。 ISO C99 不支持参数前向声明。
因此您可以使用 "new" 运算符在 运行 时动态分配内存。但是下面的情况呢:
#include <iostream>
using namespace std;
int main ()
{
int size;
cin >> size;
int a[size];
}
这里数组的大小不可能在编译时就知道,而是在运行时确定的。这与动态分配的内存有何不同?
这个问题的部分原因是 this 页上的声明:
There is a substantial difference between declaring a normal array and allocating dynamic memory for a block of memory using new. The most important difference is that the size of a regular array needs to be a constant expression, and thus its size has to be determined at the moment of designing the program, before it is run, whereas the dynamic memory allocation performed by new allows to assign memory during runtime using any variable value as size.
这在 C 中是合法的,但在 C++ 中不是。然而,一些 C++ 编译器允许它作为扩展。 This question covers that part in more detail.
它不同于典型的动态内存分配,因为内存是在堆栈(而不是堆)上分配的,并且具有自动存储持续时间(意味着它会在作用域结束时自动释放)。当执行退出包含 a
的范围时,它将自动被释放。通过 new
/malloc
.
它仍然是动态内存分配的一种形式(很明显,因为内存必须在堆栈上动态分配),但它不是人们在使用该术语时通常指的动态内存分配类型。
ISO C99 允许可变长度自动数组,作为扩展,GCC 在 C90 模式和 C++ 中接受它们。这些数组的声明方式与任何其他自动数组一样,但长度不是常量表达式。存储在声明点分配,并在包含声明的块作用域退出时释放。例如:
FILE *
concat_fopen (char *s1, char *s2, char *mode)
{
char str[strlen (s1) + strlen (s2) + 1];
strcpy (str, s1);
strcat (str, s2);
return fopen (str, mode);
}
跳出或突破数组名称的范围会释放存储空间。不允许跳入范围;你收到一条错误消息。
作为扩展,GCC 接受可变长度数组作为结构或联合的成员。例如:
void
foo (int n)
{
struct S { int x[n]; };
}
您可以使用函数 alloca 来获得类似于可变长度数组的效果。函数 alloca 在许多其他 C 实现中可用(但不是全部)。另一方面,可变长度数组更优雅。
这两种方法之间还有其他区别。 Space 用 alloca 分配的函数一直存在到包含函数 returns。一旦数组名称的作用域结束,可变长度数组的 space 就会被释放。 (如果您在同一个函数中同时使用可变长度数组和 alloca,释放可变长度数组也会释放最近分配给 alloca 的任何东西。)
您还可以使用变长数组作为函数的参数:
struct entry
tester (int len, char data[len][len])
{
/* ... */
}
数组的长度在分配存储时计算一次,并在数组范围内记住,以防您使用 sizeof 访问它。
如果你想先传递数组再传递长度,你可以在参数列表中使用前向声明——另一个GNU扩展。
struct entry
tester (int len; char data[len][len], int len)
{
/* ... */
}
分号前的'int len'是一个参数前向声明,它的作用是在解析数据声明时使名称len已知。
您可以在参数列表中写入任意数量的此类参数前向声明。它们可以用逗号或分号分隔,但最后一个必须以分号结尾,后面是“真正的”参数声明。每个前向声明必须与参数名称和数据类型中的“真实”声明相匹配。 ISO C99 不支持参数前向声明。