所以我对如何创建一个函数有点困惑,该函数将返回指向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的指针数组的指针? 一些帮助理解这将是美好的。谢谢!
答案 0 :(得分:2)
那么,如果我给出的这个解释是正确的,是不是内存被分配给一个指向int的指定的指定数量的指针,而不是实际的整数?
不,您问malloc
aDefinedSize * sizeof(int)
字节,不
aDefinedSize * sizeof(int *)
个字节。这是你得到的内存大小,类型取决于用于访问内存的指针。
因此,isnt myInt指向一个指向int的指针数组?
不,因为你把它定义为int *
,指向一个指针。
当然,指针不知道分配的内存有多大,但只能指向适合那里的第一个 int
。作为程序员,你需要跟踪大小。
请注意you shouldn't use that explicit typecast。 malloc
返回void *
,可以静默分配给任何指针,如下所示:
int* myInt = malloc(aDefinedSize * sizeof(int));
指针上的算术在指向类型的步幅中起作用,即使用int *p
,p[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中,您要记住数组只是内存中的地址,加上长度和对象类型。当您将它作为参数传递给函数或函数的返回值时,长度会被遗忘,并且它与第一个元素的地址可互换地处理。这导致在读取或写入缓冲区末尾的程序中出现许多安全漏洞。
在大多数上下文中,数组的名称会自动转换为其第一个元素的地址,因此您可以将数组或指针传递给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更具可重复性,当你调试并查看指针时,很明显它是零,而指针是垃圾就不会立即显而易见。