编程基础

C++版本

C++98 (ISO/IEC 14882:1998):C++的第一个版本于 1998年10月发布。有一些较老的oj在使用。
C++03 (ISO/IEC 14882:2003):在这个版本的c++中,值初始化(int i=1;)是在2003年2月引入的。
C++11(蓝桥杯选用):它于 2011年8月发布。这个 C++修订版引入了 Lambda 表达式、委托构造函数、统一初始化语法、自动类型推导auto、nullptr、decltype、Rvalue、References 等。
C++14:它于 2014年8月发布。此版本中添加的功能包括多态lambda、数字分隔符、通用lambda捕获、变量模板、二进制整数文字、引用字符串等。
C++17:它于 2017年 12月发布。它引入了折叠表达式、十六进制浮点文字、u8字符文字、带有初始化程序的选择语句、内联变量等。
C++20:它于 2020年12月发布。包括的一些新功能包括:测试宏3路比较、运算符<=>和运算符==()=默认值、新属性:[[no_unique_address]]、[[likely]]

基本数据类型

int 整数
lomg long 长整
float 单精度浮点型(小数)
double 双精度浮点型(小数)
char 字符
chan[] 字符串(数组)
bool 布尔型(true/false),输出是1/0。

常量

#define 定义常量,如#define PI 3.14,使用时PI就是3.14
const 定义常量,如const int PI = 3.14,使用时PI就是3.14

变量

int a = 1; 定义变量a,并赋值为1。
int a; 定义变量a,不赋值。
int a, b, c; 定义多个变量。
int a[n]; 定义数组,n为数组长度。,元素下标为a[0]~a[n-1]。(注意,n必须为常量(不会变化的))。

C++代码格式与语法基础

Hello, World!

1
2
3
4
5
6
7
8
#include <bits/stdc++.h>//使用万能头文件
using namespace std;//使用标准命名空间
int main()//main函数是c++中内置的启动函数,也就是程序入口
{
cout<<"Hello, World!";//利用cout将字符串输出,字符串用双引号括起来
printf("Hello, World!");//利用printf将字符串输出
return 0;//函数遇到return会立刻结束。返回0表示main函数正常结束
}

输出

1
2
Hello, World!
Hello, World!

基本数据类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <bits/stdc++.h>//使用万能头文件
using namespace std;//使用标准命名空间
int main()//main函数是c++中内置的启动函数,也就是程序入口
{
int x=3;//整数型x=3
double d=3.14;//浮点型(小数)d=3.14
char ch ='A'//字符ch
char s[]="Hello";//字符串s
bool b=true;//布尔型(即真假值)b

cout<<x<<endl;//输出整数x,endl表示换行
cout<<d<<'\n';//输出浮点数d,'\n'表示换行,\n换行会更快
cout<<ch<<'\n';//输出字符ch
cout<<s<<'\n';//输出字符串s
cout<<b<<'\n';//输出布尔型b
return 0;//函数遇到return会立刻结束。返回0表示main函数正常结束
}

输出

1
2
3
4
5
3
3.14
A
Hello
1

示例代码1(数组)

1
2
3
4
5
6
7
8
9
#include <bits/stdc++.h>
using namespace std;
//const表示常量,后续不可被修改
const int N=1e5+9;
int a[N];//开一个大小为N的全局数组,下标为[0,N-1],自动初始化为0(全局变量自动声明)
int main()
{
return 0;
}

示例代码2(typedef)

1
2
3
4
5
6
7
8
9
10
11
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;//typedef可以给类型起别名,如ll表示long long
//const表示常量,后续不可被修改
const int N=1e5+9;
//开一个大小为N的全局数组(类型为long long),下标为[0,N-1],自动初始化为0(全局变量自动声明)
ll a[N];
int main()
{
return 0;
}

示例代码3(字符串)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <bits/stdc++.h>
using namespace std;

int main()
{
char s[]="Hello"//长度为5的数组,下标区间为[0,4]
for(int i=0;i<4;++i)//数组下标从0开始,for(初始化;结束条件;后语句,一次循环结束执行)
{
cout<<s[i];//字符串s中下标为i的元素
}
cout<<'\n';//换行
cout<<s<<'\n';//输出s(遇到\0结束),并换行
return 0;
}

