C++是C语言的继承,支持多重编程模式,例如过程化程序设计、数据抽象、面向对象程序设计、泛型程序设计和设计模式等

常量 (constant)

 

  1. define 宏常量

    #define 常量名 常量值

    • 通常在文件上方
  2. const 修饰的变量

    const 数据类型 常量名 = 常量值

     


 
 

标识符命名规则

 

  • 标识符不能是关键字
  • 只能由字母、数字、下划线组成
  • 第一个字母必须为字母或下划线(不能是数字)
  • 区分大小写

 
 

数据类型

 

sizeof 关键字

语法: sizeof(数据类型/变量)

作用:得到该类型的数据所占用的空间

实型(浮点型)

数据类型占用空间有效数字
float4字节7位有效数字
double8字节15~16位有效数字

举例

float f1(3.14f);//末尾可以加f

double d1(3.14);//不加f默认是双精度

//科学计数法
float f2(3e-2);

字符型

  • 语法:

char ch1('a');

char ch2(97);//直接使用ASCII编码赋值

  • 需要用 单引号 ,不能用双引号
  • 只能存储一个字母

占用空间:1字节

存储方式是ASCII编码, 是有序类型

可以使用(int)ch得到ASCII码

字符ASCII码
048
@64
A65
a97

转义字符

字符含义
\n换行符
\\\
\t水平制表符

字符串型

  • C风格字符串

char 变量名[]("字符串值");

  • C++风格字符串

string 变量名("字符串值");

  • 需要 #include <string>

布尔类型

  1. true --- 真(本质是1)

    • 非零都为真
  2. false --- 假(本质是0)

bool类型占用1个字节


 

自动类型推导

auto

auto根据=后面的值进行类型推导

int a = 10;
auto b = a;

 

auto的自动类型推导发生在编译期,不会造成运行效率的降低

 

注意事项:

  • auto声明的变量必须初始化
  • auto不能被声明为返回值,不能作为形参,不能被修饰为模板参数(只能用于类的静态成员)
     

decltype

decltype根据()里面的值进行类型推导,可以用于类的非静态成员

 

decltype是类型说明符,可以返回操作数的数据类型

decltype不会实际计算表达式的值,而是让编译器分析表达式,得出变量类型

 

语法:

decltype (expression)

 

int a(0);
decltype(a) b = a;
decltype(a + 10) c;

 

推导规则:decltype(e)

  • 若e是左值表达式

    • 如果e是一个名字,得到e的类型 decltype(a), decltype(func())
    • 如果e不是一个名字,得到左值引用 decltype((a)), decltype(c = a + b)
  • 若e是纯右值,得到e的类型 decltype(0)
  • 若e是将亡值,假设e的类型为T,则得到T&&

 


 
 

运算符

 

算术运算符

  • / 两个整型的数相除,结果是整数, 舍弃小数部分
  • % 关于负数的模运算:

由于C/Java采用Truncate除法(向0取整),模运算值的符号和被模数相同

表达式结果
-17 % 10-7
17 % -107
-17 % -10-7
运算符术语示例结果
++前置递增a=2;b=++a;a=3;b=3;
++后置递增a=2;b=a++;a=3;b=2;
--前置递减a=2;b=--a;a=1;b=1;
--后置递减a=2;b=a--;a=1;b=2;

逻辑运算符

运算符术语示例结果
!!a
&&a && b全真为真,否则为假
|a || b全假为假,否则为真

双冒号作用域运算符 ::

#include <iostream>
using namespace std;

int atk = 1000;

void test01(){
    int atk = 2000;
    cout<<atk<<endl;    //输出2000
    //如果::前没有任何内容,代表使用全局作用域
    cout<<::atk<<endl;  //输出1000
}
int main(){
    test01();
    return 0;
}

 
 

命名空间 (namespace)

 

用途:解决名称冲突

  • game1.h

    #include <iostream>
    using namespace std;
    namespace LOL{void goAtk();}
  • game1.cpp

    #include "game1.h"
    void LOL::goAtk(){cout<<"LOL的goAtk实现"<<endl;}
  • game2.h

    #include <iostream>
    using namespace std;
    namespace GoK{void goAtk();}
  • game2.cpp

    #include "game2.h"
    void GoK::goAtk(){cout<<"GoK的goAtk实现"<<endl;}
