(int *)在c中动态分配int数组时

时间:2017-04-09 12:57:46

标签: c arrays pointers memory-management

所以我对如何创建一个函数有点困惑,该函数将返回指向C 中的int数组的指针。我明白你做不到:

int* myFunction() {
  int myInt[aDefinedSize];
  return myInt; }

因为这会返回一个指向局部变量的指针。 所以,我想到了这个:

int* myFunction(){
  int* myInt = (int) malloc(aDefinedSize * sizeof(int));
  return myInt; }

这给出了错误:从指针强制转换为不同大小的整数 这意味着要使用它,这有效:

int* myFunction(){
  int* myInt = (int*) malloc(aDefinedSize * sizeof(int));
  return myInt; }

我感到困惑的是: 我解释了malloc之前的(int *)来执行此操作:它告诉编译器所分配的内存的数据类型是什么。例如,当您逐步执行数组并且编译器需要知道要递增多少字节时,就会使用它。 那么,如果我给出的这个解释是正确的,是不是内存被分配给一个指向int的指定的指定数量,而不是实际的整数?因此,isnt myInt指向一个指向int的指针数组的指针? 一些帮助理解这将是美好的。谢谢!

3 个答案:

答案 0 :(得分:2)

  

那么,如果我给出的这个解释是正确的,是不是内存被分配给一个指向int的指定的指定数量的指针,而不是实际的整数?

不,您问malloc aDefinedSize * sizeof(int)字节, aDefinedSize * sizeof(int *)个字节。这是你得到的内存大小,类型取决于用于访问内存的指针。

  

因此,isnt myInt指向一个指向int的指针数组?

不,因为你把它定义为int *,指向一个指针。

当然,指针不知道分配的内存有多大,但只能指向适合那里的第一个 int。作为程序员,你需要跟踪大小。

请注意you shouldn't use that explicit typecastmalloc返回void *,可以静默分配给任何指针,如下所示:

int* myInt = malloc(aDefinedSize * sizeof(int));

指针上的算术在指向类型的步幅中起作用,即使用int *pp[3]*(p+3)相同,这意味着大致“转到{ {1}},以字节为单位前进三次p,并访问该位置“sizeof(int)将是一个指向指向int的指针,并且可能指向一个指针数组。

答案 1 :(得分:0)

malloc分配一个字节数组并返回指向第一个字节的void*。如果分配失败,请NULL

要将此数组视为不同数据类型的数组,必须将指针强制转换为该数据类型。

在C中,void*隐式转换为任何数据指针类型,因此不需要显式转换:

int* allocateIntArray(unsigned number_of_elements) {
    int* int_array = malloc(number_of_elements * sizeof(int)); // <--- no cast is required here.
    return int_array;
}

答案 2 :(得分:-1)

C

中的数组

在C中,您要记住数组只是内存中的地址,加上长度和对象类型。当您将它作为参数传递给函数或函数的返回值时,长度会被遗忘,并且它与第一个元素的地址可互换地处理。这导致在读取或写入缓冲区末尾的程序中出现许多安全漏洞。

在大多数上下文中,数组的名称会自动转换为其第一个元素的地址,因此您可以将数组或指针传递给memmove(),但有一些例外情况,它也有一个长度很重要。数组上的sizeof()运算符是数组中的字节数,但sizeof()指针是指针变量的大小。因此,如果我们声明int a[SIZE];,则sizeof(a)sizeof(int)*(size_t)(SIZE)相同,而sizeof(&a[0])sizeof(int*)相同。另一个重要的一点是,编译器通常可以在编译时告诉数组访问是否超出范围,而它不知道对指针的哪些访问是安全的。

如何返回数组

如果你想返回一个指向同一个静态数组的指针,并且每次调用该函数都可以得到相同的数组,你可以这样做:

#define ARRAY_SIZE 32U

int* get_static_array(void)
{
  static int the_array[ARRAY_SIZE];
  return the_array;
}

您必须在静态数组上调用free()

如果你想创建一个动态数组,你可以这样做,虽然这是一个人为的例子:

#include <stdlib.h>

int* make_dynamic_array(size_t n)
// Returns an array that you must free with free().
{
  return calloc( n, sizeof(int) );
}

当您不再需要动态数组时,必须使用free()释放动态数组,否则程序将泄漏内存。

实用建议

对于任何简单的事情,你实际上会写:

int * const p = calloc( n, sizeof(int) );

除非由于某种原因,数组指针会改变,例如:

int* p = calloc( n, sizeof(int) );
/* ... */
p = realloc( p, new_size );

我建议calloc()超过malloc()作为一般规则,因为它会将内存块初始化为零,而malloc()会保留未指定的内容。这意味着,如果您有一个读取未初始化内存的错误,使用calloc()将始终为您提供可预测,可重现的结果,并且使用malloc()每次都会给您不同的未定义行为。特别是,如果你分配一个指针,然后在0是指针的陷阱值(如典型的桌面CPU)的实现上取消引用它,calloc()创建的指针将立即给你一个段错误,虽然由malloc()创建的垃圾指针可能出现,但会损坏内存的任何部分。追踪这种错误要困难得多。在调试器中也更容易看到内存是否被清零,而不是任意值是有效还是垃圾。

进一步讨论

在评论中,一个人反对我使用的一些术语。特别是,C ++提供了几种不同的方法来返回对数组的引用,以保留有关其类型的更多信息,例如:

#include <array>
#include <cstdlib>

using std::size_t;

constexpr size_t size = 16U;
using int_array = int[size];

int_array& get_static_array()
{
  static int the_array[size];
  return the_array;
}

std::array<int, size>& get_static_std_array()
{
  static std::array<int, size> the_array;
  return the_array;
}

因此,一个评论者(如果我理解正确的话)对象是“返回一个数组”只应该 引用这种函数。我比这更广泛地使用了这个短语,但我希望能澄清你在C中return the_array;时会发生什么。你得到一个指针。与您的相关性是您丢失了有关数组大小的信息,这使得在C中编写安全错误非常容易,这些错误读取或写入超过为数组分配的内存块。

还有一些异议,我不应该告诉你,使用calloc()而不是malloc()来动态分配包含指针的结构和数组将使几乎所有现代CPU分段如果你在初始化它们之前取消引用这些指针。对于记录:绝对不是所有的CPU都不是这样,所以它不是可移植的行为。有些CPU不会陷阱。一些旧的大型机将捕获除零之外的特殊指针值。但是,当我在桌面或工作站上编码时,它会非常方便。即使你运行其中一个异常,至少你的指针每次都会有相同的值,这应该使bug更具可重复性,当你调试并查看指针时,很明显它是零,而指针是垃圾就不会立即显而易见。