当前位置: 首页 > news >正文

C++指针笔试题1

分析 char*(*p)[3][6]; 的类型

  • p 是一个指针,它指向的类型是 char*[3][6](一个 3 行 6 列、元素为 char* 的二维数组)。

计算 sizeof(p)

p 是指针,在 32 位系统中,指针的大小固定为 4 字节,所以 sizeof(p) = 4

计算 sizeof(*p)

*p 表示 p 指向的对象,即 char*[3][6] 类型的二维数组。

  • 这个二维数组有 3 行、6 列,每个元素是 char*(大小为 4 字节)。
  • 数组总大小 = 行数 × 列数 × 每个元素的大小,即 3 × 6 × 4 = 72,所以 sizeof(*p) = 72

计算 sizeof(**p)

**p 表示二维数组中第一行的数组(类型为 char*[6],即 1 行 6 列、元素为 char* 的一维数组)。

  • 该一维数组有 6 个元素,每个元素是 char*(大小为 4 字节)。
  • 数组总大小 = 列数 × 每个元素的大小,即 6 × 4 = 24,所以 sizeof(**p) = 24

为什么会有 *p 和 **p

指针的解引用(*)本质是 “获取指针指向的对象”,而对象的类型决定了 “是否可以继续解引用”:

  1. p 的类型char*(*)[3][6](指向二维数组的指针)p 存储的是 “整个二维数组的起始地址”,解引用 *p 得到的是 p 指向的二维数组本身(类型为 char*[3][6])。注意:这个二维数组虽然是 “实体”,但在多数语境下会隐式退化—— 作为 “由多个行数组组成的集合”,它会退化为指向 “第一行数组” 的指针(类似一维数组名退化为指向首元素的指针)。其实,退化是常态,** 只要 *p 离开 “不会退化的特殊语境”(如 sizeof(*p)&*p),就会自动退化 **。

  2. *p 的类型char*[3][6](二维数组)→ 退化后为 char*(*)[6](指向行数组的指针)当 *p 退化为 “指向第一行数组的指针” 时,对其再次解引用(**p),得到的就是 这个指针指向的对象—— 即二维数组的第一行数组(类型为 char*[6])。

最终输出

代码会依次输出:

plaintext

4
72
24

备注:

1、

#include <stdio.h>int main() {int arr[5] = {1,2,3,4,5};int (*p)[5] = &arr;  // 指向数组的指针(数组指针)int* q = arr;        // 指向int的指针(普通指针)// 1. 指针本身的sizeof:结果相同printf("sizeof(p) = %zu\n", sizeof(p));  // 32位系统输出4,64位输出8printf("sizeof(q) = %zu\n", sizeof(q));  // 结果和上面完全一致// 2. 指针指向对象的sizeof:结果不同(类型差异的体现)printf("sizeof(*p) = %zu\n", sizeof(*p));  // *p是整个数组,大小=5*4=20printf("sizeof(*q) = %zu\n", sizeof(*q));  // *q是单个int,大小=4return 0;
}

2、

1. 数组名 arr 不是指针,而是 “数组类型的标识符”

数组名代表的是整个数组的实体,而非指针变量。例如:

int arr[5];  // arr 是 "int[5]" 类型的数组,不是指针
  • 指针是独立的变量,存储内存地址,可被赋值修改(如 int* p; p = &x;);
  • 数组名是 “常量标识符”,不能被赋值(如 arr = &x; 会报错),它与数组在内存中的存储绑定,本身不占用额外内存(指针变量则占用内存)。

2. 数组名可以用 sizeof,因为 sizeof 识别数组类型

sizeof(arr) 计算的是整个数组的总字节数,这是因为 sizeof 是编译期运算符,能直接识别数组的完整类型(如 int[5]):

int arr[5];
printf("%zu", sizeof(arr));  // 输出 20(5个int,每个4字节)
  • 若 arr 是指针,sizeof(arr) 会输出指针大小(如 8 字节),但实际输出的是数组总大小,证明 arr 不是指针。
  • 只有数组名作为 sizeof 的操作数时,才不会退化(保持数组类型),这是 sizeof 对数组的特殊处理。

3. 数组名 “退化” 为指针的原因:简化数组访问

在多数语境下(除 sizeof(arr)&arr 等少数情况),数组名会隐式转换为指向首元素的指针(类型为 元素类型*),这是 C 语言设计的便利性:

int arr[5];
int* p = arr;  // 等价于 p = &arr[0],arr 退化为 int* 类型

