# typedef

typedef 并不是简单的宏替代。

  • 定义一种 类型的别名
  • 定义 struct结构体别名
  • 用 typedef 来定义与 平台无关 的类型
  • 复杂的声明 定义一个 简单的别名 ,表示的是一个指向 函数的指针
  • typedef 可以定义 各种类型别名 ,但不能定义变量
  • 使用 typedef 便于 程序的通用
  • typedef 只是将一个已经存在的类型用一个 新的名称 替代
  • typedef不 能添加 新类型

# typedef#define 区别

typedef 是一种 类型别名 ,而 #define 只是 宏定义 ,二者 并不总是 可以 互换 的。

# 比较函数

C++ 的比较函数适用于 整型字符串浮点数 等多种类型。

# max

返回队列中的 最大值 ,参数 两个 参数,如果想要 多个参数 ,使用 大括号初始化列表容器 的形式可以,但相比于直接两个 两个比较比较耗时

#include <iostream>
#include <algorithm>
using namespace std;
int main(void)
{
	float a = 1.359;
	float b = 1.823;
	float c = 1.829;
	auto result = max({ a, b,c });
	cout << result << endl;
	return 0;
}

# min

返回 队列 中的 最小值

# minmax

算法标头的库函数,用于查找 最小和最大值 ,它接受两个值并返回一对最小和最大值,该对中的第 一个 元素包含最 小值 ,并且该对中的第 二个 元素包含 最大值

该函数包括 <algorithm> 头文件,

#include <iostream>
#include <algorithm>
using namespace std;
int main(void)
{
    // 字符串类型同样应用于比较,会以 ASCII 码值进行对比
	int a = -10;
	int b = -20;
	auto result = minmax(a, b);
	cout << "最小值" << result.first << endl;
	cout << "最大值" << result.second << endl;
	return 0;
}

# 友元

在函数前加 friend

友元 成员函数 ,但是它可以访问 类中私有保护 成员。

提高了程序的 运行效率 ,但是破坏了类的封装和隐藏,使得非成员函数可以访问类的私有成员。

  • 友元具有 不对称性 ,即 A 是 B 的友元,但 B 不一定是 A 的友元, 单向的 ,不具有交换性

  • 友元关系 不具传递性

  • 友元关系 不能被继承

# main 参数

main 函数有三个参数, argcargvenvp

int main(int argc,char*argv[],char*envp[])
{
    
}
// **int argc: 存放了命令行参数的个数
//char argv [] 是个字符串的数组,每个元素都是一个字符指针,指向一个字符串,即命令行中的每一个参数
//char envp [] 也是一个字符串的数组,这个数组的每一个㢝是指向一个环境变量的字符指针

#

image-20230716092743942

  • floatdoublelong double 等类型 不允许 直接进行 位与 操作符

  • float取地址 (也是符号) 转换为 unsigned int 类型,再用取值操作符 ( * ), 编译器会识别为 unsigned int类型

  • 使用 int short long移位 时,最好加上 unsigned ,这样就是 汇编中规律移位 (即全部移位)

  • 加入不加 unsigned,正数全是规律 移位 ,负数 左移 保持符号位为 1 ,右边补 0 ,负数右移时保持 符号位为1左边补1 ,所有 - 1 无论怎么右移都是 - 1

  • 位与操作符的操作优先级小于 移位操作符,但移位操作符小于取地址操作符 (取值操作符 *・*)

# static

静态数据成员 类内定义 ,就必须在 类外初始化

特点 :

  • 所有成员都 共享 数据成员,只有 一份内存
  • 必须在 类外 进行 初始化

# 静态数据成员的内存?

存放在内存的全局区

内存分配

# 基类的静态数据成员不能被继承

  • 继承:继承是 一个类另一个类 获取 成员变量成员函数 的过程 (子类继承父类)

基类继承

继承特性:

  • 继承 访问 父类 私有属性
  • 但是 有继承 已经被 继承,被编译器 隐藏
  • 静态成员属性不会被继承 (属于全部对象)
  • 创建子类时, 构造函数 的调用, 先父类后子类析构 时: 先子类后父类
  • 构造函数析构函数赋值操作符 不能被继承

无论什么继承,子类 可以访问 基类中公共保护 成员,但 子类对象 就只能访问 子类的公共成员

在析构时:

  • 释放子类 的指针对象时,会调用 子类和父类 的析构函数
  • 当释放子类的指针对象时,只会调用 父类的析构函数
#include <iostream>
using namespace std;
class person// 父类
{
public:
	person() { cout << "person的构造函数" << endl; }
	~person() { cout << "person析构函数" << endl; }
};
class son :public person
{
public:
	son() { cout << "son的构造函数" << endl; }
	~son() { cout << "son的析构函数" << endl; }
};
int main()
{
	son* s = new son;// 定义一个子类指针
	person* p = s;// 父类指针指向子类
	//delete s;// 释放子类内存 // 会调用子类和父类的析构函数
	delete p;  // 释放父类 只会调用父类的析构函数
	return 0;
}