输出

1
2
Hello
Hello

示例代码4(交换变量)

1
2
3
4
5
6
7
8
9
10
11
12
#include <bits/stdc++.h>
using namespace std;

int main()
{
int a=5,b=3;//初始化变量a,b
int tmp=b;//定义临时变量tmp
b=a;//a的值给b
a=tmp;//tmp的值给a
cout<<a<<' '<<b<<'\n';//输出a,b的值
return 0;
}

输出

1
3 5

示例代码5(判断)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <bits/stdc++.h>
using namespace std;

int main()
{
//输出1~n中所有偶数
int n=10;
for(int i=1;i<=n;++i)
{
//如果后面不加大括号则仅执行一条语句
//i%2==0表述i除以2余数为0
if(i%2==0)cout<<i<<'\n';
}
return 0;
}

输出

1
2
3
4
5
6
2
4
6
8
10

输入输出

scnanf和printf

scanf和printf的优势:
1.格式化和输出
2.效率高

1
2
3
4
5
6
7
int main()
{
int a, b;
scanf("%d %d", &a, &b);//&取址符and;输入2 9
printf("%d, %d\n", a, b);//输出2, 9
return 0;
}

1
2
3
4
5
6
7
int main()
{
double a, b;
scanf("%lf %lf", &a, &b);//输入3 5
printf("%.2f, %.3f\n", a, b);//输出3.00, 5.000(自动四舍五入)
return 0;
}

1
2
3
4
5
6
7
int main()
{
char a, b;
scanf("%c %c", &a, &b);//输入a b
printf("%c, %c\n", a, b);//输出a, b,\n换行
return 0;
}

1
2
3
4
5
6
7
int main(){
char s[100];
scanf("%s", s);//输入abc这里因为本来就是指针形式,所以不用&
//scanf遇到空格或换行符就停止
printf("%s\n", s);//输出abc
return 0;
}

1
2
3
4
5
6
int main(){
char s[15];
scanf("%[^\n]", s);//[]中是正则表达式,表示只要不是回车就读入。^上尖号表示排除。\n回车转义字符
printf("%s\n", s);//输出abc
return 0;
}

常见类型
int %d%i(少用)
double %lf
char %c
char[] %s
string %s
long long %lld

cin 和 cout

1
2
3
4
5
6
7
8
9
10
int main(){
int a, b;
cin >> a >> b;//输入2 9
cout << a << " " << b << endl;//输出2 9

double c,d;
cin>>c>>d;//输入3 5
cout<<c<<d;//输出35
return 0;
}
1
2
3
4
5
6
7
int main(){
double a, b;
cin >> a >> b;//输入3 5
cout << fixed << setprecision(2) << a << ", " << fixed << setprecision(3) << b << endl;//输出3.00, 5.000(自动四舍五入)
//fixed表示固定小数点,setprecision表示保留几位小数
return 0;
}
1
2
3
4
5
int main(){
char ch;
cin >> ch;//输入a
cout << ch << endl;//输出a
}
1
2
3
4
5
int main(){
char s[10];
cin >> s;//输入lan qiao
cout<< s << endl;//输出lan,因为遇到空格或回车就停止
}
1
2
3
4
5
int main(){
string s;
getline(cin, s);//输入lan qiao 这里的避免了cin遇到空格或回车就停止
cout<< s << endl;//输出lan qiao
}

取消同步流

由于cin和cout需要自动判断变量类型等内部原因flash(),读写效率比scanf和printf更低。当数据量较大时,可能导致程序运行超时,我们可以通过取消同步流来加速cin和cout,加速后效率相差无几。
注意,最好不要cin/cout和scanf/printf混用,防止出问题

1
2
3
4
5
6
7
8
int main(){
//取消同步流
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
//其他操作不变
int x;cin>>x;
cout<<x<<'\n';//取消后换行用\n
return 0;
}

代码示例1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 150;

int a[N];