退化的目的是方便通过指针访问数组元素(如 arr[i] 等价于 *(arr + i)),避免每次都手动写 &arr[0]

常见的退化场景:

  • 数组名作为函数参数(如 void func(int arr[]) 中,arr 实际是 int* 指针);
  • 数组名参与指针运算(如 arr + 1 指向 arr[1]);
  • 数组名赋值给同类型指针变量(如上面的 p = arr)。

4. 数组名arr只占编译时内存不占运行时内存。

  • 若问 “编译阶段 arr 是否占内存”:,它作为编译器符号表的一条记录,占用编译器进程的内存(但这是编译器的工作内存,与你的程序无关)。
  • 若问 “程序运行时 arr 是否占内存”:,此时只有数组的实体数据在内存中,arr 这个名字已被编译器转换为具体地址,不再以独立形式存在。

5.若 q 是 int* 类型,&q 的类型就固定为 int**,不能用 int* 类型的 r 接收,否则编译器会报错(类型不匹配)。

6.int *p[2][5] 和 int (*p)[2][5] —— 完全不一样

这两个声明的本质、p 的类型、用途都截然不同,核心区别是 p 是 “数组” 还是 “指针”。

1. int *p[2][5] —— 二维数组(元素为 int*
  • 结合逻辑[] 的优先级高于 *,所以 p 先与 [2][5] 结合,声明为 “2 行 5 列的二维数组”;数组的每个元素是 int*(指向 int 的指针)。
  • 类型p 是 int*[2][5] 类型(二维数组,元素为一级指针)。
  • 内存占用:数组大小 = 行数 × 列数 × 每个元素大小(如 64 位系统中,int* 占 8 字节,总大小 = 2×5×8 = 80 字节)。
  • 示例:可存储 10 个 int* 指针,每个指针指向一个 int 变量或数组。

[] 先绑定 p 确定其为数组,* 再限定数组元素的指针属性,int 最后限定指针指向的类型

2. int (*p)[2][5] —— 三维数组指针(指向 int[2][5] 类型的二维数组)
  • 结合逻辑:括号 () 强制 p 先与 * 结合,声明为 “指针”;指针指向的类型是 int[2][5](2 行 5 列的二维数组)。
  • 类型p 是 int (*)[2][5] 类型(指向二维数组的指针,属于 “数组指针”)。
  • 内存占用:指针本身的大小(与系统位数相关,64 位系统占 8 字节,32 位占 4 字节),与指向的数组大小无关。
  • 示例:需指向一个已存在的 int[2][5] 二维数组(如 int arr[2][5]; p = &arr;)。

7.int *pint (*p) 和 int* p 这三种写法中,int *p 和 int* p 完全等价,而 int (*p) 与前两者在 “语法效果上一致(均为一级指针),但括号冗余且不常用”—— 核心区别仅在于 * 与 int/p 的排版方式,以及是否存在冗余括号,本质都是 “声明一个指向 int 类型的一级指针 p”。

1. 先明确:C/C++ 中 * 是 “跟随变量” 的,而非 “跟随类型”

首先要纠正一个常见误区:int* 不是一个 “整体类型”(虽然我们常口头说 “int* 类型的指针”),在语法层面,* 是 “绑定到变量名” 的运算符。比如 int* p1, p2; 实际声明的是:p1 是 int* 指针,p2 是普通 int 变量 —— 因为 * 只绑定到 p1,没绑定到 p2。这也是为什么 int *p* 靠近 p)和 int* p* 靠近 int)在语法上完全等价:无论 * 排版在哪里,它最终都是与变量 p 结合,声明 p 是指针。

2. 逐一分析三种写法
(1)int *p 和 int* p —— 完全等价
  • 核心逻辑:两者都是声明 “变量 p 是指向 int 类型的一级指针”,唯一区别是 * 的排版位置(靠近 p 还是靠近 int)。
  • 编译效果:编译器会将两者解析为完全相同的代码,无任何区别。
  • 示例
    int a = 10;
    int *p1 = &a;  // 正确,p1 是 int* 指针
    int* p2 = &a;  // 正确,p2 也是 int* 指针,与 p1 完全等价
    printf("%d %d", *p1, *p2);  // 均输出 10
    
  • 开发习惯:两种写法都很常见,int *p 更强调 “p 是指针”,int* p 更强调 “p 的类型是 int*”,但本质无差异。