# 据成员 什么必须 类外初始化

静态数据成员 也属于 静态变量 ,属于 静态全局区 ,全局区的变量,随着程序生死。而 对象 不是全局静态区的,是有 生命周期的 。由于生命周期的不同,所以必须在类外初始化,来解决类的生命周期问题。

  • static 加强了 访问控制全局变量继承
  • 类和子类对象, static 变量 占有 一份 内存

# 结构体内存

结构体内存规则

  • 第一个成员在与结构体变量 偏移量为0地址处
  • 其他成员变量 要对齐到 对齐数的整数倍地址处
  • 对齐数 = min (编译器默认的对齐数,该成员大小)
  • 结构体 总大小最大对齐数 (每个成员变量都有一个 对齐数 ) 的 整数倍
  • 如果 嵌套了结构体 的情况,嵌套的结构体 对齐 到自己大的 最大对齐数的整数倍处结构体的整体大小 就是所有 最大对齐数 (函嵌套结构体的对齐数) 的 整数倍

# C 语言

# 变量类型

  • register :建议 编译器 将该变量放入 CPU

# 函数 类型缺省

  • 返回值
    • C 语言,如果函数 未指定 返回值类型,则・ 默认int
    • C++ 如果函数 没有返回值 ,默认类型必须指定为 void
  • 参数列表
    • C语言 ,如果函数没有指定参数列表,返回值类型必须指定为 void
    • C++ 中,有 严格的类型检测 ,没有参数列表的函数 默认为void , 接受 任意参数
  • 缺省参数
    • C不支持
    • C++支持 ,如果没有指定实参则使用缺省值,有则使用指定实参
      • 默认实参必须在 参数列表的结尾
      • 默认参数只能出现在函数声明或者定义二选一中
      • 缺省值 必须常量或全局变量
      • 缺省参数必须是 值传递 或者 常参传递
  • 函数重载
    • C: 不支持
    • C++:支持

# 转义字符

  • \t 表示横向指标
  • \v 表示竖向制表
  • \b 表示退格
  • \r 表示回车
  • \f 表示换页
  • \? 表示问号字符
  • \0 表示空字符(null)

# 指针大小

  • 指针 ,在 64bit 的机器中是 8字节int 4 字节

# 读取

  • getchar : 读取 一个字符
  • %2d : 读取 数字限定 两个字符,如读取的指针位置 后面 出现字母 忽略掉前面 出现字母将 全部忽略 ,指针移动到读取截止为止。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
    char c1, c2;
    int a1, a2;
    c1 = getchar(); // 读取第一个字符 1
    scanf("%2d", &a1);  // 读取宽度为两个,int 型,只读取 2
    c2 = getchar();  // 读取 a
    scanf("%3d", &a2);  // 宽度为 3,读物 345
    printf("%d,%d,%c,%c\n", a1, a2, c1, c2);
    return 0;
}
/*
输入: 12a345b789
输出: 2,345,1,a
*/

# 优先级

成员选择符 -> 的优先级比 前置++ ,和 后置++ 都要

C语言运算符优先级

# 字符串未赋值部分

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
    int a[3][3] = { {1,2},{3,4},{5,6} }, i, j, s = 0; // 最后一个没有赋值的为 0
    for (i = 1; i < 3; i++)
    {
        for (j = 0; j <= i; j++)
        {
            s += a[i][j];  //a[2][2] = 0
        }
    }
    printf("%d\n", s++);
    return 0;
}
/*
输出: 18
*/

# 表达式等级类型

基本类型字符串 从低到高 如下,运算的时候,从 低转到高 ,表达式的 类型自动提升为参与表达式求值最上级类

  • char
  • int
  • long
  • float
  • double

# 字符串操作

字符串时字符数组的一种形式,它以 "\0" 结尾

  • strcpy() : 复制字符串
  • strcmp() : 比较字符串
  • strlen() : 计算字符串的 长度 ,遇到 \0时 结束 计算不算\0 , 且 从1 开始计数。
// 将字符串 source 拷贝到字符串 destination 中
// 函数返回 destination 字符串
strcpy(char destination[], const char source[]);
// 将字符串 source 中前 numchars 个字符拷贝到字符串 destination 中
// 注意 source 中 numchars 个字符将覆盖掉字符串 destination 中前 numchars 个字符
// 函数返回 destination
strncpy(char destination[], const char source[], int numchars);
// 将字符串 source 接到字符串 target 的后面,要提前确保 taeget 有足够的空间
// 函数返回 target
strcat(char target[], const char source[]);
// 将字符串 source 的前 nnumchars 个字符接到字符串 target 的后面
strncat(char target[], const char source[], int numchars);
// 比较 first 是否大于 second,成功大于 0,
int strcmp(const char firststring[], const char secondstring);
// 统计长度
// 统计字符串 string 中字符的个数
strlen( const char string[]);

# 参考资料

  • C++ 继承
  • typedef
  • C 语言字符串操作总结大全