C++教程

首发于 http://helloos.wikidot.com/cpp ,由HelloOSMeHelloOSMeMinecraft_windows11Minecraft_windows11整理。
暗色css使用GNU/GPL 3.0协议


可能不及时更新。


0 一切从零开始

首先,你先安装Dev C++之类的IDE。

我推荐RedPanda-Dev-C++,这是支持Linux和Windows的!
如果你想下载Linux版本,请去这个项目的GitHub地址。

但是你要注意,不要保存为*.c文件,正宗C++文件后缀名是*.cpp,否则我们就无法写C++的代码,只能写C的了……

1 Hello,world

如果你学过其他语言,你应该知道写代码的第一串代码是Hello World,Hello World因人而异,有很多种Hello world。

那么,试试看!

例题1.1 Hello,world

难度:简单到不能再简单了

//我是单行注释
/*
我是多行注释1
我是多行注释2
我是多行注释3
*/
#include <bits/stdc++.h>//万能头文件
using namespace std;//std命名空间,比如A班有张三,B班也有张三,就需要指定是哪个张三了。例如cout,cin,endl等等都是std命名空间的,其他空间也有,但可能效果不一样。
//你也可以这样用,但是不推荐!想想谁更方便吧!
//using std::cin;
//using std::cout;
//using std::endl;
//因为,我们后面还要用到很多std命名空间内的东西呢!比如string变量和STL。
int main(){
    cout<<"Hello,World!"<<endl;//输出字符串里的Hello,World!
    //为了能让代码通过你谷的第一道测试题目Hello,World,W是大写的
    return 0;//告诉程序到这里就没了,不加也行,但是在CSP/NOI/NOIP/WC等竞赛上,是不允许的。
}

我虽然加了一堆注释,但你是不是一脸茫然?别急,我们简单讲一讲!

1.1. 万能头文件以及更多头文件

首先,bits/stdc++.h里面到底有啥东西,我们去他的文件里瞅一瞅!

// C++ includes used for precompiling -*- C++ -*-
 
// Copyright (C) 2003-2014 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library.  This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.
 
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
 
// Under Section 7 of GPL version 3, you are granted additional
// permissions described in the GCC Runtime Library Exception, version
// 3.1, as published by the Free Software Foundation.
 
// You should have received a copy of the GNU General Public License and
// a copy of the GCC Runtime Library Exception along with this program;
// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
// <http://www.gnu.org/licenses/>.
 
/** @file stdc++.h
 *  This is an implementation file for a precompiled header.
 */
 
// 17.4.1.2 Headers
 
// C
#ifndef _GLIBCXX_NO_ASSERT
#include <cassert>
#endif
#include <cctype>
#include <cerrno>
#include <cfloat>
#include <ciso646>
#include <climits>
#include <clocale>
#include <cmath>
#include <csetjmp>
#include <csignal>
#include <cstdarg>
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
 
#if __cplusplus >= 201103L
#include <ccomplex>
#include <cfenv>
#include <cinttypes>
#include <cstdalign>
#include <cstdbool>
#include <cstdint>
#include <ctgmath>
#include <cwchar>
#include <cwctype>
#endif
 
// C++
#include <algorithm>
#include <bitset>
#include <complex>
#include <deque>
#include <exception>
#include <fstream>
#include <functional>
#include <iomanip>
#include <ios>
#include <iosfwd>
#include <iostream>
#include <istream>
#include <iterator>
#include <limits>
#include <list>
#include <locale>
#include <map>
#include <memory>
#include <new>
#include <numeric>
#include <ostream>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <stdexcept>
#include <streambuf>
#include <string>
#include <typeinfo>
#include <utility>
#include <valarray>
#include <vector>
 
#if __cplusplus >= 201103L
#include <array>
#include <atomic>
#include <chrono>
#include <condition_variable>
#include <forward_list>
#include <future>
#include <initializer_list>
#include <mutex>
#include <random>
#include <ratio>
#include <regex>
#include <scoped_allocator>
#include <system_error>
#include <thread>
#include <tuple>
#include <typeindex>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
#endif

