这些数组声明在C中的区别是什么?

时间:2014-02-04 14:08:57

标签: c arrays malloc

人们似乎在使用数组时会说malloc是如此之大,如果你不知道数组在编译时有多少元素(?),你可以使用它。好吧,没有malloc你不能那样做吗?例如,如果我们知道我们有一个字符串,其最大长度为10,那么以下内容是否足够接近同一个东西?...除了能够释放内存之外。

char name[sizeof(char)*10]; 

char *name = malloc(sizeof(char)*10); 

5 个答案:

答案 0 :(得分:7)

第一个在堆栈上创建一个chars数组。数组的长度为sizeof(char)*10,但看作char的标准是1的大小,您可以写char name[10];
如果你想要一个大到足以存储10个整数的数组(每个标准定义为至少 2个字节大小,但最常见的是4个大字节),int my_array[10]也有效。编译器可以计算出需要多少内存,不需要编写类似int foo[10*sizeof(int)]的内容。事实上,后者将是不可预测的:取决于sizeof(int),数组将存储至少 20个整数,但可能足够大以存储40个。 无论如何,后一个片段调用一个函数,malloc将尝试分配足够的内存来存储堆上的10个字符。内存未初始化,因此它将包含垃圾。

堆上的内存稍慢,需要您编写代码时更多关注:您必须明确free。 再次:char保证大小为1,因此char *name = malloc(10);也会在此处执行。但是,在使用堆内存时,我 - 我并不孤单 - 更喜欢使用some_ptr = malloc(10*sizeof *some_ptr);分配内存*some_ptr,就像说大小的10倍键入此指针将指向。如果您以后碰巧更改了类型,则无需重构所有malloc次来电。

一般的经验法则,回答你的问题“你可以不用malloc,是 使用malloc,除非你必须 堆栈内存更快,更易于使用,但它不够丰富。这个站点是以一个众所周知的问题命名的,当你把太多的东西推到堆栈上时它会遇到这个问题:它溢出了。

运行程序时,系统会分配一块可以自由使用的内存。这并不多,但很多简单的计算和调用函数。一旦用完,你将不得不求助于从堆中分配内存 但在这种情况下,10个字符的数组:使用堆栈。

