数组对象类型

Array of Type,它是多个相同对象类型的一维派生类型,包含两要素:元素个数,元素的对象类型

所谓多维数组,不过是元素的迭代衍生,本质还是一维的

声明 对象标识的名称 对象类型 对象存储元素类型 解释
int b[3] b int[3] int int[3]类型包含3个元素,每个元素对象类型为int
int a[2][3] a int[2][3] int[3] int[2][3]类型包含2个元素,每个元素对象类型为int[3]

sizeof用法

当其后跟对象类型时,必须加括号

sizeof(3);	// √
sizeof 3 ; // √
sizeof(int[3]); // √
sizeof int[3] ; // ×

不完全对象类型

对象类型的其中一种分类:完全对象类型,不完全对象类型。

不完全对象类型,指缺少“能确定对象大小”信息的类型,包括:

  • 缺少元素个数的数组: extern int a[]
  • 变长数组VLA
  • 包含不完全对象类型的struct/union
  • void类型

指针对象类型

Pointer to Type,任何一种对象类型,都有对应的指针对象类型

原类型 对应指针类型 解释
int[2][3] int(*)[2][3] 数组指针的语法比较怪
int(*)[2][3] int(**)[2][3] 指针类型也是类型,也就有对应的指针类型
int*[2][3] int*(*)[2][3] 元素为int*[2][3]形数组,其指针类型就如第一行

举一反三,int(*[2])[3] 类型应该如下解构(结合上表规则):

它是一个2元素数组,数组中的元素类型是指针,该指针指向int[3](即类型为int(*)[3]

int(*ppa[2])[3];		// 此时ppa[1]没有指向具体内存,所以不能直接解引用寻找对应内存地址
int a[3] = {1,2,3}; ppa[1] = &a;
printf("%d\n", (*ppa[1])[2]); // 输出3
(*ppa[1])[2] = 10;
printf("%d\n", (*ppa[1])[2]); // 输出10

typedef使用

C提供typedef为对象类型提供别名。

对于数组、指针相关的typedef,稍显不同寻常

原始类型 目标类型(别名) 声明语法 描述
int(*)[2] PAINT typedef int (*PAINT)[2]; 倒像是声明变量了
int[2] AINT typedef int AINT[2];
int[2][3] AAINT typedef int AAINT[2][3];

由于将对象类型包装,所以指针语义将被延续:

typedef int* PINT;
int* p,q; // p是int*, q是int
PINT r,s; // r和s均为int*

内存对象的属性:值

每个内存对象的值包含两层语义:值,值的类型。可表示为二元组<Value, ValueType>

  • 对于非数组对象类型:ValueType = ObjectType,对象按规则转换成Value (左值转换);
  • 对于数组对象类型: Value = 第一个元素的首地址,ValueType = 元素类型对应的Pointer Type
    • e.g. int a[2],其对象类型为int[2],则a的值为<a代表的内存的首地址, int*>(可以从编译器报错中确认)

对内存对象的抽象:内存六元组

Object = <Addrress, ObjectType, Name, Size, Value, ValueType>

名称 含义 说明
Address 系统给对象分配内存的首地址编号 系统分配,不再改变
ObjectType 对象的类型 即声明变量时的变量类型
Name 对象标识符 即声明变量时的变量名,在符号表中,代表这块内存
Size 内存的大小 内存的字节数量,sizeof可得
Value 这段内存的表示值 根据ObjectType确定
ValueType 这段内存的表示值类型 根据ObjectType确定

内存信息读取的三步骤

定位内存 --> 识别对内存的操作类型 --> 获取相应返回值

通过表达式(左值表达式)定位内存:

  • 变量名表达式
  • * 和 指针 结合的表达式

对于每块内存,有3种操作类型(evaluate):

  • &(exp):获取exp定位的内存的首地址,返回值为<Address, ObjectType*>
  • sizeof(exp):获取exp定位的内存的大小,返回值为<Size, size_t>
  • exp(表达式本身):获取exp定位的内存的值,返回值为<Value, ValueType>

获取的返回值:即为值,形如<Value, ValueType>

表达式与左值

表达式:一些列操作符和操作对象组成的序列

左值:能定位到一个对象内存的表达式

表达式类型

基本表达式

后缀表达式

一元表达式

Cast表达式

条件表达式

运算表达式

位运算表达式

逻辑运算表达式

逗号运算表达式

const修饰符(qualifiers)

对于一个对象类型ObjectType,用const修饰符修饰将会产生一个新的对象类型ObjectType const(和const ObjectType等价),不过该对象的表示值类型仍为ValueType

... become qualified type, the value has unqualified version ...

声明 ObjectType ValueType 解释
int const a = 10; int const int 说明a表示的内存is unmodifiable
int* const p = &a; int* const int* const修饰int*。p的内存表示一个int*指针,它是unmodifiable的
int const* p = &a; int const* int const* const修饰int。p的内存表示一个int const*的正常指针,其指向的内存类型是int const的,即为unmodifiable的int
int const* const p = &a int const* const int const* p本身、指向的内存均为unmodifiable
int const g[1][2] = {1,2}; int const[1][2] int const(*)[3] 仍旧把int const当作整体看,数组的元素对象类型是int const

对ObjectType中含有const修饰的内存的修改操作,都会导致编译错误。

const的位置摆放:若放在ObjectType之前,可能会导致歧义。例如const int* p = &a;const究竟修饰int还是修饰int*未可知,属于未定义行为。

关于字符串

char str[8] = "hello";

双引号修饰的字符串都有一个隐藏的'\0';如上例,"hello"会在静态区找合适的空间存放'h' 'e' 'l' ... '\0',而之后可以直接通过"hello"定位到这块内存

  • 基本的evaluate:&"hello"获取地址,sizeof("hello")获取大小,"hello"返回值<addr, char*>(数组的表示值)
  • sizeof("hello"),结果为6,定位到"hello"内存,返回其大小;sizeof("hello"+1-1),结果为4,"hello"作为表达式的一部分,返回值的类型是char*,+1和-1操作后整个表达式的类型仍为char*,所以为指针大小4
  • char c = "hello"[0],c将得到'h',因为"hello"定位到内存后,后面等同数组的操作,合乎逻辑;"hello"[0] = 'e'则是一个未定义行为,视编译器而定,不要乱来
  • char* p = "hello"; char* q = "hello";,可以想见,p和q的值应该相同,都指向同一个内存地址

在C中,有StringString Literal的区分,前者仅在结尾以'\0'结尾(如"hello world"),后者可包含多个'\0'(如"hello\0world")。不失一般性,两者可统称字符串

sizeof(String Literal):全部字符串长度,包括结尾'\0'

strlen(String Literal):第一个String的长度,不包括'\0'

sizeof("abc\0def");	// 8 : a b c \0 d e f \0
strlen("abc\0def"); // 3 : a b c

复合字面量(Compound Literal)

一种合法的后缀表达式,强调按字面意义理解Type + Initializer

int* q = (int[2]){2, 3};

同样可以定位内存,相关的evalute操作适用,且对其内存的修改为合法行为(String Literal则是未定义行为)

字面量(Literal)和常量(Constant)

常量 String Literal Compound Literal
是否可定位内存(为左值)
是否能修改内存

C系统级编程-复习的更多相关文章

  1. 系统级编程(csapp)

    系统级编程漫游 系统级编程提供学生从用户级.程序员的视角认识处理器.网络和操作系统,通过对汇编器和汇编代码.程序性能评测和优化.内存组织层次.网络协议和操作以及并行编程的学习,理解底层计算机系统对应用 ...

  2. ARMV8 datasheet学习笔记4:AArch64系统级体系结构之编程模型(1)-EL/ET/ST

    1.前言 ARMV8系统级编程模型主要包括异常级别.运行状态.安全状态.同步异常.异步异常.DEBUG 本文主要对系统级编程模型做一个概要介绍 2. 异常级别 2.1 Exception level概 ...

  3. 转 系统级编程语言性能PK

    http://www.solidot.org/story?sid=35754 看了此文,为什么我现在如此看好Rust C/C++已经统治系统编程很久,除了ObjectiveC之外语言都无法获得很高的关 ...

  4. [CSAPP笔记][第十章 系统级I/O]

    第十章 系统级I/O 输入/输出(I/O) : 是指主存和外部设备(如磁盘,终端,网络)之间拷贝数据过程. 高级别I/O函数 scanf和printf <<和>> 使用系统级I ...

  5. Java-Runoob-高级编程:Java 网络编程

    ylbtech-Java-Runoob-高级编程:Java 网络编程 1.返回顶部 1. Java 网络编程 网络编程是指编写运行在多个设备(计算机)的程序,这些设备都通过网络连接起来. java.n ...

  6. 深入理解计算机系统10——系统级I/O

    系统级I/O 输入/输出 是在主存和外部设备之间拷贝数据的过程. 外部设备可以是:磁盘驱动器.终端和网络. 输入和输出都是相对于主存而言的. 输入是从I/O设备拷贝数据到主存.输出时从主存拷贝数据到I ...

  7. CentOS:设置系统级代理(转)

    原文地址:http://www.cnblogs.com/cocowool/archive/2012/07/05/2578487.html YUM代理设置 编辑/etc/yum.conf,在最后加入 # ...

  8. 系统级性能分析工具perf的介绍与使用

    测试环境:Ubuntu16.04(在VMWare虚拟机使用perf top存在无法显示问题) Kernel:3.13.0-32 系统级性能优化通常包括两个阶段:性能剖析(performance pro ...

  9. 从service弹出系统级自定义提示框,可在任意页面弹出

    添加权限 <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> // 显示 ...

  10. 系统级IO实践学习记录

    代码分析 cp1.c 功能:复制文件. #include <stdio.h>#include <stdlib.h>#include <unistd.h>#inclu ...

随机推荐

  1. 【问题解决】Pycharm、IDAE等乱码问题:运行输出窗口就正常显示,调试乱码的问题

    添加如下内容 -Dfile.encoding=UTF-8 重启软件生效

  2. shell中字符串比较和模糊比较说明

    shell字符串比较说明 1 完全比较方法(完全匹配) if [ "$soure" == "$dest" ]; then echo "is ==&qu ...

  3. com.sun.xml.internal.messaging.saaj.util 不存在

    maven 编译时报错:程序包com.sun.xml.internal.messaging.saaj.util不存在需要添加 <compilerArguments> <verbose ...

  4. 【转载】Spring Cloud Gateway限流详解

    https://www.imooc.com/article/290828/ Spring Cloud Gateway限流详解 2019.08.11 12:56 7257浏览   Spring Clou ...

  5. Qt项目升级到Qt6吐血经验总结

    Qt的版本发布越来越频繁,Qt6发布已经有一段时间了,越来越多的人咨询之前的代码是否可以增加对Qt6的支持,包括开源的项目QWidgetDemo(一年时间超过2.6K star),近期百忙之中,对所有 ...

  6. 主动式AI(代理式)与生成式AI的关键差异与影响

    大型语言模型(LLMs)如GPT可以生成文本.回答问题并协助完成许多任务.然而,它们是被动的,这意味着它们仅根据已学到的模式对接收到的输入作出响应.LLMs无法自行决策:除此之外,它们无法规划或适应变 ...

  7. JS-正则表达式(基本语法、test、exec、\d\D\w\W\s\S .)

    二,正则表达式 1,什么是正则表达式 是一种规范,对字符串格式进行验证的规范 不用自己写,常用的正则表达式,网上都有,只要会使用就可以 2,定义方法 字面量 var reg = /正则表达式/ 常用方 ...

  8. pitch、yaw、roll三个角的区别

    Z轴正方向为前进方向 pitch():俯仰,将物体绕X轴旋转(localRotationX) yaw():航向,将物体绕Y轴旋转(localRotationY) roll():横滚,将物体绕Z轴旋转( ...

  9. MAC 使用问题汇总

    1. 在.zshrc中添加的环境变量不起作用 Answer: 需要把/etc/zshrc文件复制到 ~, 并命名为.zshrc,然后设置环境变量即可:

  10. 题解:AT_abc386_d [ABC386D] Diagonal Separation

    分析题面,发现题目求的是是否存在一个白点被 \((1, 1)\) 和任意一个黑点围成的矩形内. 先将所有黑点按 \(x\) 坐标排序. 枚举所有的白点. 找到所有横坐标不比该白点横坐标小的所有黑点的纵 ...