这串代码就是把所有文件都包含了进去,所以说可以算是万能的,但是世界上没有十全十美的东西。他会有如下缺点:

  • 某些编译器或者测评机不支持,因为他不是标准头文件里面的。
  • 这里面包含了一些不该包含的东西,会拖慢时间。
  • 不支持移植?也就是说你不可能用这东西去开发操作系统(?)但是HelloOS恰恰是用它搭建起来的,而且Windows和Linux通用。
  • 不包含系统本身API

然后cout,cin这些流来自于头文件iostream,所以你可以改成如下:

#include <iostream>//输入输出流
using namespace std;//不要忘记分号
 
int main(){
    cout<<"Hello,World!"<<endl;//有分号
    return 0;//分号
}

提一嘴,一般来说,我们需要在C++代码结尾加分号。当不需要加分号时,我们会在对应章节提醒你的!
比如,在引用头文件时,我们会使用这个格式:
#include<文件名>
看!这里就不需要加分号。int main的大括号结尾也不需要,我们暂时就记为大括号结尾不需要加分号吧。

拓展一下格式化输入输出:
scanf("%类型(如整型是%d)",&变量名);
记住!输入一定要加&号!!

而输出:
printf("%类型(如整型是%d)",变量名);
这里不需要加&。
你可以这样输出:%03d-即输出的数站3个位,如你想输出10,它会为你用0补全子确保占满3格,会输出010
%3d会用空格补全3位,会输出 10.
这个3可以改成别的数字!
输出Hello,world?
这样:printf("Hello,World!");

2 整数类型变量

我们通常要利用计算机进行计算,可是我们如何输入一个数,计算后输出它呢?
我们需要用到变量了!

0x01 short

short是短整型(整型=整数类型),不常用。

0x02 int/long

int是最常用的C++变量。你看,连main都是int定义的!
当然,main是函数,我们以后再说。
一般来说,int范围足够我们使用。
那long呢?你可以看做int,范围大小和int一样。

0x03 long long

如果你要处理大数据,long long 再好不过了!我们目前数据不会超过long long范围。

类型 范围
short -65535~65535
int -2147483648~2147483647
long 和int一样
long long -9223372036854775808~9223372036854775807

那么如何定义变量呢?这个看看吧!

变量类型 变量名;

注意!变量名只能由字母、数字和下划线组成!而且,数字不能是变量名的第一个字符!

