【问题标题】:Using sizeof with a dynamically allocated array将 sizeof 与动态分配的数组一起使用
【发布时间】:2011-02-13 11:04:18
【问题描述】:

gcc 4.4.1 c89

我有以下代码sn-p:

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

 char *buffer = malloc(10240);
 /* Check for memory error */
 if(!buffer)
 {
    fprintf(stderr, "Memory error\n");
    return 1;
 }
 printf("sizeof(buffer) [ %d ]\n", sizeof(buffer));

但是,sizeof(buffer) 总是打印 4。我知道 char* 只有 4 个字节。但是,我已经分配了 10kb 的内存。那么大小不应该是10240吗?我想知道我在这里思考吗?

非常感谢您的任何建议,

【问题讨论】:

  • 在大多数情况下,C 编译器(对于任何版本)都不知道函数 malloc 实际做什么或用于做什么。它只知道它接受一个无符号整数 (size_t) 并返回一个 void 指针。它可以使用它的参数来播种随机数生成器并将随机数转换为(void *) 以供编译器关心,因此编译器无法知道指向的内存大小。

标签: c sizeof


【解决方案1】:

sizeof 不适用于动态分配(C99 中有一些例外)。你在这里使用sizeof 只是给你指针的大小。此代码将为您提供所需的结果:

char buffer[10240];
printf("sizeof(buffer) [ %d ]\n", sizeof(buffer));

如果malloc() 成功,则指向的内存至少与您要求的一样大,因此没有理由关心它分配的实际大小。

另外,您分配了 10 kB,而不是 1 kB。

【讨论】:

  • 这段代码有点危险:它在栈上分配缓冲区,而不是堆上。如果您让指向此缓冲区的任何指针从声明它的函数中泄漏出来,那么您将面临堆栈损坏(取决于您的程序运行多长时间、堆损坏和/或分段错误)。
  • @Anon - 这并不危险,它只是以不同的方式解决问题。 OP 对从函数传回缓冲区没有任何要求。
  • OP 的问题到底是什么?在我看来,它正在跟踪堆分配结构的大小。建议 OP 使用堆栈分配的结构并不是解决该问题的方法。
【解决方案2】:

您要的是 char* 的大小,实际上是 4,而不是缓冲区的大小。 sizeof 运算符不能返回动态分配缓冲区的大小,只能返回编译时已知的静态类型和结构的大小。

【讨论】:

  • sizeof 可以返回 C99 中可变长度数组的动态缓冲区的大小。
  • @Carl - VLA 不是动态的。它们是“可变长度”,因为它们的长度可以在运行时计算,但不是“可变长度”,因为它们的长度可以改变。它们仍然是基于堆栈的数组,这就是为什么 sizeof 被定义为适用于它们的原因。
  • @robUK - 使用struct { char *buf; size_t len; }; 自己跟踪它。或者使用别人的字符串库。或者严格遵守“始终通过缓冲区传递长度”规则(无论如何您都应该这样做)。
  • @robUK,如果没有其他可能告诉您的操作系统/库功能,就无法知道malloc() 实际给了您多少内存。这些将取决于操作系统/编译器。
  • C99 VLA 在许多情况下是最合适的选择,并且使用它们比使用旧的非标准 alloca() 好得多。如果没有人使用它们,支持将永远不会改善。
【解决方案3】:

如果需要,您可以跟踪内存的大小。 malloc 返回的内存只是指向“未初始化”数据的指针。 sizeof 运算符仅适用于 buffer 变量。

【讨论】:

  • 运行时环境肯定知道分配缓冲区的大小(因为free(void*)不要求大小),那我们为什么要自己跟踪呢?
  • 底层内存管理代码几乎肯定有大小,除非它有一些不需要大小的神奇释放算法。但该信息并未公开。
  • 数据不暴露是否有原因?
  • 不是这样定义的。 This answer 讨论它。
【解决方案4】:

将您的sizeof 替换为malloc_usable_size(手册页表明这是不可移植的,因此可能不适用于您的特定C 实现)。

【讨论】:

  • malloc_usable_size() 非常不便携。我在 OS X Leopard 上没有它。无论如何,首先依赖它是一个糟糕的想法(如手册中所述)。
  • 注意:如果您不关心可移植性并且在 OSX 上(或者其他人不关心并且您坚持移植到 OSX)来自 的 malloc_size 是您的适合这份工作的人。
【解决方案5】:

没有。 bufferchar *。它是指向char 数据的指针。指针仅占用 4 个字节(在您的系统上)。

它指向 10240 字节的数据(顺便说一下,它不是 1Kb。更像是 10Kb),但是指针不知道这一点。考虑:

int a1[3] = {0, 1, 2};
int a2[5] = {0, 1, 2, 3, 4};

int *p = a1;
// sizeof a1 == 12 (3 * sizeof(int))
// but sizeof p == 4
p = a2
// sizeof a2 == 20
// sizeof p still == 4

这是数组和指针的主要区别。如果不是这样,sizeof p 会在上面的代码中发生变化,这对于编译时常量没有意义。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-12
    • 2015-08-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多