简体   繁体   English

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

[英]Getting array size in C. Cannot understand output

I am curious why I am getting the following behaviour in my code.我很好奇为什么我的代码会出现以下行为。

#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;
}

The output is输出是

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

I would have thought the output would be 24 in both places.我原以为这两个地方的输出都是24 How then does one get the size of the malloced array If somehow I have "forgotten" it?如果不知何故我“忘记”了它,那么如何获得 malloced 数组的大小?

Surely the pointer ptr will contain some information about the size of the malloced array since when we call free(ptr) it will release the array just malloced当然,指针ptr将包含一些关于 malloced 数组大小的信息,因为当我们调用free(ptr) ,它将释放刚刚 malloced 的数组

When you use sizeof() on a pointer, you get the size of the pointer.当您在指针上使用sizeof()时,您将获得指针的大小。 Not the size of the allocated array.不是分配数组的大小。 In your case, a pointer is probably 8 bytes and an int is 4 bytes, hence why you get 2.在你的情况下,一个指针可能是 8 个字节,一个int是 4 个字节,因此你得到 2。

In short, you can't get the size of an allocated array.简而言之,您无法获得已分配数组的大小。 You need to keep track of it yourself.你需要自己跟踪它。


EDIT : Note that some compilers do actually support this functionality as an extension:编辑:请注意,某些编译器确实支持将此功能作为扩展:

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

While sizeof() works as you'd expect with fixed-length and variable-length arrays, it doesn't know anything about the sizes of malloc() 'ed arrays.虽然sizeof()对固定长度和可变长度数组如您所期望的那样工作,但它对malloc() ed 数组的大小一无所知。

When applied to a pointer, sizeof() simply returns the size of the pointer.当应用于指针时, sizeof()仅返回指针的大小。

More generally, given a pointer to a malloc() 'ed block, there's no standard way to discover the size of that block.更一般地说,给定一个指向malloc() 'ed 块的指针,没有标准的方法来发现该块的大小。

See C FAQ questions 7.27 and 7.28 .参见 C FAQ 问题7.277.28

In summary, if you need to know the size of a heap-allocated array in a portable manner, you have to keep track of that size yourself.总之,如果您需要以可移植的方式知道堆分配数组的大小,则必须自己跟踪该大小。

You cannot obtain, at runtime, the size of an array if you only have a pointer to (the first element of) the array.如果您只有一个指向数组(的第一个元素)的指针,则您无法在运行时获得数组的大小。 There are no constructs at all in C that allow you to do this. C 中根本没有任何构造允许您执行此操作。 You have to keep track of the length yourself.你必须自己记录长度。

If you happen to have an array rather than a pointer then you can find its length, but not for a pointer to an element of the array.如果您碰巧有一个数组而不是指针,那么您可以找到它的长度,但不能找到指向数组元素的指针。

In your code, ptr is a pointer and so you cannot find out the length of the array to which it points.在您的代码中, ptr是一个指针,因此您无法找出它指向的数组的长度。 On the other hand, arr is an array and so you can find out its length with sizeof(arr)/sizeof(arr[0]) .另一方面, arr是一个数组,因此您可以使用sizeof(arr)/sizeof(arr[0])找出它的长度。

The size of a pointer is 4 bytes on 32-bit machines and 8 bytes on 64-bit machines.指针的大小在 32 位机器上为 4 个字节,在 64 位机器上为 8 个字节。 I guess you work on a 64-bit machine since the size of an int is 4, and you got that sizeof(ptr)/sizeof(ptr[0]) is 2.我猜你在 64 位机器上工作,因为 int 的大小是 4,你得到sizeof(ptr)/sizeof(ptr[0])是 2。

