用c语言获取数组大小,无法理解输出



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

#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 %lun",sizeof(ptr)/sizeof(ptr[0])); /* Get the size of memory alloctaed. Should be the same as N?*/
    printf ("Size of your normal arrays is %lun",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。那么,如果我不知何故"忘记"了它,如何获得错位数组的大小?

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

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

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


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

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

虽然sizeof()可以像您期望的那样使用定长和变长数组,但它不知道malloc() 'ed数组的大小。

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

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

参见C常见问题解答7.27和7.28。

总而言之,如果您需要以可移植的方式了解堆分配数组的大小,那么您必须自己跟踪该大小。

如果只有指向数组第一个元素的指针,则无法在运行时获得数组的大小。在C语言中根本没有任何结构允许您这样做。你必须自己记录长度。

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

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

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

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

关于sizeof要记住的是,它是一个编译时操作符1;它根据操作数的类型返回字节数。

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

一般来说,你不能根据指针本身的值来确定指针指向的内存块有多大;这些信息必须单独跟踪。

风格单元:写malloc调用的首选方式是

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

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

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


1sizeof应用于可变长度数组时,此规则将出现例外;因为数组的大小直到运行时才确定,所以应用于VLA的sizeof运算符将在运行时计算。

2注意,这是而不是c++中的;强制转换是必需的,但如果你正在编写c++,你应该使用newdelete,而不是mallocfree。同样,这只适用于C89;旧版本的C有malloc返回char *而不是void *,所以对于那些版本,强制转换必需的。除非您正在使用非常旧的实现(例如运行旧版本VMS的旧VAX mini),否则这应该不是问题。

相关内容

  • 没有找到相关文章

最新更新