C语言 c中的动态与静态数组

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/35442414/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 10:20:07  来源:igfitidea点击:

Dynamic vs static array in c

carraysmemory-managementdynamicstatic

提问by Cache

The following code creates an array with the malloc function. But i know that this can be done much simplier with just int array[size]. I think this is static array. But with the malloc function is it dynamic array? I found this code in the net... What is really happening and whats the difference between a static array and a dynamic array(and static memory between heap memory). Can you change the size of the dynamic array during runtime? or... what i dont know exactly... If someone could explain i would appreciate :)

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

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void)
{
    int size;
    int i;
    printf("Choose size of array: ");
    scanf("%d",&size);

    /*---MALLOC/FREE---*/
    int *m_array = (int *)malloc((size+1)*sizeof(int));
    memset(m_array,'
T a[N];
T a[N] = { /* initializer list */ };
char_type a[N] = "string literal";
T a[]  = { /* initializer list */ };
char_type a[]  = "string literal";
',size+1); for(i=0; i<size ; i++) { m_array[i]=i; printf("%d ",m_array[i]); } printf("\n"); free(m_array); return 0; }

回答by John Bode

There are several flavors of arrays, depending on how and where they are declared.

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

Fixed-length Arrays

定长数组

Fixed-length arrays must have their size determined at compile time. You cannot change the size of a fixed-length array after it has been defined.

定长数组的大小必须在编译时确定。定长数组一经定义便无法更改其大小。

Fixed-length arrays are declared in one of the following ways:

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

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

In the first three cases, Nmust be a constant expressionwhose value must be known at compile time. In the first three cases, the size of the array is taken from N; in the last two cases, it's taken from the number of elements in the initializer list or the size of the string literal.

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

The initial contents of a fixed-length array depend on its storage durationand whether an initializer has been supplied.

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

If the array has staticstorage duration (meaning it was declared at file scope outside of any function body, or was declared with the statickeyword) and no initializer is present, then all of the array elements are initialized to 0(for scalars) or NULL(for pointers). If Tis an aggregate type such as a structor an array type, then each member of the aggregate is initialized with a 0or NULL. uniontypes are similarly zeroed out.

如果数组有static存储期(意味着它是在任何函数体之外的文件范围内声明的,或者是用static关键字声明的)并且不存在初始化器,那么所有数组元素都被初始化为0(对于标量)或NULL(对于指针) )。如果T是聚合类型,例如 astruct或数组类型,则聚合的每个成员都使用 a0或 进行初始化NULLunion类型同样被清零。

If the array has autostorage duration (meaning it was declared within a function or block without the statickeyword) and no initializer is present, then the contents of the array are indeterminate- basically, garbage.

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

If the array is declared with an initializer list (regardless of storage duration), then the initial values of the array elements correspond to the initializer. If there are fewer elements in the initializer than the array (for example, Nis 10 but you only initialize the first 5 elements), then the remaining elements are initialized as thoughthe array had staticstorage duration. IOW, given the declaration

如果数组是用初始化器列表声明的(无论存储持续时间如何),则数组元素的初始值对应于初始化器。如果初始化器中的元素比数组少(例如,N是 10,但您只初始化前 5 个元素),则其余元素将被初始化,就好像数组具有static存储持续时间一样。IOW,鉴于声明

char a[10] = "test"; 

then the initial contents of the array are {0, 1, 2, 0, 0, 0, 0, 0, 0, 0}.

那么数组的初始内容是{0, 1, 2, 0, 0, 0, 0, 0, 0, 0}.

Fixed-length arrays containing string values may be initialized using a string literal. C allows for "wide" character strings, so char_typemay be either charor wchar_t. The rules are the same for regular initializer lists, except that N(if specified) must be at least 1 more than the length of the string to account for the string terminator.

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

This means that

这意味着

char a[] = "test";

will be initialized as {'t', 'e', 's', 't', 0, 0, 0, 0, 0, 0}and

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

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

will be initialized as {'t', 'e', 's', 't', 0}.

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

Arrays with staticstorage duration are stored such that they are available as soon as the program is loaded, and aren't released until the program exits. This usually means that they're stored in a memory segment like .dataor .bss(or the equivalent for whatever executable format your system uses).

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

Arrays with autostorage duration are stored such that they are allocated at block or function entry and released at block or function exit (in practice, they'll probably be allocated at function entry, regardless of whether they're limited to a smaller scope within the function) - this typically translates to the stack, although it doesn't haveto.

auto存储持续时间的数组被存储为在块或函数入口分配并在块或函数出口释放(实际上,它们可能会在函数入口分配,无论它们是否被限制在较小的范围内)函数) - 这通常转换为堆栈,尽管它不是必须的。