int main(){
//取消同步流
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);

int n;cin>>n;//输入数组大小
for(int i=0;i<n;i++) cin>>a[i];//遍历输入数组元素
for(int i=0;i<n;i++) cout<<a[i]<<' ';
return 0;
// 输入5
// 1 2 3 4 5
// 输出5 4 3 2 1
}

代码示例2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 150;

int a[N];

int main(){
//取消同步流
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);

cin>>s+1;//从s[1]开始输入
for(int i=1;s[i];++i) cout<<s[i];//从s[1]开始输出,i=1;中间结束条件是s[i]≠'\0'的省略写法
return 0;
// 输入lanqiao
// 输出lanqiao
}

代码示例3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 150;

char s[N];

int main(){
scanf("%s",s);//不用取址符号
for(int i=0;s[i];++i) cout<<s[i]<<'\n';//注意以后不要混用scanf和cin
return 0;
// 输入lanqiao
// 输出l
// a
// n
// q
// i
// a
// o
}

代码示例4

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 150;

double a[N];

int main(){
int n;scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%lf",&a[i]);
double sum=0;
for(int i=1;i<=n;i++) sum+=a[i];
printf("%.2lf",sum);//保留两位小数,自动四舍五入
return 0;
// 输入5
//1.0 2.313 6.22 5.47 9.299
// 输出24.30
}

示例题目

题目详见蓝桥OJ:A+B问题
在里面好好练习输入输出吧,顺便练习一下取消同步流。

String的使用

string简介

