关于sizeof,对空指针sizeof(*p)可以吗?

本文探讨了C/C++中sizeof运算符的机制,特别是在处理空指针时的行为。通过实例说明了如何利用sizeof计算未初始化指针所指向类型的大小,以动态分配内存,避免硬编码,提高代码的灵活性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

C/C++的sizeof在动态分配内存时经常用到,但之前一直没怎么关注它的具体机制。今天在为一个复杂声明的指针分配内存时,想起来要了解一下sizeof到底是什么?

先抛个问题:

  程序运行过程中对空指针解引用,程序会直接core。那么sizeof对一个空指针“解引用”行不行?(int p=nullptr; size_t iSize=sizeof(*p))。比如如下应用场景:

  int (*p)[10] = nullptr;/*p是一个指向有10个int型元素的数组的指针*/

  如果要分配5个数组的空间,用malloc(5 * 10 * 4)吗?还是用malloc(5 * 10 * sizeof(int))?从结果来看,都能实现。但如果上述数组的类型、大小可能会变化,比如数组大小变成11,就得在声明和分配处分别修改代码,难免会改漏。一种可行的方式是用一个宏来表示数组大小。这里,我想换个方式,指针声明时明确了数组大小,所以能不能在malloc的时候用sizeof计算出指针的元素大小(即数组大小,注意此时指针是空的),从而只需要在声明时说明数组大小,避免在malloc的时候再关心数组多大?

  答案是可以。这条语句是合法的:p = (int (*)[10])malloc(5 * sizeof(*p))。这里sizeof的参数p是空指针,下面解释为什么这里的*p是合法的。

 

什么是sizeof,以及它的机制?

  sizeof的一般使用形式都是sizeof( xx ),所以sizeof是不是一个函数呢?答案是看情况。有些编程语言里,sizeof是函数,这个不细讲(因为我也不会几种编程语言)。在C/C++里,sizeof不是函数,是一个内置的运算符或操作符,跟“ + - * / ”一样的运算符。sizeof可以返回一个类型或者对象所占用的内存空间字节数。

  而且关键的,sizeof的参数是类型(如sizeof(int)),或者是具体某个变量的类型(如int* p, sizeof(*p),这里的参数是int*)。sizeof是编译器在编译阶段解析并完成计算的,运行阶段并没有sizeof。所以对一个空指针执行sizeof(*p),实际上等价于对p指向的对象的类型作sizeof,而且是在编译阶段就完成了,没解引用,所以是合法的。

 

  这里分享个《C专家编程》第2章的例子:

  a = N * sizeof * q;/*这里有几个乘号?答案是1个。sizeof操作符把指针q指向的东西作为操作数(即*q)*/

  有意思的是上面这个例子,sizeof的参数没用括号,在函数调用里这显然不合法,但sizeof是操作符就是任性。当sizeof的操作数是类型名时,两边必须加括号,但操作数如果是变量则可以不加括号。

  apple = sizeof(int) * a;/*这个例子书上没给答案。事实上,这里先计算sizeof(int),然后再乘以a的值*/

 

  最后回到开篇的问题,给p分配内存的另一种方式:

  typedef int pPtr[10];/*为了方便我们用自定义类型*/

  pPtr* p=nullptr;/*相当于int (*p)[10] = nullptr;*/

  p = (int (*)[10])malloc(5 * sizeof(*p))。

  这里sizeof对空指针操作了*p,实际并未解引用,而是在编译阶段计算出指针p指向的类型的大小,所以是合法的。

  

  

转载于:https://www.cnblogs.com/JoZSM/p/9833203.html

### C/C++ 中 `sizeof` 运算符用于解引用后的数据类型 当使用 `sizeof` 对指针进行解引用时,实际上是在获取该指针所指向对象的大小。对于不同类型的指针,其解引用的结果会有所不同。 #### 基本语法与示例 假设有一个整型数组和一个指向此数组的指针: ```cpp int array[10]; int *ptr = array; ``` 此时可以通过如下方式来查看单个元素以及整个数组的大小: - 单个元素的大小: ```cpp printf("Size of single element: %lu\n", sizeof(*ptr)); // 输出 int 类型的大小 ``` - 整个数组的大小(通过指针访问): 需要注意的是直接对指针应用 `sizeof` 只能得到指针本身的大小而不是它指向的内容。为了获得实际内容的大小,可以先计算出总长度再乘以每个元素的大小: ```cpp size_t num_elements = /* 计算元素数量 */; printf("Total size of the pointed-to data: %zu bytes\n", num_elements * sizeof(*ptr)); ``` 针对更复杂的多维数组或自定义结构体的情况,同样适用上述原则。例如给定一个多维动态分配的 double 数组并尝试测量它的尺寸: ```cpp double (*arr)[3][6]; // 定义了一个指向三维数组的指针 // ... 初始化 arr ... printf("Size of dereferenced pointer to multi-dimensional array: %zu\n", sizeof(**arr)); // 获取最内层元素大小 [^1] ``` 这里需要注意的是,一旦涉及到复杂的数据结构如二维或多维数组、结构体等,应当确保正确解析每一级间接寻址关系以便准确求得所需部分的实际占用空间。 另外值得注意的一点是,即使是一个空类的对象也会占有一定量的存储单元,默认情况下至少为一字节以保证不同的对象拥有独一无二的地址[^2]。不过这并不影响到指针本身作为变量存在的时候总是固定占据特定数目的字节(通常取决于平台架构, 如32位系统上通常是4字节)。 最后关于野指针的问题,由于它们可能指向任意位置甚至是非法区域内的内存,因此对其进行任何形式的操作都是危险且不可预测的,包括试图读取其所指向的位置的信息或是调用 `sizeof` 来查询这些信息都可能导致程序崩溃或其他异常行为[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值