我可以用这种方式制作动态阵列吗?

时间:2017-01-19 14:11:00

标签: c arrays dynamic-memory-allocation variable-length-array

所以我的代码是这样的:

trigger

我的问题是,我被告知这是一种分配内存的错误方法,我应该使用malloc。我应该使用用户的维度创建一个动态数组。

编辑:程序的其余部分:

jQuery("select").change(function (e) {
  var str = "";
  str = jQuery(this).find("option:selected").text();   
  jQuery(".labelChanged").text(str);
}).trigger('change')
e.preventDefault()

4 个答案:

答案 0 :(得分:6)

取决于您如何定义"更正"。这是C99以来的合法C.

但问题是,如果bmalloc太大,则数组将溢出调用堆栈。如果这是一种可能的情况,您应该更喜欢double (*array)[b] = malloc(sizeof(double[a][b])); 。与堆相比,调用堆栈通常被分配得相当小。所以这可能是建议的来源。

请注意,您仍然可以使用动态分配的数组来享受数组下标表示法:

a[i][j]

数组在一个连续的块中,VLA指针将导致test_abc.R引用正确的元素。

答案 1 :(得分:5)

不,这是完全正确且有效的方式,只要您使用支持Variable-length array的编译器版本/环境。

这是C99上的强制性功能,但在C11上再次可选。

使用VLA和"指针和内存分配器功能组合"之间的主要区别是

  • VLA是块范围的。 VLA不在作用域之外,因此它不能从函数返回并在调用者中使用,这与指针和malloc方法不同。
  • 通常,堆栈为所有主要实现分配VLA,因此大小有限。

答案 2 :(得分:4)

C编译器可以将其作为有效代码处理,尽管C11 standard made VLA support optional

主要问题是实际上你无法检查分配是否成功,特别是当大小未知时。这也是malloc/calloc

的主要优势
double (*array1)[b] = malloc(a * sizeof(*array1));
if (!array1) {
     // handle allocation failure
}

答案 3 :(得分:2)

scanf("%d %d", &a, &b);
double array1[a][b];

这在C99标准中是有效的,尽管您希望首先对输入进行一些完整性检查(即,确保两个输入都被实际读取,确保它们都不是负数,请确保它们是&#39 ;在合理的范围内,等等)。

array1是一个可变长度数组(VLA),它首先在C99中引入。从C2011开始,它们已经成为可选项,但我认为几乎所有托管的实现仍然支持它们。要确保检查__STDC_NO_VLA__宏 - 如果已定义,则实现支持VLA。

size_t a, b;
if ( scanf( "%zu %zu", &a, &b ) < 2 )
  // bail out with an error message

#if defined( __STDC_VERSION__ ) && __STDC_VERSION__ >= 199901L && !defined( __STDC_NO_VLA__ ) 

  /**
   * This implementation supports VLAs.  We need to do an additional
   * sanity check on a and b to make sure we don't allocate an
   * object too large for the stack (even though VLAs
   * don't have to be allocated on the stack, that's how many 
   * implementations choose to do it).
   */
  if ( a > SOME_MAX_LIMIT || b > SOME_MAX_LIMIT )
    // bail out with an error
  double array1[a][b];

#else  

  /**
   * This implementation does not support VLAs, so we'll have to use
   * dynamic memory allocation.  Note that memory allocated this way
   * is *not* contiguous - rows are not adjacent, so the object immediately
   * following array1[0][b-1] is not array1[1][0].  If that matters, 
   * then this won't work.  
   */
  double **array1 = malloc( sizeof *array1 * a );
  if ( array1 )
  {
    size_t i;
    for ( i = 0; i < a; i++ )
    {
      array1[i] = malloc( sizeof *array1[i] * b );
      if ( !array1[i] )
        break;
    }
    if ( i < a ) // memory allocation failure, clean up any previously allocated memory
    {
      while ( i-- )
        free( array1[i] );
      free( array1 );
      // bail out with an error here
    }
  }
  else
    // memory allocation failed, bail with an error

#endif

此时,无论我们分配哪种方式,您的代码都可以引用array1[i][j]。但是,您需要在函数末尾添加它:

#if !defined( __STDC_VERSION__ ) || __STDC_VERSION__ < 199901L || defined( __STDC_NO_VLA__ )

  for ( size_t i = 0; i < a; i++ )
    free( array1[i] );

  free( array1 );

#endif

如果我们必须使用malloc,我们就可以自行清理。

VLA与其他auto(本地)数组非常相似 - 当您退出函数时,它们的内存将被释放,因此您无法返回指向它们的指针并使指针为函数退出后有效。

由于它们的大小在运行时尚未确定,因此您无法在文件范围内使用它们(在任何函数之外),您不能将它们声明为static,并且它们不能是structunion类型的成员。

您可以将VLA与动态内存分配结合使用:

size_t a, b;
if ( scanf( "%zu %zu", &a, &b ) < 2 )
  // bail out with an error

double (*array1)[b] = malloc( sizeof *array1 * a );

您将获得一个动态分配的2D阵列,其中包含 连续的用户指定维度,并且您只受堆大小限制,而不是堆栈大小,因此您可以分配大以这种方式对象。