$\color{#00FF00}{正确的名称:}$ a1_b2
$\color{red}{错误的名称:}$ 1a
好了,现在我们来看看一道实例。

例题2.1 A+B Problem

#include<iostream>
using namespace std;
int main(){
    int a,b;
    //定义变量a和b。我们可以这样一次定义多个变量:
    //类型 变量名1,变量名2,变量名……
    cin>>a>>b;
    cout<<a+b;//输出相加结果
    return 0;
}

试试看!
$a-b$
cout«a-b;
$a \times b$
cout«a*b;
$a \div b$
cout«a/b;

那么有些聪明的同学就要问了:那么除出来会有小数部分怎么办?小数部分就消失了?
没错,就……这么消失了,变量会向下取整。3.1会变成3,3.9也一样。它不会四舍五入的!

那如何获取除出来的余数呢?这样?
int c=a-(a/b*b);

你想麻烦了,直接用%就行!!
如3 % 2 = 1,因为$3÷2=1……1$.

很简单,是不是?!

3 小数类型

变量名 有效位数
float 6位小数
double 15位小数
long double 18位小数

一般来说我们使用double就可以了。
特殊的输出方法:

  1. 自动消除末尾0:直接用cout。
  2. 保留0:printf,中间用%f即可
  3. 保留特定位数小数:printf,%.nf,%后面的点点不要忘记加了!n就是位数。

4 判断

格式:
if(表达式){

}else if(表达式){

}else{

}

注意!判断相等是==!是==!!是==!!!

5 循环

循环有3种,for,while和do…while
使用方法:

for(变量初始化;保持循环要满足的要求;变量每次循环的变化){内容}
 
while(保持循环要满足的要求){内容}
 
do{}while(保持循环要满足的要求);//这个do…while后面没有后括号,要加分号。
//do…while先斩后奏

试试看!
例题5.1 CSP-J 2022 乘方

#include<iostream>
using namespace std;
int main(){
    long long jie=1;
    int a,b;
    cin>>a>>b;
    if(a==1){
        cout<<1;
        return 0;//结束程序
    }
    if(b>=1000000000){
        cout<<-1;
        return 0;
    }
    for(int i=0;i<b;i++){
        jie*=a;//相当于jie=jie*a
        if(jie>1000000000){
            cout<<-1;
            return 0;
        }
    }
    if(jie>1000000000){
        cout<<-1;
        return 0;
    }
    cout<<jie;
    return 0;
}

是的,知道这些,你就可以参加CSP了,而且会被刷得很惨……
没关系,你没有学过文件输入输出呢……

6 字符变量

我们就要学习字符变量了。
先来了解一下ASCII码:
字符 ASCII码
0 48
1 49
9 57
A 65
Z 90
a 97
z 122

这些是最重要的。
记住,我们字符类是char,char的范围是-128~127

scanf/printf对应格式化输入码是"%c".

那么我们要输入一串字符怎么办?
string试试吧!
呵呵,string可以获取整行输入哦!
试试getline(cin,str);吧!

试试看!
实例6.1 制造简单CMD命令行

#include<iostream>
using namespace std;
int main(){
    string s;
    while(true){
        cout<<">>> ";
        getline(cin,s)
    }
    return 0;
}

好了,你已经入门了C++语法!

7 变量数组

数组的用处是什么?
如果你输入一大堆数据,要求加和之后输出,你会怎么办?
数组会大大简化你定义一大堆变量的工作!
定义方式:

变量类型 变量名[数组大小];

例子:
int a[10];
我们就定义了有10个空的int类数组。

使用数组方法:
通过数组下标访问。

数组下标从0开始,到中括号内的数-1.

例子:
正确访问方式:int a[10];a[9]=1;
错误访问方式:int a[10];a[10]=1;

还有一种数组赋值方式:
int a[10]={1,2,3};
这样,a[0]=1,a[1]=2,a[2]=3了!

是的,string可以看作char ch[n]!不过没有范围!
你可以这样用string:
string a="1212";a[0]='2';
我们还可以这样定义:int a[10][20];

那么字符串数组如何知道大小呢?
char数组:包含#include<cstdio>头文件
string:变量名.size()

试试看!
例题7.1 NOIP2008普及组-ISBN码

#include<iostream>
using namespace std;
int main(){
    string str;
    long long ma=0;
    cin>>str;
    int zz=0;
    for(int i=0;i<str.size()-1;i++){
        if(str[i]>='0'&&str[i]<='9'){
            ma=ma+((str[i]-'0')*(zz+1));
            zz++;
        }
    }
    if(ma%11==str[str.size()-1]-'0'){
        cout<<"Right";
    }else if(ma%11==10&&str[str.size()-1]=='X'){
        cout<<"Right";
    }else{
        for(int i=0;i<str.size()-1;i++){
            cout<<str[i];
        }
        if(ma%11==10){
            cout<<'X';
        }else{
            cout<<ma%11;
        }
    }
    return 0;
}

8 文件操作

文件操作是我们必学的内容,一个应用程序可以记住你对它的设置的原因救赎这个。

一、文件重定向

包含头文件cstdio。(万能头当然是万能的啊!)

freopen("文件名.后缀名","r",stdin);//文件输入
freopen("文件名.后缀名","w",stdout);//文件输出
 
fclose(stdin);//关闭输入文件
fclose(stdout);//关闭输出文件

记住,stdin和stdout一定要对应r和w!!!
文件打开了,那如何操作呢?

很简单,直接正常使用输入输出即可。
对,没错,你可以照样使用输入输出,只不过不会输出到屏幕上了,即使你关闭了文件。

二、文件流

包含头文件fstream。(万能头最好用了!)

ifstream fin ("文件名.后缀名");
//相当于:
//ifstream fin;
//fin.open("文件名.后缀名");
fin.close();
//输入
 
ofstream fout;//输出文件,用法和ifstream一样。
 
//输入方法:
fin>>内容;//相当于cin的使用方法
//输出方法
fout<<内容;//相当于cout的使用方法
//fin和fout可以随便改,比如改成myfile,但是输入输出时就要用myfile>>或myfile<<了。

这个虽然无法直接cin/cout,但是使用fin/fout时你可以同时输出到屏幕!!