Variable-length Arrays

变长数组

Variable-length arrays were added in C99 - they behave mostlylike fixed-length arrays, except that their size is established at run time; Ndoes not have to be a compile-time constant expression:

C99 中添加了可变长度数组——它们的行为大多类似于固定长度数组,不同之处在于它们的大小是在运行时确定的N不必是编译时常量表达式:

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

Contrary to what their name implies, you cannot change the size of a variable-length array after it has been defined. "Variable-length" simply means that the size isn't fixed at compile time, and can change from definition to definition.

与其名称所暗示的相反,您不能在定义可变长度数组后更改其大小。“可变长度”只是意味着大小在编译时不是固定的,并且可以随定义而变化。

Since their size isn't set until runtime, variable-length arrays may not be declared at file scope or with the statickeyword, nor can they be declared with an initializer list. Exactly how the space for VLAs is managed is up to the implementation; it may be (and usually is) taken from the stack, but AFAIK may be taken from somewhere else.

由于它们的大小直到运行时才设置,因此不能在文件范围内或使用static关键字声明变长数组,也不能使用初始值设定项列表声明它们。究竟如何管理 VLA 的空间取决于实施;它可能(通常是)从堆栈中取出,但 AFAIK 可能从其他地方取出。

Dynamic Arrays

动态数组

Dynamic arrays are not really "arrays" as such, at least in terms of the data types of the objects we use to manage them. Dynamic arrays are allocated at runtime using one of malloc, calloc, or realloc, and that storage is held until released with a call to free.

动态数组并不是真正的“数组”,至少就我们用来管理它们的对象的数据类型而言。动态数组所使用的一个在运行时分配的malloccalloc或者realloc,和存储一直保持到一起的呼叫释放free