#include <iostream>
#include <game1.h>
#include <game2.h>
using namespace std;
//1.解决名称冲突
void test01(){
    LOL::goAtk();
    GoK::goAtk();
}
//2.命名空间下 可以存储变量、函数、结构体、类
//3.命名空间必须声明在全局作用域下
namespace A
{
    int m_A = 10;
    void func(){}
    struct Person{};
    class Animal{};
}
//4.命名空间可以嵌套
namespace B
{
    int m_A = 10;
    namespace C
    {
        int m_A = 20;
    }
}
void test03()
{
    cout<<"B空间下的m_A = "<<B::m_A<<endl;
    cout<<"C空间下的m_A = "<<B::C::m_A<<endl;
}
//5.命名空间是开放的,可以随时向空间中添加新成员
namespace B
{
    int m_B = 30;
}
//6.命名空间可以是匿名的
namespace
{
    int m_C = 100;
    int m_D = 200;
}
void test06(){
    cout<<"m_C = "<<m_C<<endl;
    cout<<"m_D = "<<::m_D<<endl;
}
//7.命名空间可以起别名
namespace veryLongName
{
    int m_E = 1000;
}
void test07(){
    namespace shortName = veryLongName;
    cout<<shortName::m_E<<endl;
}
int main(){}

using声明和using编译指令

#include <iostream>
using namespace std;

namespace LOL
{
    int sunWuKongID = 1;
}
void test01()
{    
    //1.using声明
    //int sunWuKongID = 2; //如果有这句会冲突
    using LOL::sunWuKongID;
    cout<<sunWuKongID<<endl;
}
void test02()
{
    //2.using编译指令
    //int sunWuKongID = 2; //如果有这句会输出2
    using namespace LOL;
    cout<<sunWuKongID<<endl;
}

 

流程结构

 
 

顺序结构

//预编译指令,引入头文件iostream
#include <iostream>
//使用命名空间:std
using namespace std;

int main(){
    cout<<"hello world"<<endl;  //endl:end line 刷新缓冲区并换行
    return EXIT_SUCCESS;  //返回正常的退出值
}

选择结构

if语句

关键词: if , else if , else

三目运算符 c ? x : y

在C++中三目运算符返回的是变量,可以继续进行赋值

switch语句

switch(expression)    //整型或字符型
{
    case 常量表达式1:
        执行语句1;     //执行语句一直到下一个break终止
        break;
    case 常量表达式2:
    case 常量表达式3:  //可共用执行语句
        执行语句2;
        break;
    
    //...
    default: 执行语句; //非必需
}

循环结构 (Loop)

  • 指定运行次数的循环

    • for loop
  • 指定条件的循环

    • while loop
    • doWhile loop

 

Range-based for loop

基于范围的for循环:

for(declaration : expression){
    statement;
}

 

解释:

  • expression是要遍历的序列
  • declaration定义一个变量,每次迭代,这个变量会被初始化为expression的下一个元素的值

 

举例:

int a[] = {1,2,3,4,5};
for(int i:a)
    cout<<i<<" ";

 

自定义类的实现条件:

有迭代器、begin(), end()成员方法、重载!=比较操作, ++前置递增,和*解引用操作


跳转语句

break

作用: 跳出选择结构或循环结构

break使用的时机:

  • 出现在switch语句中,终止case并跳出switch
  • 出现在循环语句中,跳出当前的循环语句
  • 出现在嵌套循环中,跳出最近的内层循环语句

continue

在循环语句中,跳过本次循环余下尚未执行的语句,继续下一次循环

goto

  • 作用: 可以无条件跳转语句
  • 语法: goto 标签;

    • 标签一般用全大写单词表示 FLAG : cout<<"*";

 

数组 (array)

 

一维数组

  • 定义和初始化
  1. int a[5]={1,2,3,4,5}; //等号可省略
  2. int a[]={1,2,3,4,5};
  3. int x[10]={0,1,2,3,4}; //给前五个元素赋值,其余值为0
  4. int a[5]={}; //全部初始化为0
  • 注意事项:

    1. 下标从0开始计数,例如,元素a[10]并不在数组a[10]之内
    2. 数组很大时,要在 main 函数之外声明,在 main 函数之内时,数组稍大就会异常退出
    3. 定义在int main()之内的数组不初始化,数值是==随机==的,定义在外面的数值默认是0
  • 一维数组数组名

一维数组数组名的用途:

