编译器编译过程 :
编译{
预编译: 注释删除、宏替换、头文件包含、条件编译等
编译: 语法检查、符号汇总
汇编: 符号表生成 (存有符号的名称和其存储在内存中的地址) (若某个符号仅声明未定义则符号表中就会存储一份虚拟地址)
}
链接{
合并段表
符号表的合并及重定位
}
C++基础:
{
#include <iostream> // 包含iostream头文件
iostream 库 // 包含两个基础类型: 输入流istream 输出流ostream
'cin' : {
标准输入流 用于从控制台读取输入数据
输入运算符 '>>' 默认情况下跳过空白符 读入后面与变量类型对应的值(给一组变量赋值时可用空格符 回车符 制表符将输入数据间隔开)
输入字符串时 跳过空白符 读入非空白字符 直到另一个空白字符为止 并在串尾放置字符串结束标志 '\0'
eg:{
int cinX ;
cin >> cinX ; // 读取变量x
}
}
'cout' : {
标准输出流 用于向控制台输出数据
输出运算符 '<<'
eg:{
cout << "Hello, world!" ; // 输出字符串 "Hello, world!"
}
}
标准错误:
cerr 用于输出错误信息
运行时信息:
clog 用于输出运行时信息
'endl' : 刷新缓冲区 即换行
'::' : {
作用域标识符: 用于区分同名的变量和函数 作用域指的是变量或函数的可访问范围 全局作用域 局部作用域 命名空间作用域
当全局变量与函数中某个局部变量重名 则可通过'::'来区分
eg:{
int zozoX; //全局变量
int anyfunc() {
int zozoX; //局部变量
::zozoX = ::zozoX * zozoX; // 其中 '::zozoX' 指代全局变量 'zozoX'指代局部变量
return ::zozoX;
}
}
可通过 '命名空间名称 :: 命名空间成员' 的方式访问命名空间成员
eg:{
std::cout << "Hello, world!" ; // 输出字符串 "Hello, world!"
注释: std 命名空间 cout是该命名空间的成员 std::cout 访问该命名空间的cout成员
}
假设 A、B 表示两个类 在A、B中都有成员member
那么可以通过 A::member 和 B::member 访问各自的member
假设声明了一个类Zozo ,声明了一个成员函数zozoFunc(), 在类中未给出定义 则类外定义时使用 '类名::成员函数名(形参表)'
eg:{
class Zozo {
public:
int zozoFunc();
...
};
int Zozo::zozoFunc() // 类名::成员函数名(形参表)
{
...
}
}
}
'const' 常量限定符:{ 修饰常量 const对象必须初始化
const float PI = 3.14 ; // 此时PI是个常量 不能修改 类似于宏定义 #define PI 3.14
float const PI = 3.14 ; // 与上例等价
/* 若想在多个文件之间共享const对象 则需要在定义变量之前加上 extern */
extern const int buffer = 695; //定义
extern const int buffer; // 外部调用形式
指向常量的指针:一个指向常量的指针变量 '非const指针 const数据'
{
const char* ptr = "abcd"; //指针变量ptr指向一个常量字符串 'abcd' const位于*右侧
ptr[3] = 'x' ; // error: 不能修改常量字符串的内容
ptr = "efgh"; // 指针是变量 可以改变ptr所指的地址
}
常指针:将指针变量所指的地址声明为常量 'const指针 非const数据'
{
char* const ptr1 = "myName"; //指针常量ptr1指向一个字符串 "myName" const位于*右侧
ptr[3] = 'L' ; // 可以修改ptr1所指的地址的内容
ptr = "world!" ; // error: 不能修改指针ptr1指向的地址
}
指向常量的常指针:指针指向的地址及地址中的内容均不可改变 'const指针 const数据'
{
const char* const ptr2 = "you are my hart"; // 指针常量ptr2指向常量字符串 const位于*两边
}
总结: '左定值 右定向 const修饰不变量'
常量一旦建立 任何地方都不能修改
}
/* ----------- practice 1.0 -----------*/
#include <iostream> // for input/output operations
int main()
{
int zozoX , zozoY;
int zozoSum = 0;
std::cout << "please enter the value of zozoX and zozoY: " << std::endl;
std::cin >> zozoX >> zozoY ;
std ::cout << std::endl;
zozoSum = zozoX + zozoY;
std::cout << "The sum of zozoX and zozoY is: " << zozoSum << std::endl;
int zozoR = 15;
const float zozoPI = 3.14;
// zozoPI = 3.14159; // error: assignment of read-only variable 'zozoPI'
float zozoArea = zozoPI * zozoR * zozoR;
std::cout << "The area of zozoCircle is: " << zozoArea << std::endl;
char zozoStr[5] = "zozo";
const char *zozoName = zozoStr; // 指向常量字符串的指针变量
// zozoName[3] = 'L'; // error: assignment of read-only location 'zozo'
zozoName = "Tom";
std::cout << "The myname is: " << zozoName << std::endl;
std::cout << "The address of myname is: " << &zozoName << std::endl;
std::cout << "The address of zozoStr is: " << &zozoStr << std::endl;
int* const zozoNewPtr = &zozoR; // 指向变量的指针常量
*zozoNewPtr = 100;
// zozoNewPtr = &zozoSum; // error: assignment of read-only variable 'zozoNewPtr'
std::cout << "The value of zozoR is: " << *zozoNewPtr << std::endl;
std::cout << "The address of zozoR is: " << zozoNewPtr << std::endl;
const int *const zozoPtr = &zozoSum; // 指向常量的常指针
// *zozoPtr = 100; // error: assignment of read-only variable 'zozoPtr'
// zozoPtr = &zozoX; // error: assignment of read-only variable 'zozoPtr'
std::cout << "The value of zozoSum is: " << *zozoPtr << std::endl;
std::cout << "The address of zozoSum is: " << zozoPtr << std::endl;
return 0;
}
'void' :{
通常表示无值 将void作为指针类型时 表示不确定类型 void型指针是一种通用型指针 任何类型的指针值都可以赋给void类型
已获值的void型指针 处理时 须进行显示类型转换
void *pc;
int i = 123;
char str = 'a';
pc = &i;
cout << pc << endl; // 输出指针的地址
cout << *(int*)pc << endl; // 输出值123
pc = &str;
cout << *(char*)pc << endl; // 输出值a
}
'inline' :{
函数名前冠以 inline 关键字 表明该函数是内联函数 编译器将在调用该函数的地方将其展开 使得程序运行速度更快
inline int zozoAdd(int zoa, int zob) {
return zoa + zob;
}
int main() {
int zozoRes = zozoAdd(10, 20);
return 0;
}
注释 :内联函数以空间换时间 内联函数体内一般不含复杂语句 如for、switch等
内联函数不宜冗长且频繁调用 inline函数的定义最好放在头文件中
}
带有默认参数的函数:{
进行函数调用时 编译器从左至右依次将实参与形参结合 若未指定足够实参 则使用默认值
void init(int x = 10, int y = 9);
init(100, 20); //100 , 20
init(40); //40 , 9
init(); //10 , 9
注释: 带默认值的参数必须从从右至左依次出现
void init(int x, int y, int z = 100);
void init(int x, int y = 30, int z = 100);
void init(int x, int y = 30, int z); // error!!!!!!!!!!!
如果函数声明和函数定义分开写 函数声明和函数定义不能同时设置默认参数 建议函数声明时设置参数
eg:{
int zozoFunc(int x = 10, int y = 20);
int main()
{
cout << zozoFunc() << endl;
return 0;
}
int zozoFunc(int x, int y)
{
return x + y;
}
}
}
/* ---------------------- pratice 1.1 --------------------------- */
#include <iostream> // for input/output operations
using namespace std; // 声明命名空间
inline int add(int a, int b); //内联函数
int main()
{
int zozoI = 10;
char zozoC = 'a';
void *zozoPtr = nullptr; // void型指针 即通用指针
zozoPtr = &zozoI; // 已获值指针
cout << "The value of zozoI is: " << *(int*)zozoPtr << endl; // 进行显示类型转换
zozoPtr = &zozoC;
cout << "The value of zozoC is: " << *(char*)zozoPtr << endl; // 进行显示类型转换
cout << "The address of zozoPtr is: " << zozoPtr << endl;
cout << "The address of zozoC is: " << &zozoC << endl;
char zozoBuf[10] ="hello";
char *zozoBufPtr = zozoBuf;
cout << "address of zozoBuf: " << &zozoBuf << endl; // 输出 0x7ffffb542a1e 地址
cout << "address of zozoBuf: " << (int*)zozoBuf << endl; // 输出 0x7ffffb542a1e 地址
cout << "zozoBuf: " << zozoBuf << endl; // 输出 hello 即数组buffer的内容
cout << "zozoPtr: " << zozoBufPtr << endl; // 输出 hello 即数组buffer的内容
cout << "address of zozoPtr: " << (int*)zozoBufPtr << endl; // 输出 0x7ffffb542a1e 地址 即zozoBuf的地址
cout << "address of zozoPtr: " << &zozoBufPtr << endl; // 输出zozoBufPtr本身的地址 即指针的地址 与数组地址不同
int zozoX, zozoY;
cout << "Enter two numbers for zozoX and zozoY: " << endl;
cin >> zozoX ;
cin >> zozoY ;
int zozoSum = add(zozoX, zozoY); // 调用内联函数
cout << "The zozoSum is: " << zozoSum << endl;
double IntX = 10.99;
int DoubleY = (int)IntX;
cout << "The value of DoubleY is: " << DoubleY << endl;
return 0;
}
inline int add(int a, int b)
{
return a + b;
}
函数重载:{
同一作用域 函数参数列表(类型or个数or顺序)一个及以上不同 但函数名称相同 称为函数重载
int add(int a, int b)
{
return a+b;
}
double add(double a, double b)
{
return a+b;
}
int add(int a, int b, int c)
{
return a+b+c;
}
int main() {
int a=6, b=9, c=5;
double d=3.14, e=2.71;
cout << add(a,b) << endl; // 输出 15
cout << add(d,e) << endl; // 输出 5.85
cout << add(a,b,c) << endl; // 输出 20
return 0;
}
注释: 只有返回值类型不同的函数 不允许重载
若函数重载与带默认值函数同时使用 可能引起二义性
若给出实参和形参类型不相符 可能产生不可识别错误
}
强制类型转换:{
int x = 10;
double y = double(x); // 强制类型转换 整数转浮点数 或者 double y = (double)x;
}
'new' 和 'delete' :{
同c语言中的 malloc 和 free 函数 分配和释放堆区内存
格式 : 指针变量名 = new 类型;
delete 指针变量名;
eg:{
int *p ;
p = new int ;
delete p ;
}
注释:
new分配的空间 结束后用delete释放 否则该部分空间变为不可回收的死空间
使用new分配内存时 不能满足分配要求 则new返回空指针NULL
new 可为数组动态分配内存及释放 形式如下:
指针变量名 = new 类型 [下标表达式];
delete [] 指针变量名;
eg:{
int *p = new int[10];
delete [] p;
}
new 可在为简单变量分配空间时进行初始化 形式如下:
指针变量名 = new 类型(初值);
eg:{
int *p;
p = new int(99); // p指向一个值为99的int型变量
delete p;
}
}
/* ----------- practice 1.2 -----------*/
#include <iostream> // for input/output operations
using namespace std;
int main()
{
int *p;
p = new int; // 为指针分配内存
cout << "The 1st value of p is: " << *p << endl;
delete p;
p = new int(695); // 为指针分配内存 并设置初值
cout << "The 2nd value of p is: " << *p << endl;
delete p;
p = new int[5]; // 为指针数组分配内存 该数组有5个元素
p[2] = 69;
cout << "The value of p[2] is: " << p[2] << endl;
delete[] p;
int x = 42;
int &r = x; // 引用变量
cout << "The value of x is: " << x << endl;
cout << "the value of r is :" << r << endl;
cout << "The address of x is: " << &x << endl;
cout << "the address or r is: " << &r << endl;
return 0;
}
引用:{
变量的引用就是变量的别名 故引用又称别名
引用与其代表的变量共享一内存单元 系统不为引用另外分配存储空间 引用及其代表的变量具有相同地址
格式:类型 &引用名 = 已定义变量名; //(类型& 引用名 = 已定义变量名 or 类型 & 引用名 = 已定义变量名)
eg:{
int x = 10;
int &j = x; // int& j = x; int & j = x;
cout << "j = " << j << endl;
cout << "i的地址为 " << &i << endl;
cout << "j的地址为 " << &j << endl;
}
注释: 引用非独立数据类型 必须与某一变量联系 且声明时需立即初始化
指针通过地址间接访问变量 引用通过别名直接访问变量
引用可以被用作函数参数 也可以被用作函数的返回值
eg:{
void swap(int &a, int &b) // 引用作为函数参数
{
int temp = a;
a = b;
b = temp;
}
int a[] = {3, 4, 5, 6, 7};
int& get_datastr(int i) // 引用作为函数返回值
{
return a[i];
}
}
不允许建立void类型引用 不能建立引用的数组 不能建立引用的引用 不能建立指向引用的指针
可以将引用的地址赋值给一个指针 此时指针指向原变量
可以用const修饰引用 此时不允许通过引用改变变量的值 但不阻止原变量的值被改变
}
/* ----------- practice 1.3 -----------*/
#include <iostream> // for input/output operations
using namespace std;
void swap(int &a, int &b) // 引用作为函数参数
{
int temp = a;
a = b;
b = temp;
}
int a[] = {3, 4, 5, 6, 7};
int& get_datastr(int i) // 引用作为函数返回值
{
return a[i];
}
int main()
{
int a1 = 12 , b1 = 11;
swap(a1, b1);
cout << "a1 = " << a1 << "b1 = " << b1 << endl;
int testIndex = 2;
cout << "The value of a[" << testIndex << "] is: " << get_datastr(testIndex) << endl;
get_datastr(testIndex) = 100;
cout << "changed The value of a[" << testIndex << "] is: " << get_datastr(testIndex) << endl;
int num = 10;
int &renum = num;
int *pointer ;
pointer = &renum;
cout << "The value of num is: " << num << endl;
cout << "The value of renum is: " << renum << endl;
cout << "the address of num is: " << &num << endl;
cout << "the address of renum is: " << &renum << endl;
cout << "the address of pointer is: " << pointer << endl;
const int& renum2 = num;
cout << "The value of renum2 is: " << renum2 << endl;
// renum2 = 20; // error: assignment of read-only variable 'renum2'
num = 30;
cout << "The value of num is: " << num << endl;
cout << "The value of renum2 is: " << renum2 << endl;
return 0;
}
}