C++基础部分复习
C++ fast review
C 数据类型
基本类型:包括两种类型:整数类型和浮点类型。
整数:(不同操作系统上的大小可能不太一致)
- char :1
- unsigned char:1
- signed char :1 ==char
- 下面没有unsiged 默认为signed
- int :4
- short :2
- long :8(主流64,long long也是64)
long 修饰的影响:(修饰int 的时候就等价于前面一部分的内容)
- long long // 至少 64 位
- long int // 与 long 完全等价
- long long int // 与 long long 完全等价
- signed long long // 显式带符号(默认就是带符号)
- unsigned long long
浮点类型:(不分signed 和unsigned )

- float:4, 6位小数,8位指数
- double:8,15位小数,11位指数
- long double :16,19位小数
枚举类型:只能赋予其一定的离散整数值的变量
void 类型
派生类型:包括:指针类型、数组类型、结构类型、共用体类型和函数类
变量
变量声明(种类上包括了定义)
变量声明向编译器保证变量以指定的类型和名称存在
- 一种是需要建立存储空间的。例如:int a 在声明的时候就已经建立了存储空间
- 另一种是不需要建立存储空间的,通过使用extern关键字声明变量名而不定义它。
- 除非有extern关键字,否则都是变量的定义。
extern int i; //声明,不是定义 int i; //声明,也是定义
C 中的左值(Lvalues)和右值(Rvalues)
- 左值(lvalue): 指向内存位置的表达式被称为左值(lvalue)表达式。(左值可以出现在赋值号的左边或右边。)
- 右值(rvalue): 术语右值(rvalue)指的是存储在内存中某些地址的数值。(右值可以出现在赋值号的右边,但不能出现在赋值号的左边)(数值型的字面值是右值)
C 常量(字面量)
常量的值在定义后不能进行修改。
整数常量

前缀指定基数:
- 0x 或 0X :十六进制,
- 0 :八进制,
- 不带前缀:十进制。
后缀:U 表示无符号整数(unsigned),L 表示长整数(long)
浮点常量(有符号注释明确的话就必须要有完整部分)
- 当使用小数形式表示时,必须包含整数部分、小数部分,或同时包含两者。
- 当使用指数形式表示时, 必须包含小数点、指数,或同时包含两者。

字符常量
- 普通的字符(例如 ‘x’)、
- 转义序列(不叫字符叫序列)(例如 ‘\t’),在 Windows 的命令行中,\a 通常会发出"滴"的一声。(抽象完了)

- 通用的字符(例如 ‘\u02C0’)
字符串常量
有两种简单的定义常量的方式:
- 使用 #define 预处理器。
#define LENGTH 10 - 使用 const 关键字。
const int LENGTH = 10;
C 存储
可用的存储类:
- auto(所有局部变量默认的存储类,只能用在函数内)
- register(定义存储在寄存器中而不是 RAM 中的局部变量,最大尺寸等于寄存器的大小)(定义 ‘register’ 并不意味着变量将被存储在寄存器中,它意味着变量可能存储在寄存器中)
- static(在程序的生命周期内保持局部变量的存在,而不需要在每次它进入和离开作用域时进行创建和销毁。)
- 当 static 修饰全局变量时,会使变量的作用域限制在声明它的文件内。
- 全局声明的一个 static 变量或方法可以被任何函数或方法调用,只要这些方法出现在跟 static 变量或方法同一个文件中
- extern:
- extern 存储类用于提供一个全局变量的引用,全局变量对所有的程序文件都是可见的
C 运算符
- 算术运算符
- 关系运算符(比较)
- 逻辑运算符(真假)(&&)
- 位运算符 (逐位执行操作)(A|B = 0011 1101)
- 赋值运算符(%=)
- 杂项运算符(指针,三元运算)
- 优先级:

C 作用域规则
- 局部变量(在某个函数或块的内部)局部变量保存在栈中,只有在所在函数被调用时才动态地为变量分配存储单元。
- 全局变量(定义在函数外部,通常是在程序的顶部)全局变量保存在内存的全局存储区中,占用静态的存储单元;
- 形式参数(函数的参数,形式参数,被当作该函数内的局部变量)
C 数组
声明数组 // 定义 + 声明
type arrayName [ arraySize ];
初始化数组
double balance[5] = {1000.0, 2.0, 3.4, 7.0, 50.0};
double balance[] = {1000.0, 2.0, 3.4, 7.0, 50.0};
传递数组给函数
void myFunction(int *param)
void myFunction(int param[10])
void myFunction(int param[])
这个指针是一个副本指针,跟形参的定义是一致的
从函数返回数组
int * myFunction()
C 不支持在函数外返回局部变量的地址,除非定义局部变量为 static 变量。(在表达式里写 return r; 时,编译器执行数组到指针的退化(array-to-pointer conversion),得到的是 int* 且值等于 &r[0]。)

