c中的动态与静态数组

时间:2016-02-16 20:31:44

标签: c arrays memory-management dynamic static

以下代码使用malloc函数创建一个数组。但我知道只需使用int array [size]就可以做得更简单。我认为这是静态数组。但是malloc函数是动态数组吗?我在网上发现了这个代码......真正发生了什么,以及静态数组和动态数组(以及堆内存之间的静态内存)之间的区别。您可以在运行时更改动态数组的大小吗?或者......我完全不知道......如果有人能解释我会很感激:)

[HttpPost]
public async Task<dynamic> Upload([FromBody] UploadRequest UploadedData)
{
    // Now can access the JArray via uploadedData.pdfs directly
    // ...
}

3 个答案:

答案 0 :(得分:20)

有几种类型的数组,具体取决于它们的声明方式和位置。

定长数组

固定长度数组的大小必须在编译时确定。定义后,您无法更改固定长度数组的大小。

固定长度数组以下列方式之一声明:

T a[N];
T a[N] = { /* initializer list */ };
char_type a[N] = "string literal";
T a[]  = { /* initializer list */ };
char_type a[]  = "string literal";

在前三种情况下,N必须是常量表达式,其值必须在编译时知道。在前三种情况下,数组的大小取自N;在最后两种情况下,它取自初始化列表中的元素数量或字符串文字的大小。

固定长度数组的初始内容取决于其存储持续时间以及是否已提供初始化程序。

如果数组具有static存储持续时间(意味着它在任何函数体之外的文件范围内声明,或者使用static关键字声明)并且没有初始化器,则所有数组元素初始化为0(对于标量)或NULL(对于指针)。如果T是聚合类型(例如struct或数组类型),则聚合的每个成员都会使用0NULL进行初始化。 union类型同样归零。

如果数组具有auto存储持续时间(意味着它在没有static关键字的函数或块中声明)并且没有初始化器,则数组的内容为不确定 - 基本上,垃圾。

如果使用初始化列表声明数组(无论存储持续时间如何),则数组元素的初始值对应于初始化程序。如果初始化程序中的元素少于数组(例如,N为10,但您只初始化前5个元素),则剩余的元素初始化为,就好像数组一样static存储时间。 IOW,给出声明

int a[10] = {0, 1, 2};

然后数组的初始内容为{0, 1, 2, 0, 0, 0, 0, 0, 0, 0}

可以使用字符串文字初始化包含字符串值的固定长度数组。 C允许&#34;宽&#34;字符串,因此char_type可以是charwchar_t。规则初始化列表的规则是相同的,除了N(如果指定)必须至少比字符串终止符的字符串长度多1个。

这意味着

char a[10] = "test"; 

将初始化为{'t', 'e', 's', 't', 0, 0, 0, 0, 0, 0}

char a[] = "test";

将初始化为{'t', 'e', 's', 't', 0}

存储static存储持续时间的数组,以便在程序加载后立即可用,并且在程序退出之前不会被释放。这通常意味着它们存储在像.data.bss这样的内存段中(或者系统使用的任何可执行格式的等效项)。

存储auto存储持续时间的数组,以便它们在块或函数入口处分配,并在块或函数出口处释放(实际上,它们可能在函数入口处分配,无论是否它们仅限于函数中较小的范围) - 这通常转换为堆栈,尽管它没有

可变长度数组

在C99中添加了可变长度数组 - 除了它们的大小是在运行时建立之外,它们的行为主要是类固定长度数组。 N不必是编译时常量表达式:

int n;
printf( "gimme the array size: ");
scanf( "%d", &n );
T a[n]; // for any type T

与其名称所暗示的相反,您无法在定义可变长度数组后更改其大小。 &#34;可变长度&#34;只是意味着大小在编译时没有固定,并且可以从定义更改为定义。

由于它们的大小在运行时没有设置,因此可能不会在文件范围或static关键字中声明可变长度数组,也不能使用初始化列表声明它们。究竟如何管理VLA的空间取决于实现;它可能(并且通常是)从堆叠中取出,但AFAIK可以从其他地方取出。

动态阵列

动态数组实际上不是&#34;数组&#34;因此,至少就我们用来管理它们的对象的数据类型而言。动态数组在运行时使用malloccallocrealloc之一进行分配,并且该存储将一直保持到调用free为止。