string是C++标准库的重要组成部分,主要用于字符串处理。
使用string库需要在头文件中包括该库#include
string与char[]不同,string实现了高度的封装,可以很方便地完成各种字符串的操作,比如拼接、截取、匹配等等。

  1. 字符串管理:string封装了字符串的存储和管理。它自动处理字符串的内存分配和释放,避免了手动管理内存的麻烦。
  2. 动态大小调整:string可以根据需要自动调整字符串的大小。在添加或删除字符时,string会自动调整内部的存储容量,确保足够的空间来容纳字符串。
  3. 安全性:string提供了一些方法来确保字符串的安全性。例如,它提供了越界访问检查,以避免访问超出字符串范围的字符。
  4. 迭代器支持:string支持迭代器,可以使用迭代器遍历字符串中的字符,进行字符级别的操作。
  5. 兼容性:string是C++标准库的一部分,因此在C++中广泛使用,并且与其他标准库组件和C++语言特性兼容。

    string的声明与初始化

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    #include <iostream>
    #include <string>
    int main()
    {
    //如果用了using namespace std;则不需要std::
    //声明并初始化一个空字符串
    std::string str1;
    //使用字符串字面量初始化字符串
    std::string str2 = "Hello, World!";
    //使用另一个string对象来初始化字符串
    std::string str3=str2;
    //使用部分字符串初始化字符串,从第0位开始,选5位
    std::string str4 = str2.substr(0, 5);;
    //使用字符数组初始化字符串
    const char* charArray="Hello";
    std::string str5(charArrary);
    //使用重复字符初始化字符串AAAAA
    std::string str6(5, 'A');

    //输出
    std::cout << str1 << std::endl;
    std::cout << str2 << std::endl;
    std::cout << str3 << std::endl;
    std::cout << str4 << std::endl;
    std::cout << str5 << std::endl;
    std::cout << str6 << std::endl;
    return 0;
    }

    输出

    1
    2
    3
    4
    5
    6
    7

    Hello, World!
    Hello, World!
    Hello
    Hello
    AAAAA

    string的常用操作0:printf输出字符串

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #include <bits/stdc++.h>
    using namespace std;
    int main()
    {
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    char buf[100];//临时变量,用于输入
    scanf("%s",buf);//输入buf
    string str(buf);//用buf构造str
    printf("str = %s\n",str.c_str());//输出str
    return 0;
    }

    输入

    1
    Hello

    输出
    1
    2
    str = Hello

    string的常用操作1:获取字符串长度

    1
    2
    3
    std::string str = "Hello, World!";
    int len = str.length();//或者int len = str.size();
    std::cout << len << std::endl;

    string的常用操作2:字符串拼接

    1
    2
    3
    4
    5
    6
    std::string str1 = "Hello, ";
    std::string str2 = "World!";
    std::string str3 = str1 + str2;//使用+运算符
    std::string str4 = str1.append(",").append(str2);//使用append函数
    std::cout << str3 << std::endl;
    std::cout << str4 << std::endl;

    string的常用操作3:字符串查找

    1
    2
    3
    4
    5
    6
    7
    std::string str = "Hello, World!";
    size_t pos = str.find("World");//查找子串"World"在str中的位置
    if (pos != std::string::npos) {//npos=-1,表示未找到
    std::cout << "Found at position: " << pos << std::endl;//pos目前是等于7的,下标(index)从0开始
    } else {
    std::cout << "Not found" << std::endl;
    }

    string的常用操作4:字符串替换

    1
    2
    3
    std::string str = "Hello, World!";
    str.replace(7, 5, "Universe");//将str中从第7个位置开始的5个字符替换为"Universe"
    std::cout << str << std::endl;

    string的常用操作5:字符串截取

    1
    2
    3
    std::string str = "Hello, World!";
    std::string subStr = str.substr(7, 5);//从第7个位置开始截取5个字符
    std::cout << subStr << std::endl;

    string的常用操作6:字符串比较

    string重载了不等号,所以可以直接使用s1 < s2的方式来比较string的大小,比较的规则是按照字典序大小进行比较。
    字典序的比较方法是从小到大一个一个比较,一旦遇到不相等的字符就确定大小关系。
    例如:
    аааа < bььь
    аzz < baaa
    aZZZZZZZZZZZZz < b
    lanqiao == lanqiao
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    std::string str1 = "Hello";
    std::string str2 = "World";
    int result = str1.compare(str2);//比较两个字符串的大小
    if (result == 0) {
    std::cout << str1 << " is equal to " << str2 << std::endl;
    } else if (result < 0) {
    std::cout << str1 << " is less than " << str2 << std::endl;
    } else {
    std::cout << str1 << " is less than " << str2 << std::endl;
    }

    string的常用操作7:字符串遍历

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    string s = "Hello";
    for (int i = 0; i < s.length(); ++i)cout << s[i];
    cout<<'\n';
    for (auto i : s){
    cout << i;
    i='z';//此处i只是s的拷贝,不是引用,因此修改无效
    }
    cout<<'\n';
    //此时s为"Hello"
    for(auto &i : s){
    cout<<i;
    i='a';//此处修改会改变s的值
    }
    cout<<'\n';
    //此时s为"aaaaa"
    cout<<s<<'\n';
    1
    2
    3
    4
    string s = "Hello";
    for (auto it = s.begin(); it != s.end(); it++) {
    cout << *it << endl;//利用迭代器依次输出
    }

    string练习题:反转字符串中的字符

    题目详见蓝桥OJ:反转字符串中的字符
    1
    2
    3
    4
    5
    6
    7
    8
    9
    #include <bits/stdc++.h>
    using namespace std;
    int main()
    {
    string s;
    getline(cin, s); // 用于获取带有空格的字符串
    for ( int i=s.size()-1; i>=0; i-- ) cout << s[i]; // 反向输出字符串
    return 0;
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #include <bits/stdc++.h>
    using namespace std;
    int main()
    {
    string s;
    getline(cin, s);
    reverse(s.begin(), s.end());
    cout << s;
    return 0;
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #include <bits/stdc++.h>
    using namespace std;
    int main()
    {
    string s;
    getline(cin, s);
    for ( int i=0; i<s.size()/2; i++) swap(s[i], s[s.size()-1-i]);
    cout << s;
    return 0;
    }

    小作业:妮妮的翻转游戏

    题目详见蓝桥OJ:妮妮的翻转游戏
    方法很多,这里列举一种。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #include <bits/stdc++.h>
    using namespace std;
    int main(){
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int x;
    cin>>x;
    if(x)x=0;
    else x=1;
    cout<<x<<'\n';
    return 0;
    }