(2)int (*p) —— 语法有效,但括号冗余
  • 核心逻辑:括号 () 强制 p 先与 * 结合,但由于没有其他高优先级运算符(如数组下标 []、函数 ()),括号没有实际作用,最终效果与 int *p 一致。
  • 编译效果:编译器会忽略冗余的括号,将其解析为 “p 是 int* 指针”,与前两种写法无区别。
  • 示例
    int a = 20;
    int (*p3) = &a;  // 正确,p3 是 int* 指针,括号冗余
    printf("%d", *p3);  // 输出 20
    
  • 注意:实际开发中很少这么写,因为括号不仅没有必要,还会略微降低代码可读性(容易让人误以为有特殊逻辑)。

8.*p 的退化不是 “在取 **p 时才发生”,而是在多数语境下(包括作为 * 运算符的操作数时)会自动发生**p 只是利用了这种退化的结果。

具体拆解:*p 的退化时机

当 p 是 char*(*)[3][6] 类型(指向二维数组的指针)时:

  1. *p 得到的是 char*[3][6] 类型的二维数组(p 指向的实体)。此时,只要 *p 出现在 “需要指针的语境” 中(如赋值给指针变量、参与指针运算、作为 * 的操作数等),就会立即退化为 char*(*)[6] 类型(指向第一行数组的指针)。

  2. 当执行 **p 时:

    • 第一步:*p 先退化(因为它作为 * 运算符的操作数,处于 “需要指针的语境”),变成指向第一行的指针(char*(*)[6] 类型);
    • 第二步:对这个 “指向第一行的指针” 解引用(*),得到第一行数组(char*[6] 类型)。

关键:退化是 “语境触发”,而非 “显式取 * 时才触发”

*p 的退化不是 “等待 **p 时才发生”,而是:** 只要 *p 离开 “不会退化的特殊语境”(如 sizeof(*p)&*p),就会自动退化 **。例如,即使不写 **p,单独使用 *p 时也会退化:

char* arr[3][6];
char*(*p)[3][6] = &arr;  // p 指向二维数组char*(*q)[6] = *p;  // 正确:*p 退化后是 char*(*)[6] 类型,可直接赋值给 q

这里 *p 并没有参与 **p 运算,但依然发生了退化(否则无法赋值给 q)。

总结

退化的触发时机很普遍:*p 的退化不是 “在取 **p 时才发生”,而是在大多数语境下(包括作为 * 运算符的操作数)会自动发生,**p 只是对退化后的指针再次解引用的结果。简单说:退化是 *p 自身在多数语境下的特性,**p 是利用了这个特性进行的二次操作。

http://www.dtcms.com/a/418607.html

相关文章:

  • 中英双语 网站 模板网站建设项目验收单
  • 【centos生产环境搭建(二)redis安装】
  • 四川移动网站建设网架报价明细表
  • 网站设计思路WordPress客户端
  • 做试玩网站网站快速排名技术
  • Day30_【NLP 自然语言处理(0)—入门】
  • springboot 配置 HikariDataSource 连接池信息
  • identity mapping kernel image mapping
  • Docker操作命令
  • iOS 26 能耗检测实战指南,升级后电池掉速是否正常 + KeyMob + Instruments 实时监控 + 优化策略
  • perl踩坑系列===正则表达式第2坑---split中的“或”操作符
  • 苹果iOS 26正式版系统性能深度测试:续航、信号、流畅度详细解析
  • 假网站网站怎么做中山中小企业网站建设
  • 网站备案 二级域名学会网站建设项目
  • 01-元字符:如何巧妙记忆正则表达式的基本元件?
  • yandex俄语网站建设广东省网站备案查询
  • nginx xxs漏铜修复、nginx 域名配置、nginx https证书配置、Http不安全处理方法
  • 建设银行客户端官方网站flask做大型网站开发
  • 耐达讯自动化妙解Modbus与Profibus协议冲突:变频器控制的“黄金公式“
  • 自动化专业核心课《计算机控制技术》导览---数字时代的控制中枢
  • 【星海出品】计算机科学缓存命中学习
  • YOLO入门教程(番外):计算机视觉数学、编程基础
  • 做商品网站医院网站建设方案计划书
  • 从零开始学RabbitMQ:Java实战简单模式与工作队列消息处理
  • 农家乐网站模板腾讯云电商网站建设
  • 响应式网站用什么软件做效果站酷设计网站官网入口免费个人海报
  • JavaScript中国手机号校验
  • 【OJ】stack 的经典OJ题
  • 算法1.0
  • 语义网络对人工智能自然语言处理中深层语义分析的影响与启示