/**
 * 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;                                    

A dynamic array may be resized using the realloclibrary function, like so:

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

T a[N];

While the memory for the array elements themselves is taken from the heap (or whatever dynamic memory pool), the memory for the pointer variablepwill be allocated from either a .bssor .datasegment or from the stack, based on p's storage duration (staticor auto).

虽然数组元素本身的内存是从堆(或任何动态内存池)中获取的,但指针变量的内存p将从.bss.data段或堆栈中分配,基于p的存储持续时间(staticauto)。

Memory allocated with mallocor reallocis not initialized; the contents of that memory will be indeterminate. Memory allocated with callocwill be initialized with zeros.

分配的内存malloc或未realloc初始化;该内存的内容将是不确定的。分配的内存calloc将用零初始化。

Arrays vs. Pointers

数组与指针

At some point, somebody is going to tell you that "an array is just a pointer". That person is not correct.

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

When you declare an array (either fixed- or variable-length), enough storage is set aside for the elements of that array and nothing else; no storage is set aside for any metadata such as the array length or a pointer to the first element. Given the declaration

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

    +---+
 a: |   | a[0]
    +---+
    |   | a[1]
    +---+
    |   | a[2]
    +---+
     ...
    +---+ 
    |   | a[N-1]
    +---+

then the storage will look something like this:

那么存储将如下所示:

T *p = malloc( sizeof *p * N );

There is no object aapart from the array elements themselves (or, more properly, the object aisthe elements of the array), and the expression amay not be the target of an assignment.

a除了数组元素本身之外没有任何对象(或者,更准确地说,对象a数组的元素),并且表达式a可能不是赋值的目标。

But...

但...

The expression a[i]is definedas *(a + i); that is, given a pointer value a, offset ielements(not bytes!) from that address and dereference the result. But if ais not a pointer, how can that work?

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

Like this - except when it is the operand of the sizeofor unary &operators, or is a string literal used as an array initializer in a declaration, an expressionof type "N-element array of T" will be converted("decay") to an expression of type "pointer to T", and the value of the expression will be the address of the first element of the array.

像这样 - 除非它是sizeof或 一元运算&符的操作数,或者是在声明中用作数组初始值设定项的字符串文字,否则类型为“ -element array of ”的表达式将被转换(“衰减”)为表达式类型为“指向”的指针,表达式的值将是数组第一个元素的地址。 NTT

This has several implications:

这有几个含义:

  • The expressions a, &a, and &a[0]will all yield the same value(the address of the first element of the array), but the typesof the expressions will be different (T *, T (*)[N], and T *, respectively);
  • The subscript operator []works equally well with both array expressions and pointer expressions (indeed, it's definedto work on pointer expressions);
  • When you pass an array expression to a function, what you are actuallypassing is a pointer value, not the entire array;
  • 的表达a&a以及&a[0]将所有产生相同的(所述阵列的所述第一元素的地址),但类型的表达式将是不同的(T *T (*)[N],和T *,分别地);
  • 下标运算符[]对数组表达式和指针表达式同样适用(实际上,它被定义为用于指针表达式);
  • 当您将数组表达式传递给函数时,您实际传递的是一个指针值,而不是整个数组;

For dynamic arrays, the situation is different. Given the line

对于动态数组,情况就不同了。鉴于行

   +---+
p: |   | ---+
   +---+    |
    ...     |
     +------+
     |
     V
   +---+
   |   | p[0]
   +---+
   |   | p[1]
   +---+
    ...   
   +---+
   |   | p[N-1]
   +---+

then your storage will look something like this:

那么您的存储将如下所示:

int arr[] = { 1, 3, 4 };

In this case, pisa separate object from the array. Thus, &pwon'tgive you the same value as pand &p[0], and its type will be T **as opposed to T (*)[N]. Also, since pis just a pointer variable, you can assign a new value to it (although if you do so without freeing the memory it points to first, you'll create a memory leak).

在这种情况下,p与数组不同的对象。因此,&p不会为您提供与pand相同的值&p[0],它的类型将T **T (*)[N]. 此外,由于p它只是一个指针变量,因此您可以为其分配一个新值(尽管如果您这样做而没有首先freeing 它指向的内存,则会造成内存泄漏)。

Similarly, sizeof pwon'tbehave like sizeof a; it will simply return the size of the pointer variable, not the size of the allocated memory that the pointer points to.

同样,sizeof p不会表现得像sizeof a; 它会简单地返回指针变量的大小,而不是分配的内存指针点的大小

回答by Muhammad Noman

Static arrays are allocated memory at compile time and the memory is allocated on the stack. Whereas, the dynamic arrays are allocated memory at the runtime and the memory is allocated from heap.

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

This is static integer array i.e. fixed memory assigned before runtime

这是静态整数数组,即在运行前分配的固定内存

int* arr = new int[3]; 

This is dynamic integer array i.e memory assigned on runtime

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

(int *m_array) =...

回答by Larry

You're using dynamic arrays of size+1 and adding elements to it (from 0 to size) and releasing the space at the end before returning 0. So when in your case, int *m_array is a pointer to an int. What you're doing on line 13 is declaration:

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

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

and allocation:

和分配:

int m_array[size];

Since it is a dynamic array, you are allocating on heap and is kept until it is freed (that's why you have free(m_array) at the end). If it was static, you could've initialized the array this way:

由于它是一个动态数组,因此您在堆上分配并一直保留到它被释放为止(这就是为什么最后有 free(m_array) 的原因)。如果它是静态的,你可以这样初始化数组:

##代码##

And it would've been allocated on static storage area (unless is automatic) and would be deallocated as soon as the program ended. You can't change the size of an static array in C, so you need to use a dynamic array. You use reallocwhen you want to change to size of a dynamic array.

它会被分配到静态存储区(除非是自动的)并且会在程序结束后立即被释放。你不能在 C 中改变静态数组的大小,所以你需要使用动态数组。当您想要更改为动态数组的大小时,您可以使用realloc