在C中获取数组大小无法理解输出

时间:2011-12-13 19:43:45

标签: c arrays malloc

我很好奇为什么我在代码中遇到以下行为。

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


int main(int argc, char *argv[])
{
    int M=24;
    int arr[M];
    int N=24;
    int* ptr=(int*) malloc(sizeof(int)*N); /*Allocate memory of size N  */

    printf("Size of your malloced array is %lu\n",sizeof(ptr)/sizeof(ptr[0])); /* Get the size of memory alloctaed. Should be the same as N?*/

    printf ("Size of your normal arrays is %lu\n",sizeof(arr)/sizeof(arr[0])); /* Ditto  */

    free(ptr);

    return 0;
}

输出

Size of your malloced array is 2
Size of your normal arrays is 24

我原以为两个地方的输出都是24。然后如何获得malloced数组的大小如果我以某种方式“忘记”了它?

当然,指针ptr将包含一些关于malloced数组大小的信息,因为当我们调用free(ptr)时,它将释放数组只是malloced

6 个答案:

答案 0 :(得分:7)

当您在指针上使用sizeof()时,您将获得指针的大小。不是分配的数组的大小。在你的情况下,一个指针可能是8个字节而int是4个字节,因此为什么你得到2个。

简而言之,您无法获得已分配数组的大小。你需要自己跟踪它。


编辑:请注意,某些编译器实际上支持此功能作为扩展名:

例如,MSVC支持_msize()http://msdn.microsoft.com/en-us/library/z2s077bc.aspx

答案 1 :(得分:3)

虽然sizeof()与固定长度和可变长度数组一样有效,但它对malloc()'ed数组的大小一无所知。

当应用于指针时,sizeof()只返回指针的大小。

更一般地说,给定指向malloc()'ed块的指针,没有标准的方法来发现该块的大小。

请参阅C常见问题解答7.277.28

总之,如果您需要以可移植的方式知道堆分配数组的大小,您必须自己跟踪该大小。

答案 2 :(得分:1)

如果只有指向数组(的第一个元素)的指针,则无法在运行时获取数组的大小。在C中根本没有允许你这样做的结构。你必须自己跟踪长度。

如果碰巧有一个数组而不是一个指针,那么你可以找到它的长度,但不能找到指向数组元素的指针。

在您的代码中,ptr是一个指针,因此您无法找到它指向的数组的长度。另一方面,arr是一个数组,因此您可以使用sizeof(arr)/sizeof(arr[0])找出其长度。

答案 3 :(得分:0)

指针的大小在32位计算机上为4个字节,在64位计算机上为8个字节。我猜你在64位机器上工作,因为int的大小是4,你得到sizeof(ptr)/sizeof(ptr[0])是2。

答案 4 :(得分:0)

正如this other question指出的那样,没有可移植的方式来获得动态数组的大小,因为malloc可能会分配比请求更多的内存。此外,管理malloc请求取决于操作系统。例如,* nix将调用sbrk并将请求存储在某处。因此,当您调用sizeof(ptr)时,它会返回指针的大小而不是数组的大小。另一方面,如果您的数组是固定的,那么它的大小是在编译时确定的,因此编译器能够用固定数组的大小替换sizeof(arr),从而为您提供“正确”的大小。

答案 5 :(得分:0)

关于sizeof要记住的事情是它是编译时运算符 1 ;它返回基于操作数的类型的字节数。

arr的类型为int [24],因此sizeof arr将评估存储24个int值所需的字节数。 ptr的类型为int *,因此sizeof ptr将计算为存储单个int *值所需的字节数。由于这是在编译时发生的,因此sizeof无法知道ptr指向哪个内存块或者它有多大。

通常,您无法根据指针值本身确定指针指向的内存块大小;必须单独跟踪该信息。

Stylistic nit:编写malloc调用的首选方式是

int *ptr = malloc(sizeof *ptr * N);

在C中,您不需要将malloc的结果强制转换为目标指针类型 2 ,如果您忘记包含{{{},那么这样做可能会掩盖有用的诊断1}}或者在范围内没有stdlib.h的原型。

其次,请注意我将表达式malloc作为操作数传递给*ptr而不是sizeof。如果您更改(int)的类型但忘记更改相应ptr调用中的类型,则可以最大限度地减少错误。这是有效的,因为malloc不会尝试评估操作数(意味着它不会尝试取消引用sizeof);它只计算类型

<小时/> 1 ptr应用于可变长度数组时,会出现此规则的例外情况;由于直到运行时才确定数组的大小,因此将在运行时评估应用于VLA的sizeof运算符。

2 请注意,这是不是 C ++中的情况;需要演员,但如果您正在编写C ++,那么您应该使用sizeofnew而不是deletemalloc。此外,这仅限于C89;旧版本的C有free返回malloc而不是char *,因此对于这些版本,需要使用 。除非您正在使用非常旧的实现(例如运行古老版本VMS的旧VAX mini),否则这应该不是问题。