一些问题的汇总解读:
1. “一个有内容的指针里存的是地址值吗?”
- 是。指针变量本身的位模式就是某个内存地址(虚拟地址)。
- 所谓"有内容"只是这个位模式不是 0/nullptr,而指向一块可访问(希望也是合法)的内存。
2. “我定义的数组 int r[10]; 实际上也是一个地址吗?”
- 不是。
r是数组对象本身,它占用10*sizeof(int)字节的连续内存;- 在大多数值上下文(函数实参、赋值、算术、比较……)里,编译器会把数组名转换成"指向首元素的指针"(type 退化
int*)。 - 这常让人误以为"数组就是指针",但它们在定义、大小、
sizeof、&结果等方面完全不同:
int r[10];
std::cout << sizeof(r); // 40 (10×4)
std::cout << sizeof(&r); // 8 (指针大小)
3. “所以我的函数返回一个数组的时候,返回类型应该为指针对吗?”
C++ 语法根本不允许把"裸数组"写成函数返回类型:
int foo()[10]; // ❌ 直接编译失败
可选方案只有两条路:
A. 返回"指向数组的指针"或"指向首元素的指针"
B. 真正符合现代 C++ 的做法:别返回裸指针,用托管容器
std::vector<int> foo(); // 最常用
std::array<int, 10> foo(); // 大小编译期固定
结论(一句话)
“数组就是数组,指针是指针;函数想’返回数组’时,语法上只能退而求其次返回指针,但更好的做法是直接返回 std::vector / std::array,让语言帮你管内存和拷贝。”
C 指向数组的指针
double balance[50];
balance 是一个指向 &balance[0] 的指针,即数组 balance 的第一个元素的地址。
double *p;
double balance[10];
p = balance;
C 指针
使用指针
ip = &var; /* 在指针变量中存储 var 的地址 */
/* 在指针变量中存储的地址 */
printf("Address stored in ip variable: %p\n", ip );
/* 使用指针访问值 */
printf("Value of *ip variable: %d\n", *ip );
C 指针的算术运算
- 四种算术运算:++、–、+、-。
- 假设 ptr 是一个指向地址 1000 的整型指针,是一个 32 位的整数,让我们对该指针执行下列的算术运算:(跳过的是其指向的对象的大小)
ptr++指针 + 1 跳过 1 个对象的大小,即增加 sizeof(*指针) 字节。
C 指针数组
可能有一种情况,我们想要让数组存储指向 int 或 char 或其他数据类型的指针。下面是一个指向整数的指针数组的声明:
int *ptr[MAX];
可以用一个指向字符的指针数组来存储一个字符串列表(见字符串)
C 指向指针的指针

- 当一个目标值被一个指针间接指向到另一个指针时,访问这个值需要使用两个星号运算符
printf("Value available at **pptr = %d\n", **pptr);
C 传递指针给函数
只需要简单地声明函数参数为指针类型即可
void getSeconds(unsigned long *par);
unsigned long sec;
getSeconds( &sec );
也能接受数组作为参数
double getAverage(int *arr, int size);
int balance[5] = {1000, 2, 3, 17, 50};
double avg;
/* 传递一个指向数组的指针作为参数 */
avg = getAverage( balance, 5 ) ;
当我们需要传递结构体,或者其他较大数据类型时,使用地址传值,这样形参就不会拷贝和原数据一样大的空间了,当然,若是不想改变原地址的数据,则用const修饰
- “用 const 修饰"并不是"复制一份”,而是在编译期加一把"只读"锁
void foo(const int *p){
*p = 42; // ❌ error: assignment of read-only location '* p'
}
C 函数指针
函数指针是指向函数的指针变量。
typedef int (*fun_ptr)(int,int); // 声明一个指向同样参数、返回值的函数指针类型
int max(int x, int y){return x > y ? x : y;}
int main(void){
/* p 是函数指针 */
int (* p)(int, int) = & max; // &可以省略
}
回调函数
函数指针作为某个函数的参数

反向控制,框架变平台
- 库只负责通用流程,把"差异化"代码挖成空壳回调;用户填回调即可,无需改库源码,实现"好莱坞原则"——Don’t call us, we’ll call you。
回调让"流程"与"策略"分离,库做平台,用户做插件,系统更灵活、更松耦、更异步。
C 字符串
实际上是使用 null 字符 ‘\0’ 终止的一维字符数组。(null字符就是’\0’)复习一下:

操作函数汇总:(先第一个参数,再第二个参数)