As this other question points out, there is no portable way getting the size of a dynamic array, since malloc may allocate more memory than requested.正如另一个问题所指出的那样,没有可移植的方法来获取动态数组的大小,因为malloc可能分配的内存比请求的多。 Furthermore managing malloc requests is up to the operating system.此外,管理 malloc 请求取决于操作系统。 For instance *nix would calls sbrk and store the requests somewhere.例如 *nix 会调用sbrk并将请求存储在某处。 So, when you call sizeof(ptr) it returns the size of the pointer and not the size of the array.因此,当您调用sizeof(ptr)它返回指针的大小而不是数组的大小。 On the other hand, if your array is fixed, the size of it is determined at compile time, so the compiler is able to replace sizeof(arr) with the size of the fixed array, thus providing you the "correct" size.另一方面,如果您的数组是固定的,它的大小是在编译时确定的,因此编译器能够用固定数组的大小替换sizeof(arr) ,从而为您提供“正确”的大小。

The thing to remember about sizeof is that it is a compile-time operator 1 ;关于sizeof需要记住的是,它是一个编译时操作符1 it returns the number of bytes based on the type of the operand.它根据操作数的类型返回字节数。

The type of arr is int [24] , so sizeof arr will evaluate to the number of bytes required to store 24 int values. arr的类型是int [24] ,因此sizeof arr将计算为存储 24 个int值所需的字节数。 The type of ptr is int * , so sizeof ptr will evaluate to the number of bytes required to store a single int * value. ptr的类型是int * ,因此sizeof ptr将计算为存储单个int *值所需的字节数。 Since this happens at compile time, there's no way for sizeof to know what block of memory ptr is pointing to or how large it is.由于这是在编译时发生的,因此sizeof无法知道ptr指向的内存块或它有多大。

In general, you cannot determine how large a chunk of memory a pointer points to based on the pointer value itself;通常,您无法根据指针值本身确定指针指向的内存块有多大; that information must be tracked separately.该信息必须单独跟踪。

Stylistic nit: a preferred way to write the malloc call is风格 nit:编写malloc调用的首选方法是

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

In C, you do not need to cast the result of malloc to the target pointer type 2 , and doing so can potentially mask a useful diagnostic if you forget to include stdlib.h or otherwise don't have a prototype for malloc in scope.在 C 中,您不需要将malloc的结果malloc转换为目标指针类型2 ,如果您忘记包含stdlib.h或在范围内没有malloc原型,那么这样做可能会掩盖有用的诊断信息。

Secondly, notice that I pass the expression *ptr as the operand to sizeof rather than (int) .其次,请注意我将表达式*ptr作为操作数传递给sizeof而不是(int) This minimizes bugs in the event you change the type of ptr but forget to change the type in the corresponding malloc call.如果您更改了ptr的类型但忘记在相应的malloc调用中更改类型,这可以最大限度地减少错误。 This works because sizeof doesn't attempt to evaluate the operand (meaning it doesn't attempt to dereference ptr );这是有效的,因为sizeof不会尝试评估操作数(意味着它不会尝试取消引用ptr ); it only computes its type .它只计算它的类型


1 The exception to this rule occurs when sizeof is applied to a variable-length array; 1sizeof应用于变长数组时,会出现此规则的例外情况; since the size of the array isn't determined until runtime, a sizeof operator applied to a VLA will be evaluated at runtime. 由于数组的大小直到运行时才确定,因此将在运行时评估应用于 VLA 的sizeof运算符。

2 Note that this is not the case in C++; 2请注意,在 C++ 中并非如此; a cast is required, but if you're writing C++ you should be using new and delete instead of malloc and free anyway. 强制转换是必需的,但如果您正在编写 C++,则无论如何都应该使用newdelete而不是mallocfree Also, this is only true since C89; 此外,这仅在 C89 之后才成立; older versions of C had malloc return char * instead of void * , so for those versions the cast was required. 老版本的C具有malloc返回char * ,而不是void * ,所以对于那些版本所需的铸件。 Unless you are working on a very old implementation (such as an old VAX mini running an ancient version of VMS), this shouldn't be an issue. 除非您正在使用非常旧的实现(例如运行旧版 VMS 的旧 VAX mini),否则这应该不是问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM