通识
跳转到“通识”(1) ptr:Pointer,只针对额缩写;nullptr:空指针;
(2)指针大小固定,32位系统,4字节;64位,8字节;
(3)指针的读法:类型 *变量名; 的声明时,其中的 变量名 就是指针,它被用来指向指定类型的数据。通常会说 “变量名 是一个指向 类型 的指针”。
(4)语法糖:指计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,到那时方便程序员使用,可以理解为加语法糖后和没加前编译的结果一样,为了方便写代码。
// c++的语法糖比如:引用int a = 1;int *p = a;*p = 2;int &b = a;b = 3;在许多编程语言中,三元运算符是一种简洁的方式来编写条件语句。例如,在C语言和JavaScript中:
int max = (a > b) ? a : b;这行代码的意思是:如果a > b为真,则max等于a,否则等于b。这可以看作是以下代码的语法糖:
int max;if (a > b) { max = a;} else { max = b;}语法糖使得代码更加简洁和易于理解,但它们背后通常有更复杂的实现,编译器或解释器会将这些语法糖转换为更基本的代码结构。
(5) 小写字母:97-122 ; 大写字母:65-90
(6) sizeof是用来计算栈大小,不涉及全局区,故类的静态成员大小sizeof不涉及
(7)
1 类与结构一样,都有字节对齐的问题 2 类中普通的函数不占用类的大小 3 类中虚函数占用一个地址位宽(4或8字节),且不论有多少个虚函数一共只占这么多 4 类中常量不占用类大小: const static / enum{aa=2,bb=4}; 5 类中static修饰的变量不占用类大小,因为修饰后存储在静态区域 6 子类的大小等于子类新增的加上父类的大小
(8)引用只能一层,不能多层引用
(9) 基类的指针指向派生类的对象:基类指针调用其虚成员函数,则会调用其真正指向对象的成员函数,而不是基类中定义的成员函数,若不是虚函数,则不管基类指针指向的是哪个派生对象,调用的都是基类中定义的那个函数
(10)如果两个比特不同,则结果为1;如果两个比特相同,则结果为0
(11)当结构体的成员自然对齐规则(由其类型决定的内存对齐要求)不能满足时,编译器通常会自动插入填充(padding),以确保每个成员都按其对齐要求放置。
(12)数组下标是从0开始的,不管是几维。
(13)16进制字母部分不分大小写的 。
(14)在继承中派生类的对象调用构造函数的顺序,应该是先调用基类的构造函数,然后是成员中的对象对应类的构造函数,最后是派生类自己的构造函数(先父母,再客人,后自己。)
(15)用父类指针指向子类对象时,在父类的成员函数前加virtual,调用时调用的才是子类本身的那个成员函数,否则调用的还是父类的成员函数。
(16)指针和引用的区别:
指针和引用是两种不同的语言特性,它们都可以用来间接地访问另一个变量。不过,它们有一些关键的区别: 1)声明和使用:
- 指针是一个变量,其值为另一个变量的地址。你需要使用
&运算符来获取地址,并使用*运算符来访问或修改指向的值。int x = 10;int* p = &x; // p是一个指针,指向x的地址*p = 20; // 通过指针修改x的值 - 引用是另一个变量的别名,一旦被初始化后,就不能改变引用的绑定(即它不能再开始引用另一个变量)。引用在声明时必须初始化,并且不需要使用特殊的符号来访问绑定的值。
int x = 10;int& r = x; // r是对x的引用r = 20; // 直接修改x的值,因为r是x的别名
2)空值:
- 指针可以有
nullptr或空值,表示它不指向任何东西。 - 引用必须引用某些东西,不能有空引用。
3)重新赋值:
- 指针可以被重新赋值以指向另一个不同的地址。
- 引用一旦被初始化后,就不能重新绑定到另一个变量;它始终引用最初被绑定的变量。
4)内存地址:
- 指针本身是一个对象,占用内存,并有自己的内存地址。
- 引用不是一个真实的对象;它没有自己的内存地址,它只是被引用对象的一个别名。
5)使用场景:
- 指针通常用在动态内存分配、数组操作、低级编程(如操作系统或嵌入式系统编程)中。
- 引用则用在传递参数给函数(特别是操作符重载)、防止对象复制产生的额外开销等场景。
6)数组和算术操作:
- 指针支持算术运算,例如指针增加(指向数组中的下一个元素)。
- 引用不支持算术运算,它们只是单个对象的别名。
dai buchong
(18)函数定义先后
在C++中,函数定义的先后顺序确实可能对程序的行为产生影响,尤其是在以下情况下:
1)前向声明与定义:如果你在一个文件中先使用了一个函数,然后在之后的地方定义了这个函数,你需要在首次使用之前提供函数的前向声明。否则,编译器在编译时不知道函数的签名,可能会导致编译错误。
2)模板函数:模板函数的定义必须在它们被使用之前可见,因为模板的定义需要在编译时展开。如果模板函数的定义在调用之后,模板实例化将无法正确进行。
3)内联函数:对于内联函数,定义必须在它被调用之前出现,因为编译器需要在调用点展开内联函数。如果内联函数的定义在调用之后,编译器无法在调用点展开它,这可能导致链接错误或运行时错误。
(19)头文件守卫
假设我们有一个项目,其中包含一个名为 MyMath.h 的头文件,该文件提供了一些数学函数的声明。这里是 MyMath.h 的内容:
#ifndef MYMATH_H#define MYMATH_H
// 这里声明一些数学函数int add(int a, int b);int subtract(int a, int b);
#endif // MYMATH_H在这个例子中,#ifndef MYMATH_H 检查 MYMATH_H 宏是否未定义。如果未定义,#define MYMATH_H 将定义这个宏,然后编译 #ifndef 和 #endif 之间的代码,即头文件的其余部分。
现在,假设我们有两个源文件 main.cpp 和 math_functions.cpp,它们都需要使用 MyMath.h 中的函数:
#include "MyMath.h"int main() { int result = add(3, 4); return 0;}
// math_functions.cpp#include "MyMath.h"int add(int a, int b) { return a + b;}当这两个源文件被编译时,会发生什么情况:
- 预处理阶段:编译器首先处理
#include指令,将MyMath.h的内容插入到main.cpp和math_functions.cpp中。 - 头文件保护:当编译器处理
main.cpp中的MyMath.h时,它检查MYMATH_H宏是否已定义。由于这是MyMath.h的第一次包含,宏未定义,所以编译器继续处理MyMath.h的内容,并定义了MYMATH_H宏。 - 避免重复包含:随后,当编译器处理
math_functions.cpp中的MyMath.h时,它再次检查MYMATH_H宏。这次,宏已经定义了(因为在编译main.cpp时已经定义),所以#ifndef MYMATH_H的条件失败,编译器跳过MyMath.h的内容,不会导致重复定义或编译错误。 - 编译源文件:编译器继续编译两个源文件中的代码,包括
add函数的定义和main函数中的add函数调用。 通过这种方式,头文件保护确保了即使头文件被多次包含,它的内容也只会被编译一次,避免了潜在的编译错误和不一致性。这是 C 和 C++ 项目中管理头文件依赖关系的一个标准做法。
(20)构造函数会在main 完成
#include "threadSeg_Yolo_RT.h"
std::string outpath = "F:/code/projects/threadSeg_Yolo_RT/assets/out";prc::PROCESS yolo_process(outpath);int main(){}在C++中,全局或命名空间作用域的变量(例如 yolo_process)是在程序的编译阶段定义的,但它们的初始化是在程序的运行时执行的。也就是说,yolo_process 的类型 prc::PROCESS 的构造函数会在 main 函数执行之前被调用,以初始化这个对象。
具体来说,当你的程序开始执行时,操作系统会加载程序的代码和数据到内存中,然后开始执行 main 函数。在 main 函数执行之前,程序会进行一系列的初始化步骤,包括:
- 初始化全局变量和静态变量。
- 调用这些变量的构造函数(如果有的话)。
(21)静态、动态库
| 特性 | .lib 文件 | .dll 文件 |
|---|---|---|
| 全称 | Library | Dynamic Link Library |
| 用途 | - 静态库:包含编译后的对象文件集合。 - 导入库:包含用于链接动态链接库的接口。 | 包含可由多个程序共享的函数和资源的二进制代码。 |
| 链接方式 | 静态链接:在编译时将库的内容复制到最终可执行文件中。 | 动态链接:在程序运行时加载库,函数地址在加载时解析。 |
| 分发 | 通常需要与应用程序一起分发,因为它们是程序的一部分。 | 可以被多个应用程序共享,不需要每个应用程序都包含一个副本。 |
| 更新和维护 | 更新静态库可能需要重新编译所有使用它的程序。 | 更新DLL可能只需要替换文件,而不需要重新编译使用它的程序。 |
| 依赖性 | 静态库在编译时解决所有依赖性。 | DLL在运行时解决依赖性,可能引入运行时错误。 |
| 性能 | 由于所有代码都包含在最终可执行文件中,可能提供更快的启动时间和更好的性能。 | 启动时间可能较慢,因为需要在运行时加载和解析DLL。 |
| 灵活性 | 较低,因为修改库需要重新编译使用它的所有程序。 | 较高,因为DLL可以独立于应用程序更新和替换。 |
| 使用场景 | - 适用于不经常更改的代码库。 - 适用于需要高性能的应用程序。 | - 适用于需要高度可维护性和灵活性的应用程序。 - 适用于跨多个应用程序共享代码和资源。 |
(22)查看属性和方法
在C++中,没有直接等同于Python的dir()函数的功能。Python的dir()函数可以列出一个对象的所有属性和方法,这是因为Python是一种动态类型的语言,可以在运行时获取对象的信息。然而,C++是一种静态类型的语言,对象的属性和方法在编译时就已经确定,无法在运行时获取。
(23)默认参数放在后面
在C++中,当函数参数提供默认值时,这些带有默认值的参数必须位于函数参数列表的末尾。这是因为如果默认参数位于非默认参数之前,它将导致函数重载解析的歧义。
(24)对对象this问题
如果有一个A类的实例ta和一个C类的实例tc,并且ta.b指向tc,那么当调用ta.fa()时,fa方法内部调用b->fc(),此时this在fc方法中指向的是tc,因为fc是被b所指向的对象调用的。简单来说,this总是指向调用方法的那个对象实例,无论这个方法是如何被调用的。在本例中,即使fc是通过A类的一个实例间接调用的,this在C类的fc方法中仍然指向C类的实例tc。
(25)
- 在 C++ 中,如果你在类的定义外部提供成员函数的实现(即在类定义的
{}外部),你通常不需要使用override关键字。 - 在 C++ 中,
noexcept是一个关键字,用来指示一个函数不会抛出异常。当你在函数声明的末尾添加noexcept,你告诉编译器这个函数保证不会抛出任何异常。在重写成员函数时,如果基类版本的成员函数也声明为noexcept,那么派生类的重写版本也应该声明为noexcept,以保证接口的一致性。
(26)对象指针
VIDEOTHREAD * __videoThread;__videoThread 被定义为 VIDEOTHREAD 类型的指针,意味着它存储的是 VIDEOTHREAD 类型对象的内存地址。当你看到 -> 运算符时,它用于访问指针指向的对象的成员。 -> 运算符的工作原理:
__videoThread存储了一个对象的内存地址。- 当你使用
__videoThread->someMemberFunction();这样的表达式时,->运算符首先会解引用__videoThread指针,得到它所指向的对象。 - 然后,它会访问该对象的
someMemberFunction成员函数。
(27)ASCII
| Bin(二进制) | Oct(八进制) | Dec(十进制) | Hex(十六进制) | 缩写/字符 | 解释 |
|---|---|---|---|---|---|
| 0000 0000 | 00 | 0 | 0x00 | NUL(null) | 空字符 |
| 0000 0001 | 01 | 1 | 0x01 | SOH(start of headline) | 标题开始 |
| 0000 0010 | 02 | 2 | 0x02 | STX (start of text) | 正文开始 |
| 0000 0011 | 03 | 3 | 0x03 | ETX (end of text) | 正文结束 |
| 0000 0100 | 04 | 4 | 0x04 | EOT (end of transmission) | 传输结束 |
| 0000 0101 | 05 | 5 | 0x05 | ENQ (enquiry) | 请求 |
| 0000 0110 | 06 | 6 | 0x06 | ACK (acknowledge) | 收到通知 |
| 0000 0111 | 07 | 7 | 0x07 | BEL (bell) | 响铃 |
| 0000 1000 | 010 | 8 | 0x08 | BS (backspace) | 退格 |
| 0000 1001 | 011 | 9 | 0x09 | HT (horizontal tab) | 水平制表符 |
| 0000 1010 | 012 | 10 | 0x0A | LF (NL line feed, new line) | 换行键 |
| 0000 1011 | 013 | 11 | 0x0B | VT (vertical tab) | 垂直制表符 |
| 0000 1100 | 014 | 12 | 0x0C | FF (NP form feed, new page) | 换页键 |
| 0000 1101 | 015 | 13 | 0x0D | CR (carriage return) | 回车键 |
| 0000 1110 | 016 | 14 | 0x0E | SO (shift out) | 不用切换 |
| 0000 1111 | 017 | 15 | 0x0F | SI (shift in) | 启用切换 |
| 0001 0000 | 020 | 16 | 0x10 | DLE (data link escape) | 数据链路转义 |
| 0001 0001 | 021 | 17 | 0x11 | DC1 (device control 1) | 设备控制1 |
| 0001 0010 | 022 | 18 | 0x12 | DC2 (device control 2) | 设备控制2 |
| 0001 0011 | 023 | 19 | 0x13 | DC3 (device control 3) | 设备控制3 |
| 0001 0100 | 024 | 20 | 0x14 | DC4 (device control 4) | 设备控制4 |
| 0001 0101 | 025 | 21 | 0x15 | NAK (negative acknowledge) | 拒绝接收 |
| 0001 0110 | 026 | 22 | 0x16 | SYN (synchronous idle) | 同步空闲 |
| 0001 0111 | 027 | 23 | 0x17 | ETB (end of trans. block) | 结束传输块 |
| 0001 1000 | 030 | 24 | 0x18 | CAN (cancel) | 取消 |
| 0001 1001 | 031 | 25 | 0x19 | EM (end of medium) | 媒介结束 |
| 0001 1010 | 032 | 26 | 0x1A | SUB (substitute) | 代替 |
| 0001 1011 | 033 | 27 | 0x1B | ESC (escape) | 换码(溢出) |
| 0001 1100 | 034 | 28 | 0x1C | FS (file separator) | 文件分隔符 |
| 0001 1101 | 035 | 29 | 0x1D | GS (group separator) | 分组符 |
| 0001 1110 | 036 | 30 | 0x1E | RS (record separator) | 记录分隔符 |
| 0001 1111 | 037 | 31 | 0x1F | US (unit separator) | 单元分隔符 |
| 0010 0000 | 040 | 32 | 0x20 | (space) | 空格 |
| 0010 0001 | 041 | 33 | 0x21 | ! | 叹号 |
| 0010 0010 | 042 | 34 | 0x22 | ” | 双引号 |
| 0010 0011 | 043 | 35 | 0x23 | # | 井号 |
| 0010 0100 | 044 | 36 | 0x24 | $ | 美元符 |
| 0010 0101 | 045 | 37 | 0x25 | % | 百分号 |
| 0010 0110 | 046 | 38 | 0x26 | & | 和号 |
| 0010 0111 | 047 | 39 | 0x27 | ’ | 单引号 |
| 0010 1000 | 050 | 40 | 0x28 | ( | 开括号 |
| 0010 1001 | 051 | 41 | 0x29 | ) | 闭括号 |
| 0010 1010 | 052 | 42 | 0x2A | * | 星号 |
| 0010 1011 | 053 | 43 | 0x2B | + | 加号 |
| 0010 1100 | 054 | 44 | 0x2C | , | 逗号 |
| 0010 1101 | 055 | 45 | 0x2D | - | 减号/破折号 |
| 0010 1110 | 056 | 46 | 0x2E | . | 句号 |
| 0010 1111 | 057 | 47 | 0x2F | / | 斜杠 |
| 0011 0000 | 060 | 48 | 0x30 | 0 | 字符0 |
| 0011 0001 | 061 | 49 | 0x31 | 1 | 字符1 |
| 0011 0010 | 062 | 50 | 0x32 | 2 | 字符2 |
| 0011 0011 | 063 | 51 | 0x33 | 3 | 字符3 |
| 0011 0100 | 064 | 52 | 0x34 | 4 | 字符4 |
| 0011 0101 | 065 | 53 | 0x35 | 5 | 字符5 |
| 0011 0110 | 066 | 54 | 0x36 | 6 | 字符6 |
| 0011 0111 | 067 | 55 | 0x37 | 7 | 字符7 |
| 0011 1000 | 070 | 56 | 0x38 | 8 | 字符8 |
| 0011 1001 | 071 | 57 | 0x39 | 9 | 字符9 |
| 0011 1010 | 072 | 58 | 0x3A | : | 冒号 |
| 0011 1011 | 073 | 59 | 0x3B | ; | 分号 |
| 0011 1100 | 074 | 60 | 0x3C | < | 小于 |
| 0011 1101 | 075 | 61 | 0x3D | = | 等号 |
| 0011 1110 | 076 | 62 | 0x3E | > | 大于 |
| 0011 1111 | 077 | 63 | 0x3F | ? | 问号 |
| 0100 0000 | 0100 | 64 | 0x40 | @ | 电子邮件符号 |
| 0100 0001 | 0101 | 65 | 0x41 | A | 大写字母A |
| 0100 0010 | 0102 | 66 | 0x42 | B | 大写字母B |
| 0100 0011 | 0103 | 67 | 0x43 | C | 大写字母C |
| 0100 0100 | 0104 | 68 | 0x44 | D | 大写字母D |
| 0100 0101 | 0105 | 69 | 0x45 | E | 大写字母E |
| 0100 0110 | 0106 | 70 | 0x46 | F | 大写字母F |
| 0100 0111 | 0107 | 71 | 0x47 | G | 大写字母G |
| 0100 1000 | 0110 | 72 | 0x48 | H | 大写字母H |
| 0100 1001 | 0111 | 73 | 0x49 | I | 大写字母I |
| 01001010 | 0112 | 74 | 0x4A | J | 大写字母J |
| 0100 1011 | 0113 | 75 | 0x4B | K | 大写字母K |
| 0100 1100 | 0114 | 76 | 0x4C | L | 大写字母L |
| 0100 1101 | 0115 | 77 | 0x4D | M | 大写字母M |
| 0100 1110 | 0116 | 78 | 0x4E | N | 大写字母N |
| 0100 1111 | 0117 | 79 | 0x4F | O | 大写字母O |
| 0101 0000 | 0120 | 80 | 0x50 | P | 大写字母P |
| 0101 0001 | 0121 | 81 | 0x51 | Q | 大写字母Q |
| 0101 0010 | 0122 | 82 | 0x52 | R | 大写字母R |
| 0101 0011 | 0123 | 83 | 0x53 | S | 大写字母S |
| 0101 0100 | 0124 | 84 | 0x54 | T | 大写字母T |
| 0101 0101 | 0125 | 85 | 0x55 | U | 大写字母U |
| 0101 0110 | 0126 | 86 | 0x56 | V | 大写字母V |
| 0101 0111 | 0127 | 87 | 0x57 | W | 大写字母W |
| 0101 1000 | 0130 | 88 | 0x58 | X | 大写字母X |
| 0101 1001 | 0131 | 89 | 0x59 | Y | 大写字母Y |
| 0101 1010 | 0132 | 90 | 0x5A | Z | 大写字母Z |
| 0101 1011 | 0133 | 91 | 0x5B | [ | 开方括号 |
| 0101 1100 | 0134 | 92 | 0x5C | \ | 反斜杠 |
| 0101 1101 | 0135 | 93 | 0x5D | ] | 闭方括号 |
| 0101 1110 | 0136 | 94 | 0x5E | ^ | 脱字符 |
| 0101 1111 | 0137 | 95 | 0x5F | _ | 下划线 |
| 0110 0000 | 0140 | 96 | 0x60 | ` | 开单引号 |
| 0110 0001 | 0141 | 97 | 0x61 | a | 小写字母a |
| 0110 0010 | 0142 | 98 | 0x62 | b | 小写字母b |
| 0110 0011 | 0143 | 99 | 0x63 | c | 小写字母c |
| 0110 0100 | 0144 | 100 | 0x64 | d | 小写字母d |
| 0110 0101 | 0145 | 101 | 0x65 | e | 小写字母e |
| 0110 0110 | 0146 | 102 | 0x66 | f | 小写字母f |
| 0110 0111 | 0147 | 103 | 0x67 | g | 小写字母g |
| 0110 1000 | 0150 | 104 | 0x68 | h | 小写字母h |
| 0110 1001 | 0151 | 105 | 0x69 | i | 小写字母i |
| 0110 1010 | 0152 | 106 | 0x6A | j | 小写字母j |
| 0110 1011 | 0153 | 107 | 0x6B | k | 小写字母k |
| 0110 1100 | 0154 | 108 | 0x6C | l | 小写字母l |
| 0110 1101 | 0155 | 109 | 0x6D | m | 小写字母m |
| 0110 1110 | 0156 | 110 | 0x6E | n | 小写字母n |
| 0110 1111 | 0157 | 111 | 0x6F | o | 小写字母o |
| 0111 0000 | 0160 | 112 | 0x70 | p | 小写字母p |
| 0111 0001 | 0161 | 113 | 0x71 | q | 小写字母q |
| 0111 0010 | 0162 | 114 | 0x72 | r | 小写字母r |
| 0111 0011 | 0163 | 115 | 0x73 | s | 小写字母s |
| 0111 0100 | 0164 | 116 | 0x74 | t | 小写字母t |
| 0111 0101 | 0165 | 117 | 0x75 | u | 小写字母u |
| 0111 0110 | 0166 | 118 | 0x76 | v | 小写字母v |
| 0111 0111 | 0167 | 119 | 0x77 | w | 小写字母w |
| 0111 1000 | 0170 | 120 | 0x78 | x | 小写字母x |
| 0111 1001 | 0171 | 121 | 0x79 | y | 小写字母y |
| 0111 1010 | 0172 | 122 | 0x7A | z | 小写字母z |
| 0111 1011 | 0173 | 123 | 0x7B | { | 开花括号 |
| 0111 1100 | 0174 | 124 | 0x7C | | | 垂线 |
| 0111 1101 | 0175 | 125 | 0x7D | } | 闭花括号 |
| 0111 1110 | 0176 | 126 | 0x7E | ~ | 波浪号 |
| 0111 1111 | 0177 | 127 | 0x7F | DEL (delete) | 删除 |
(28)‘’表示字符常量,“”表示字符串常量。
(29)main 函数不是必须
main函数和其他函数的汇编结果相同,只是好多程序默认将main函数设置为程序的入口,可以手动更改程序入口:
# 指定程序起点gcc -nostartfiles -e<functionName> test.c(30)变量是内存地址的别名
CPU对内存的寻址方式是间接寻址,全局变量内存地址唯一,栈变量(局部变量)不唯一。
# a = 1;mov DWORD PTR [rip + 0x2f18], 0x1 #40402c <a>(31)this 指针 成员函数和普通函数汇编结果相同,只是this指针作为成员函数的默认参数而被隐藏
(32)构造函数
构造函数和普通函数的汇编相同(有this指针),但是派生类的构造函数中其汇编里包含了一个调用(call)基类的构造函数语句。如果基类有虚函数,那么基类构造函数汇编中又新增仅包含其自身的虚函数表的地址,派生类的构造函数汇编中也同样新增仅包含其自身类(不含基类)的虚函数表的地址。
(32)CPU对多态无感 基类指针可以指向派生类对象,反过来不行,派生类指针不可以指向基类对象
- 多态常会用基类指针指向派生类对象;
- 多态会用派生类的结构特点复用基类的成员;
- 多态会用虚函数来拓展派生类的特性;
- 很多语言都有多态(java, c++, python)。
// 基类A,派生类BA* P = &b; // ✔,相当于降级成基类使用B* p = &a; // ✖,不能升级成派生类使用B* p = (B*)&a; // ✔,即使强转换编译通过,但是派生类部分的内容没有分配内存,即使编译通过,调用相关部分时会出现异常int* p = (int*)&b; // 所以无感 (32)指针变量|数组指针|野指针
指针变量和普通变量的读写的汇编结果相同,指针变量的区别是含*操作。指针变量存的是变量的内存地址,直接赋值而不是赋地址,会造成野指针
int* p;*p = 2; // 野指针万物皆指针:
- 指针操作(*,->)不是指针变量特有的,普通变量甚至立即数都可进行指针操作
- 万物皆有地址,万物皆有指针
- 指针可以读写任意内存地址,除了指针管理单元(MMU),知道了私有变量的地址,就可用指针读写
int* p = &a;*p = 1; // ✔*(int*)&a = 1; // ✔*(int*)0x1234 = 1 // ✔ a address is 0x1234;
// e.g. 2 类A的对象a...a.x = 1;
(&a)->x = 1; (33)参数传递|传值|传引用
C++中的引用实际上是对指针的语法糖,它不允许修改引用本身的地址,而指针则可以。此外,C++中的引用在声明后必须被初始化,并且一旦被初始化后不能指向另一个变量。而指针可以在任何时候指向任何地址,包括NULL。
1)传值(Pass by Value):
- 传值是指将实际参数的值复制到一个临时的变量(通常是函数的局部变量)中,然后将其传递给函数。
- 函数接收的是原始值的副本,对参数的修改不会影响到原始数据。
- 这种方式适用于简单数据类型,如整数、浮点数、字符等。
2)传引用(Pass by Reference):
- 传引用是指将实际参数的内存地址传递给函数,函数通过这个地址直接访问和修改原始数据。
- 函数接收的是原始数据的引用,对参数的修改会影响到原始数据。
- 这种方式适用于复杂数据类型,如数组、结构体、类对象等,可以避免复制大的数据结构。
3)传指针(Pass by Pointer):
- 传指针与传引用类似,也是将实际参数的内存地址传递给函数,但传递的是地址的副本。
- 函数通过这个地址的副本来访问和修改原始数据,对参数的修改同样会影响到原始数据。
- 传指针通常用于C语言,它提供了更多的灵活性,如可以传递
NULL指针,或者在函数内部修改指针的值。
传值示例:
void modifyValue(int x) { x = 10; // 修改x的值,但不影响传入的原始值}传引用示例:
void modifyReference(int &x){ // 使用引用作为函数参数 x = 10; // 修改x的值,影响传入的原始值}
// e.g. 2void foo(int *x){ *x = 10; // 通过指针修改了实参}
int main(){ int a = 5; foo(&a); // a 被修改为 10}传指针示例:
void modifyPointer(int *x){ // 使用指针作为函数参数 *x = 10; // 通过指针修改x指向的值,影响传入的原始值}
// e.g. 2void foo(int *x){ *x = 10; // 通过指针修改了实参}
int main(){ int a = 5; foo(&a); // a 被修改为 10}(34)指针的妙用 1)处理TCP/IP layers时 接受网卡的原始数据: TCP/IP Layer: Phthsic → Data link → Internet → Transport → Application
0偏移时候处理以太网数据,偏移sizeof(ethernet_header)处理IP header的数据。
2)芯片制造商会把控制I/O引脚的寄存器与内存统一编地,并提供手册标识出寄存器对应的地址,以便操作寄存器:
void turn_on(){ unsigned int * REG_IO = 0XFF008800; *REG_IO = 1;}
3)对数据流的多样性解析对于一段stream,使用不同类型的指针会解析出不同类型的数据```c++unsigned char* data = raw_data;
//if parse data with struct, the raw_data will be parsed into corresponding struct.struct A{ int a; int b;};struct A *data = raw_data;
<font color =red><b> (35)数组越界不报错情况</b></font>这发生在数组向下低端的情况,即数组向下低端的地址,对应的内存是未被任何使用的。想高端地址溢出不行。```c++lofng a[2];a[1] = 1;a[0] = 2;a[-1] = 3; // 向下偏移a[-2] = 3;(35)std::string::npos
std::string::npos 是 C++ 标准库中 std::string 类的一个静态常量,表示字符串搜索函数没有找到指定的子字符串。npos 的值是 size_t 类型的最大值,通常是一个非常大的数字,用来表示“没有找到”的情况。
if (iRecvResult == 0 || std::string(data, data.size()).find("END_OF_IMAGE") != std::string::npos)(36)子串和子序列
子串和子序列是两个不同的概念,它们在字符序列中的含义如下:
-
子串(Substring):
- 子串是指在原始字符串中连续出现的一系列字符。
- 子串在原始字符串中占据连续的位置,不能跳跃。
- 例如,在字符串 “pwwkew” 中,“pww”、“wwk” 和 “kew” 都是子串。
-
子序列(Subsequence):
- 子序列是原始字符串中字符的序列,但不一定连续。
- 子序列中的字符可以不连续出现在原始字符串中,它们的位置可以是跳跃的。
- 例如,在字符串 “pwwkew” 中,“pwke” 是一个子序列,因为它包含了 “pwwkew” 中的字符 ‘p’、‘w’、‘k’ 和 ‘e’,但它们在原始字符串中不是连续的。
在你给出的例子中,“wke” 是 “pwwkew” 的一个子串,因为它的字符在原始字符串中是连续的。而 “pwke” 虽然包含了相同的字符,但它不是子串,因为它的字符在原始字符串中不是连续的,但它可以是子序列。