- strcpy(s1,s2)复制 s2 到s1
- strcat(s1,s2) 连接 s2 到 s1的解位
- strlen(s1) 返回s1的长度
- srrcmp(s1,s2)比较s1 和s2的大小
- strchr(s1, ch):返回一个指针,指向字符串 s1 中字符 ch 的第一次出现的位置。
- strstr(s1, s2):返回一个指针,指向字符串 s1 中字符串 s2 的第一次出现的位置。
C 结构体
定义结构
struct tag {
member-list
member-list
member-list
} variable-list
tag 是结构体标签。member-list 是标准的变量定义,variable-list 结构变量(相当于变量名称),定义在结构的末尾。
struct Point {
int x;
int y;
} p1, p2 = {3, 4}; /* p1 未初始化,p2 初始化为 (3,4) */
struct Point p3;
结构体变量的初始化
- 可以在定义时指定初始值,见上面的内容。
- 也可以:
struct Point p3=...
访问结构成员
成员访问运算符(.) Book1.title
结构作为函数参数
void printBook( struct Books book );
(需要指明是结构题)
指向结构的指针
- 指针变量中存储结构变量的地址:
struct_pointer = &Book1 - 指向该结构的指针访问结构的成员:
struct_pointer->title;
位域
- 有些信息在存储时,并不需要占用一个完整的字节,而只需占几个或一个二进制位。
- 所谓"位域"是把一个字节中的二进位划分为几个不同的区域
- 定义与结构定义相仿:
struct 位域结构名
{
位域列表
};
例如:类型说明符 位域名: 位域长度 (类型说明符说明的是这个struct的总大小)
struct bs{
int a:8;
int b:2;
int c:6;
}data;
运算:
pbit->a=0; /* 用指针方式给位域 a 重新赋值,赋为 0 */
pbit->b&=3; /* 使用了复合的位运算符 "&=",相当于:pbit->b=pbit->b&3,位域 b 中原有值为 7,与 3 作按位与运算的结果为 3(111&011=011,十进制值为 3) */
pbit->c|=1; /* 使用了复合位运算符"|=",相当于:pbit->c=pbit->c|1,其结果为 15 */
C 共用体
在相同的内存位置存储不同的数据类型(意味着会相互覆盖)
union [union tag]{
member definition;
member definition;
member definition;
} [one or more union variables];
- 共用体占用的内存应足够存储共用体中最大的成员。
- 访问共用体的成员通结构体
C 位域(字节存储,如果在赋值的时候超出,直接变为0)
struct{type [member_name] : width ;};
C typedef
使用它来为类型取一个新的名字:typedef unsigned char BYTE;
typedef vs #define
- #define 是 C 指令,用于为各种数据类型定义别名,与 typedef 类似,但是它们有以下几点不同:
- typedef 仅限于为类型定义符号名称,#define 不仅可以为类型定义别名,也能为数值定义别名,比如您可以定义 1 为 ONE。
- typedef 是由编译器执行解释的,#define 语句是由预编译器进行处理的。
C 输入 & 输出
C 语言中的 I/O (输入/输出) 通常使用 printf() 和 scanf() 两个函数。
- scanf() 函数用于从标准输入(键盘)读取并格式化,
- printf() 函数发送格式化输出到标准输出(屏幕)。
#include <stdio.h> // 执行 printf() 函数需要该库
printf()
- %d 格式化输出整数
- %f 格式化输出浮点型数据:想"指定位数"就在 % 和 f 之间插入
.n,其中 n 是你想要的小数位数(可 0 ~ 任意)。
C 文件读写
- 非二进制:open get put close
- 二进制:fread,fwrite
FILE *fopen( const char * filename, const char * mode );(变量的类型是指针)

关闭文件
int fclose( FILE *fp );
写入文件
int fputc( int c, FILE *fp );
int fputs( const char *s, FILE *fp );
例:

二进制 I/O 函数

C 预处理器
- C 预处理器不是编译器的组成部分,但是它是编译过程中一个单独的步骤。是一个文本替换工具
- 所有的预处理器命令都是以井号(#)开头。

C 头文件
头文件是扩展名为 .h 的文件,包含了 C 函数声明和宏定义:常量、宏、系统全局变量和函数原型

C 强制类型转换
(type_name) expression
C 错误处理
- perror() 函数显示您传给它的字符串,后跟一个冒号、一个空格和当前 errno 值的文本表示形式。
- strerror() 函数,返回一个指针,指针指向当前 errno 值的文本表示形式。
C 可变参数
int func(int, ... ){......}
- func() 最后一个参数写成省略号,即三个点号(…)
使用:
- 定义一个函数,最后一个参数为省略号,省略号前面可以设置自定义参数。
- 在函数定义中创建一个 va_list 类型变量,该类型是在 stdarg.h 头文件中定义的。
- 使用 int 参数和 va_start 宏来初始化 va_list 变量为一个参数列表。宏 va_start 是在 stdarg.h 头文件中定义的。
- 使用 va_arg 宏和 va_list 变量来访问参数列表中的每个项。
- 使用宏 va_end 来清理赋予 va_list 变量的内存。
例:

C 内存管理
这些函数可以在 <stdlib.h> 头文件中找到(注意初始化与不初始化)

C 命令行参数
- 从命令行传值给 C 程序。这些值被称为命令行参数
int main( int argc, char *argv[] )argv[1](好像没有argv[0])(0的位置是程序自动填入的,如:argv[0] “./hello.exe”)- 如何输入:
$./a.out testing1 testing2
更多推荐
所有评论(0)