T *p = malloc( sizeof *p * N ); // where N may be either a compile-time or
                                // run-time expression
...
free( p );

可以使用realloc库函数调整动态数组的大小,如下所示:

/**
 * If realloc fails, it will return NULL and leave the original array in 
 * place.  We assign the result to a temporary variable so we don't risk
 * losing our only reference to that memory. 
 */
T *tmp = realloc( p, sizeof *p * new_size );  
if ( tmp )                                    
  p = tmp;                                    

虽然数组元素本身的内存取自堆(或任何动态内存池),但指针变量 p的内存将从{{{ 1}}或.bss段或来自堆栈,基于.data的存储持续时间(pstatic)。

分配了automalloc的内存未初始化;那个记忆的内容将是不确定的。分配有realloc的内存将使用零初始化。

阵列与指针

在某些时候,有人会告诉你&#34;数组只是一个指针&#34;。那个人不对。

当您声明一个数组(固定长度或可变长度)时,会为该数组的元素留出足够的存储空间,而则不包含任何其他内容;没有为任何元数据留出存储空间,例如数组长度或指向第一个元素的指针。鉴于声明

calloc

然后存储将看起来像这样:

T a[N];

除了数组元素本身之外没有对象 +---+ a: | | a[0] +---+ | | a[1] +---+ | | a[2] +---+ ... +---+ | | a[N-1] +---+ (或者更确切地说,对象a 数组的元素)和表达式{ {1}}可能不是作业的目标。

但是...

表达式a 已定义a;也就是说,给定一个指针值a[i],从该地址偏移*(a + i) 元素 not bytes!)并取消引用结果。但如果a不是指针,那怎么办?

像这样 - 除非它是i或一元a运算符的操作数,或者是在声明中用作数组初始值设定项的字符串文字,表达式类型&#34; sizeof - 元素数组&&#34;将转换(&#34;衰变&#34;)到类型为&#34的表达式;指向N&#34;的指针,并且表达式的值将是数组的第一个元素的地址。

这有几个含义:

  • 表达式TTa都将产生相同的(数组的第一个元素的地址),但是表达式的类型将分别不同(分别为&a&a[0]T *);
  • 下标运算符T (*)[N]同样适用于数组表达式和指针表达式(实际上, 用于处理指针表达式);
  • 将数组表达式传递给函数时,实际传递的是指针值,而不是整个数组;

对于动态数组,情况有所不同。给出了这一行

T *

然后您的存储空间将如下所示:

[]

在这种情况下,T *p = malloc( sizeof *p * N ); 是数组中的一个单独对象。因此, +---+ p: | | ---+ +---+ | ... | +------+ | V +---+ | | p[0] +---+ | | p[1] +---+ ... +---+ | | p[N-1] +---+ 赢得为您提供与p&p相同的值,其类型将为p,而不是&p[0] T **。此外,由于T (*)[N]只是一个指针变量,您可以为其指定一个新值(尽管如果这样做而没有p它指向的内存,那么您将创建一个内存泄漏)。

同样,free 赢得的行为与sizeof p相似;它只会返回指针变量的大小,而不是指针指向的已分配内存的大小。

答案 1 :(得分:2)

静态数组在编译时分配内存,内存在堆栈上分配。然而,动态数组在运行时分配内存,内存从堆分配。

这是静态整数数组,即在运行时

之前分配的固定内存
int arr[] = { 1, 3, 4 };

这是动态整数数组,即在运行时分配的内存

int* arr = new int[3]; 

答案 2 :(得分:1)

您正在使用大小为+ 1的动态数组并向其添加元素(从0到大小)并在返回0之前释放空格。因此,在您的情况下,int * m_array是指向一个int。您在第13行所做的是声明:

(int *m_array) =...

和分配:

...(int *)malloc((size+1)*sizeof(int));

因为它是一个动态数组,所以你在堆上进行分配并保留直到它被释放(这就是为什么你最后有空闲(m_array))。如果它是静态的,你可以用这种方式初始化数组:

int m_array[size];

它将被分配到静态存储区域(除非是自动存储区域),并且一旦程序结束就会被解除分配。您无法在C中更改静态数组的大小,因此您需要使用动态数组。如果要更改为动态数组的大小,请使用realloc