int main(){
    
    //1. 可以获取数组空间大小
    int a[10]={};
    cout<< "整个数组所占空间为: "<< sizeof(a) <<endl;
    cout<<"每个元素所占空间为: "<< sizeof(a[0]) <<endl;
    cout<<"数组的元素个数: "<< sizeof(a) / sizeof(a[0]) <<endl;
    
    //2. 可以通过数组名获取到数组的首地址
    cout<< "数组首地址为: "<< a <<endl;
    cout<< "数组第一个元素的地址: "<< &a[0] <<endl;   //结果是相同的
    
    return 0;
}

二维数组

  • 定义和初始化
  1. int a[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
  2. int a[2][3]={1,2,3,4,5,6};
  3. int a[][3]={1,2,3,4,5,6}; //如果初始化了数据,可以省略行数,不能省略列数
  • 二维数组数组名
int main(){
    
    //1. 可以获取数组空间大小
    int a[2,3]={
        {1,2,3},
        {4,5,6}
    };
    cout<<"二维数组的大小: "<< sizeof(a) <<endl;
    cout<<"二维数组一行的大小: "<< sizeof(a[0]) <<endl;
    cout<<"二维数组每个元素的大小: "<< sizeof(a[0][0]) <<endl;
    cout<<"二维数组的行数: "<< sizeof(a) / sizeof(a[0]) <<endl;
    cout<<"二维数组的列数: "<< sizeof(a[0]) / sizeof(a[0][0]) <<endl;
    
    //2. 可以查看数组的首地址
    cout<<"二维数组首地址为: "<< a <<endl;
    cout<<"二维数组第一行首地址: "<< a[0] <<endl;
    cout<<"数组第一个元素的地址: "<< &a[0][0] <<endl;   //结果是相同的
    
    return 0;
}

 


 

文件操作

 
文件类型分为两种:

  1. 文本文件:文件以文本的ASCII码形式存储
  2. 二进制文件:文件以文本的二进制形式存储

一、文件输入输出流

头文件:<fstream>

操作文件的三大类:

  1. ifstream:读操作
  2. ofstream:写操作
  3. fstream:读写操作

文件打开方式:

打开方式解释
ios::in为读文件而打开文件
ios::out为写文件而打开文件
ios::ate初始位置:文件尾
ios::app以追加方式写文件
ios::trunc如果文件存在先删除,再创建
ios::binary二进制方式

文件打开方式可以配合使用,利用&#124操作符

例如:用二进制方式写文件 ios::binary &#124 ios::out

文本文件 - 读

//1.包含头文件
#include <fstream>
//2.创建流对象
ifstream fin;
//3.打开文件并判断是否打开成功
fin.open("文件路径", 打开方式);
//4.读取数据
//四种方式读取;
//5.关闭文件
fin.close();

The >> operator returns a "not failed" condition:

if(fin >> buf)
{
    // Process input
}

The open method also sets a "not failed" condition:

fin.open(filename.c_str());
if(fin.fail()){return 0;}

Open method accept only c type string:

string fname;cin>>fname;
ifstream fin;
fin.open(fname.c_str());

读取文件的四种方式:

  • char buf[1024] = {0};
    while(fin >> buf){
        cout<<buf<<endl;
    }
  • char buf[1024] = {0};
    while(fin.getline(buf, sizeof(buf))){...}
  • string buf;
    while(getline(fin,buf)){...}
  • char c;
    //EOF: end of file
    while( (c = fin.get()) != EOF ){cout<<c;}

文本文件 - 写

//1.包含头文件
#include <fstream>
//2.创建流对象
ofstream fout;
//3.打开文件
fout.open("文件路径", ios::out);
//4.写入数据
fout<<"写入的数据";
//5.关闭文件
fout.close();

二进制文件 - 写

以二进制方式对文件进行读写操作

打开方式要指定为 ios::binary

二进制方式写文件主要利用流对象调用成员函数 write

函数原型:ostream& write(const char* buffer, int len);

注:字符指针bufer指向内存中一段存储空间,len是读写的字节数

class Person{
public:
    char m_Name[64];
    int m_Age;
};

void test01(){
    ofstream fout("person.txt", ios::out | ios::binary);

    Person p = {"张三", 18};
    fout.write(reinterpret_cast<const char *>(&p), sizeof(Person));

    fout.close();
};
int main(){test01();return 0;}

二进制文件 - 读

二进制方式读文件主要利用流对象调用成员函数 read

函数原型:istream& read(char* buffer, int len);

注:字符指针bufer指向内存中一段存储空间,len是读写的字节数

class Person{
public:

    char m_Name[64];
    int m_Age;
};

void test02(){
    ifstream fin;
    fin.open("person.txt", ios::in | ios::binary);
    
    if(!fin.is_open()){
        cout<<"文件打开失败"<<endl;
        return;
    }
    
    Person p;
    
    fin.read(reinterpret_cast<char *>(&p), sizeof(Person));
    cout<<p.m_Name<<endl;
    cout<<p.m_Age<<endl;
    
    fin.close();
}
int main(){test02();return 0;}

二、重定向版

头文件:<cstdio>

格式:FILE* freopen(const char* __filename, const char* __modes, FILE* __stream);

参数说明:

mode:文件打开的模式,和fopen中的模式(r/w)相同

stream:文件指针,通常使用标准流文件(stdin/stdout/stderr)

参数含义
stdin标准输入流,默认为键盘
stdout标准输出流,默认为屏幕
stderr标准错误流,一般默认为屏幕

通过调用 freopen ,就可以修改标准流文件的默认值,实现重定向

代码模板:

#include <cstdio>
int main(){
    freopen("slyar.in", "r", stdin);
    freopen("slyar.out", "w", stdout);
    /*中间按原样写代码,什么都不用修改*/
    fclose(stdin);fclose(stdout);
    return 0;
}

三、fopen版

头文件:<cstdio>

实例:

FILE* fin,* fout;
fin=fopen("in.txt", "rb");
fout=fopen("out.txt", "wb");
int temp,sum(0);
while(fscanf(fin,"%d",&temp)==1){
    sum+=temp;
}
fprintf(fout,"%d\n",sum);
fclose(fin);fclose(fout);
return 0;

打开文件

格式:FILE* fopen(const char*__filename,const char*__modes);

  • 读写方式(可组合):
modes含义
wwrite写,若文件存在会清空文件,若不存在则创建文件
rread读,不具备清空或创建功能
aappend追加
+ 可读可写
bbinary二进制

读写文件

  • 以字符方式读写

fgetc(), fputc()

FILE* fin, * fout;
fout = fopen("char1.txt","w");
//字符形式读写文件
char str[] = "This is a string";
for (int i = 0; i < strlen(str);i++){
    fputc(str[i],fout);
}
fclose(fout);

fin = fopen("char1.txt", "r");
char key = fgetc(fin);
while(key != EOF){
    putchar(key);
    key = fgetc(fin);
}
fclose(fin);
  • 以字符串方式读写

fgets(), fputs()

FILE* fin, * fout;
fout = fopen("char1.txt","w");
char str[] = {"This is a string"};
fputs(str, fout);
fclose(fout);

fin = fopen("char1.txt", "r");
char buf[1024];
fgets(buf, 1024, fin);
puts(buf);
fclose(fin);
  • 格式化读写

fprintf(), fscanf()

class Person{
public:

    char m_Name[64];
    int m_Age;
};

void test04(){
    Person p[3]= {{"张三", 18}, {"李四", 20}, {"王五", 19}};
    
    FILE* fout = fopen("person2.txt","w");
    for (auto & i : p){
        fprintf(fout,"%s\t%d\n", i.m_Name,i.m_Age);
    }
    fclose(fout);

    FILE* fin = fopen("person2.txt", "r");
    Person buf;
    while (fscanf(fin, "%s\t%d\n", buf.m_Name, &buf.m_Age) != EOF){
        printf("%s\t%d\n", buf.m_Name, buf.m_Age);
    }
    fclose(fin);
}
  • 结构化读写

fread(), fwrite()

class Person{
public:

    char m_Name[64];
    int m_Age;
};

void test05(){
    Person p[3]= {{"张三", 18}, {"李四", 20}, {"王五", 19}};
    FILE* fout = fopen("person2.txt","w");
    fwrite(&p[0], sizeof(Person), 3, fout);
    fclose(fout);

    FILE* fin = fopen("person2.txt", "r");
    Person buf[3];
    fread(buf, sizeof (Person), 3, fin);
    for (auto & i : buf){
        printf("%s\t%d\n",i.m_Name, buf->m_Age);
    }
    fclose(fin);
}

关闭文件

fclose(文件指针)

如果把 fopen 版的改成读写标准输入输出,只需赋值 fin=stdin; , fout=stdout; 即可,不要调用 fopenfclose