需要考虑的其他事项:

  • 数组是一个连续的内存块
  • 指针不知道/无法告诉您分配了多大的内存块(sizeof(an_array)/sizeof(type) vs sizeof(a_pointer)
  • 数组的声明不需要使用sizeof。编译器可以为您计算大小:<type> my_var[10]将保留足够的内存来容纳给定类型的10个元素。
  • 大多数时候,数组会衰减为指针,但这并不会使它们成为同一个东西
  • 指针很有趣,如果你知道你在做什么,但是一旦你开始添加函数,并开始传递指向指针的指针,或指向指向结构的指针,指针的成员就是指针。你的代码不会像维护一样快乐。我发现,从一个数组开始,可以更容易地掌握代码,因为它为您提供了一个起点。
  • 这个答案只适用于你提供的片段,如果你正在处理一个随时间增长的数组,那么首选realloc。如果你在一个递归函数中声明这个数组,那个运行得很深,那么malloc也可能是更安全的选择

Check this link on differences between array and pointers

另外take a look at this question + answer。它解释了为什么指针无法为您提供正在处理的内存块的确切大小,以及为什么数组可以。 在可能的情况下考虑支持数组的论证

答案 1 :(得分:2)

char name[sizeof(char)*10]; // better to use: char name[10];

在编译时静态分配sizeof(char)*10个char元素的向量。 sizeof运算符没用,因为如果您分配N类型为T的数组,则分配的大小已经是sizeof(T)*N,您无需进行数学运算。分配堆栈,不需要免费。通常,当您已经知道所需对象的大小(在这种情况下为字符串的长度)时,使用char name[10]

char *name = malloc(sizeof(char)*10);

在堆中分配10个字节的内存。分配在运行时完成,您需要释放结果。

答案 2 :(得分:1)

  1. char name[sizeof(char)*10]; 第一个在堆栈上分配,一旦超出范围内存就会自动释放。你无法改变第一个的大小。

  2. char *name = malloc(sizeof(char)*10); 第二个在堆上分配,应该使用free释放。在应用程序的生命周期内,它会以其他方式存在。如果需要,您可以为第二个重新分配内存。

答案 3 :(得分:0)

存储时间不同:

  • 使用char name[size]创建的数组在程序执行的整个持续时间内存在(如果在文件范围或static定义)或者执行该块,则在(否则)中定义。这些称为静态存储持续时间和自动存储持续时间。
  • 从您拨打malloc(size)到致电malloc的时间,您指定的数组与free一样存在。因此,可以在您需要时使用空间,这与静态存储持续时间(可能太长)或自动存储持续时间(可能太短)不同。

可用空间量不同:

  • 在函数内部使用char name[size]创建的数组在典型的C实现中使用堆栈,堆栈大小通常限制为几兆字节(如果在构建程序时做出特殊规定,则更多,通常在内核中更少软件和嵌入式系统)。
  • 使用malloc创建的数组可能会在典型的现代系统中使用千兆字节的空间。

对动态尺寸的支持是不同的:

  • 使用具有静态存储持续时间的char name[size]创建的数组必须具有在编译时指定的大小。如果C实现支持,则使用具有自动存储持续时间的char name[size]创建的数组可以具有可变长度(这在C 1999中是强制性的,但在C 2011中是可选的)。
  • 使用malloc创建的数组可能具有在运行时计算的大小。

malloc提供了更大的灵活性:

  • 在程序启动时(静态存储持续时间)或执行到达块或定义(自动)时,使用char name[size]始终会创建具有给定名称的数组。
  • malloc可以在运行时用于创建任意数量的数组(或其他对象),通过使用指针或链接列表或树或其他数据结构的数组来创建指向创建的对象的众多指针与malloc。因此,如果您的程序需要一千个单独的对象,则可以创建一个包含一千个指针的数组,并使用循环为每个对象分配空间。相比之下,编写一千个char name[size]定义会很麻烦。

答案 4 :(得分:0)

首先要做的事情是:不写

char name[sizeof(char)*10];

您不需要sizeof作为数组声明的一部分。只需写下

char name[10]; 

这声明了一个类型为char的10个元素的数组。就像

一样
int values[10];

声明一个包含10个int类型元素的数组。编译器根据元素的类型和数量知道要分配多少空间。

如果您知道,您将永远不需要超过N个元素,那么是的,您可以声明一个具有该大小的数组并完成它,

你冒着内部分裂的风险;您的最大字节数可能是N,但您需要的平均字节数可能远小于此数。例如,假设您要存储1000个最大长度为255的字符串,因此您声明了一个类似

的数组
char strs[1000][256];

但事实证明,这些字符串中的900个只有20个字节长;你浪费了几百千字节的空间 1 。如果您拆分差异并存储了1000个指针,那么只分配了存储每个字符串所需的空间,那么您最终会浪费很多 less 存储器:

char *strs[1000];
...
strs[i] = strdup("some string"); // strdup calls malloc under the hood
...

堆栈空间相对于堆空间也是有限的;你可能无法声明任意大的数组(如auto变量,anway)。像

这样的请求
long double huge[10000][10000][10000][10000];

可能会导致代码在运行时崩溃,因为默认堆栈大小不足以容纳它 2

最后,大多数情况属于以下三种类别之一:你有0个元素,你有1个元素,或者你有无限数量的元素。分配足够大的阵列以涵盖所有可能的场景&#34;只是不起作用。在那里,做到了,得到了多种尺寸和颜色的T恤。

<小时/> 1。是的,我们生活在未来,我们有可用的千兆字节地址空间,所以浪费几百KB并不是什么大不了的事。这一点仍然有效,你浪费了你不必要的空间。

2. 可以在文件范围内使用static关键字声明非常大的数组;这将在不同的内存段(堆栈或堆)中分配数组。问题是你只有那个数组的单个实例;如果你的功能是可重入的,那么这不会起作用。