c++ 小教程

c++ 小教程

前言

  • 由于其教程作者经历了很久的时间,因此码风可能有较大的差别。

基础语法

Hello world

在配完一个新环境的时候,为了检测配置有没有问题,我们一般都会以“输出Hello world”来检测。现在,我们就用 c++ 来写一个 Hello world 的程序扒 😄

#include<iostream>

int main() {
    std::cout << "Hello world!" << endl;
    return 0;
}

看不懂?没关系,我们一步一步看。

首先是最醒目的 #include<iostraem# 代表宏定义,这是要告诉编译器,这一行要优先编译。include 代表要让 c++ 提前加载尖括号里面的 iostream 文件。

如果你需要自己定义一个自己的头文件,请把它写成这样:

#include "head.h"

" 代表 c++ 编译器应该首先在当前目录查找,找不到才去标头路径查找,而尖括号内的头文件无法实现此功能。

然后是一行 int main() 。这里的 int 是一种数据类型,是 integer 的缩写,他代表这个函数的返回值是整形。 main 就是主要的的意思,这里是程序运行的入口。

括号里面一般是没有参数的,不过你可以写成 int main(void)int main(int argc,char *argv[](**argv)) , 原因请问度娘。

然后是一对花括号,程序员一般把它写在一行的末尾,最好空一行;但是如果你是要学信奥的话一般把它写在第二行的最左边。括号里面的就是程序执行的内容啦!

std::cout 的意思是在命名空间 std 里面调用对象 cout 。命名空间是为了防止一些函数或对象重名才来使用的。当你要用到多次 std 的时候,你最好在前面加一句 using namespace std; ,这样后面所有有关 std 的东西就可以不写了!cout 是 c++ 的标准输出,需要用 << 运算符进行输出,而引号里面的就是字符串。cout 会把字符串直接输出,显示在屏幕上。cout 还可以连续输出,用 << 连接。endl 就是 cout 里面的换行,也可以用字符 '\n' (字符是单引号)来代替,但 endl 是可以刷新缓冲区的,最好用 endl

下一行 return 0; 就是指这个函数是要返回零的,如果运行到这一行,不管后面还有什么代码,直接结束主函数。(main 函数不可以返回其他值哟~)

关于 c++ 写代码的好习惯

  • 每一行都需要一个分号,除非这一行特别长需要换行;

  • 变量最好要有实质性的内容,如果没有就用单个字符代替,最好不要起特别长的名字;

  • main 函数的末尾一定要 return 0; ,虽然有些编译器会帮你补上,但有风险;

  • cin 一定是 >>cout 一定是 <<

  • 最好代码中空点格,虽然看着很松散,但是调代码特别好调(亲身经历)。

输入、运算符

上面一段只是输出一些固定的东西,而生活是千变万化的,所以我们就需要输“入”。c++ 为我们提供的标准输入是 cin ,而 cin 的运算符是 >> ,与 cout 恰恰相反。(不要搞混了哦!)下面就是 a+b 问题的代码:

#include<iostream>
using namespace std;

int main(void)
{
    int a, b;
    cin >> a >> b;
    cout << a + b << endl;
    return 0;
}

现在这个程序与刚才的是不是不一样了呢?

首先我们先来看 int a, b; 这一行,这表示我们声明了两个整形变量 ab ,逗号是用来分隔的。当然,你也可以写成这样:

int a;
int b;

接着我们要输入他们,也就是 cin >> a >> b; 这一行。

最后我们要输出它们的和,这里用 + 运算符:

cout << a + b << endl;

最后结束 main 函数:

return 0;
怎么样?是不是特别简单?
c++ 的运算符:
名称符号作用
加法运算符+返回两个值的和
减法运算符-返回两个值的差
乘法运算符*返回两个数相乘的积
除法运算符/返回被除数除以除数的商
模运算符%返回余数
逻辑与&&若两边都为真返回真,否则返回假
逻辑或\\
逻辑非!真返回假,假返回真
赋值运算符=将右边的值赋给左边,并返回赋完的值
加运算符+=将自己的值加上右边的值,并返回自己
减运算符-=将自己的值减去做右边的值,并返回自己
乘运算符*=将自己的值乘上右边的值,并返回自己
除运算符/=将自己的值除上右边的值,并返回自己
模等于运算符%=将自己的值模上右边的值,并返回自己
成员运算符.访问类中的成员
长度运算符sizeof()返回括号中的字节长度
位与运算符&返回二进制与的结果
位或运算符\
位异或运算符^返回二进制异或的结果
取反运算符~返回二进制取反的结果
位复合运算符在位运算符后面添上=将当前变量对右边的值做相应的位运算并返回
下标运算符[ ]返回数组中的某一位
三目运算符??类似于 if
地址运算符&(只有一个参数)返回当前变量的内存地址
自增后缀运算符变量++先用这个变量,用完之后 +1
自减后缀运算符变量–先用这个变量,用完之后 -1
自增前缀运算符++变量先把这个变量 +1,然后再用
自减前缀运算符–变量先把这个变量 -1,然后再用
左移运算符<<二进制位左移,低位用 0 补齐
右移运算符>>二进制位右移,低位忽略

怎么多?别着急,用的多自然就熟了。

C 语言输入输出(c++ 兼容)

在 c++ 之前的 C 语言,也是有输入输出的,但是由于 C 语言功能没有 c++ 丰富,所以输入输出自然也不一样。C 语言输入是这样的:

scanf("控制符",&变量一,...);

输出是这样的:

printf("控制符",变量一,...);

这是 C 语言的 a+b:

#include<stdio.h>
using namespace std;

int main(void) {
    int a, b;
    scanf("%d%d",&a,&b);
    printf("%d",a+b);
    return 0;
}

可以看出,输入输出发生了很大的变化。首先头文件变了,变成了 stdio.h (在 c++ 里面也可以写成 cstdio)我们慢慢来看:

scanf 函数里面的控制字符串里面的每一个 %... 都是对应着后面的参数的,%d 就是代表下一个输入的值我们要把它们转成整数。后面的参数每一个一定都要加上 & ,因为他要改变实际的值是需要地址的,而 C 语言没有引用变量(后面会讲)。

printf 的格式与 scanf 类似,都是一样的,不过变量不用加 &

scanf 的输入控制符不只有 %d ,还有这些:

符号作用(也可做输出用)
%d读入整数
%ld读入 long 整数
%lld读入 long long 整数
%ulld读入 unsigned long long 整数
%c读入一个字符
%s读入一个字符串(char*
%i读入 i i i 后面的数的字节的整数
%x读入一个十六进制整数
% 后面的整数向右对齐
% 后面的负整数向左对齐
直接写符号表示读入对应的符号
%f读入单精度小数
%lf读入双精度小数

在保留小数方面,C 语言输入明显由于 c++:

#include<stdio.h>
using namespace std;
double a;

int main(void)
{
    scanf("%lf",&a);
    printf("它保留的三位小数是:%.3lf",a);
    return 0;
}
3.1415926535
它保留三位小数是:3.141

在保留小数、向右对齐方面,一般用 scanfprintf ,其他用 cincout

PS:

在输入多的时候,cin 由于不仅需要检测参数的类型,还要与 scanf 绑定,因此特别慢。这时候你就需要用 scanf 了。但是也有两行可以优化 cin 的代码:

std::ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);

不懂请自行问度娘

数据类型

c++ 也提供了丰富的数据类型,下面是基础数据类型:

关键字名称
int整形
char单字符型
bool布尔型
float单精度小数
double双精度小数

下面是类型修饰符以及可以修饰的数据类型:

修饰符可修饰类型作用
longint , long int , double让数的精度变高
signedint , long int , long long int , double声明这个类型既可以存正数也可以存负数
unsignedint , long int , long long , double声明这个类型只能存正数

下面是其他头文件中拓展的数据类型:

头文件类型名作用
cstringstring.hstring存储字符串
请百度请百度请百度

现在我们试验一下:

#include<iostream>
using namespace std;
int a;
char ch;
bool f;
float b;
double c;

int main(void)
{
    cin >> a >> ch >> f >> b >> c;
    cout << "整数是" << a << "字符是" << ch << "bool型是" << f << "单精度浮点型是" << b << "双精度浮点型是" << c << endl;
    return 0;
}

分支结构

if :如果括号里的条件满足,那么执行里面的内容。

if...else :如果 if 条件满足执行里面的内容,否则执行 else 里面的内容。

if...else if...else :如果 if 条件满足执行里面的内容,否则如果 else if 里面的条件满足,执行 else if 里面的内容, 否则执行 else 里面的内容。

注意:

if 可以没有 else ifelseelseelse if 也可以没有其中的一个,但是 else ifelse 必须有 if

循环结构

while(表达式) :如果表达式满足,那么执行内容,一直重复。

do...while(表达式) :首先执行一次内容,然后判断表达式有没有满足,如果满足重复步骤。

for(表达式一;表达式二;表达式三) :这是最复杂的循环语句,画个图啊:

           --->如果不满足--->跳出循环
          |
执行表达式一--->如果条件满足--->执行循环
          ^                    |
          |____________________|

大概就是这样的,比较适合从 1 − n 1-n 1n 逐步递增的场景,需要多多理解。

数组

我们之前都是用单个单个的变量来输入的。那如果现在要你输入 n n n 个数呢?我们就 for(int i=1;i<=n;++i) ,但如果你输完之后要在输出呢?如果 n ≤ 10000 n\le 10000 n10000 呢?难道你还需要定义 10000 10000 10000 个变量吗?

这是我们就需要运用到“数组”了。数组的定义方式是这样的:

数据类型 数组名[数组需要的元素大小]

在用的时候,你只需用下标运算符 [] 就可以访问数组了。注意

  • 数组下标是从零开始的,不过你也可以从一开始赋值;

  • 数组下标没有负数;

  • 下标可以使任何变量,甚至是别的数组的其中一个元素;

  • 数组下标只能是 int 类型。

试验一下:

#include<iostream>
using namespace std;

int main(void)
{
    int n;
    cin >> n;
    int a[n];
    for(int i=0;i<n;++i)
    {
        cin >> a[i];
    }    
    for(int i=n-1;i>=0;--i)
    {
        cout << a[i] << " ";
    }
    return 0;
}
3
1 2 3
3 2 1
PS:

在 c++ 中,数组大小可以是一个变量,但是只能是一维的,而且不太稳定,本渴鹅亲测过。最好开一个固定的数组来用,虽然内存多了一些,但是稳定。

数组也是可以赋初始值的,如果你回赋初始值的话,[] 内的大小是可以不用写的。比如:

int a[] = {1,2,3,4,5};

多维数组

在 c++ 中数组也是可以多维的。比如这样:

#include<iostream>
using namespace std;
int a[1005][1005];

int main(void)
{
    int n, m;
    cin >> n >> m;
    for(int i=1;i<=n;++i)
    {
        for(int j=1;j<=m;++j)
        {
            cin >> a[i][j];
        }
    }
    for(int i=n;i>=1;--i)
    {
        for(int j=m;j>=1;--j)
        {
            cout << a[i][j] << " ";
        }
        cout << endl;
    }
    return 0;
}
2 3
1 2 3
2 3 4
4 3 2
3 2 1

函数

在 c++ 中,除了主函数和系统函数,你还可以定义自己的函数,我们可以把函数看做一个对变量做操作的方法。函数定义格式是这样:

返回值 函数名(参数类型 参数名,...)
{
    函数体;
}

比如,我们可以定义一个返回 a+b 的值的函数:

int plus(int a,int b)
{
    return a+b;
}

然后在主函数内调用它:

int main(void)
{
    int a, b;
    cin >> a >> b;
    cout << plus(a,b) << endl;
    return 0;
}

这里就相当于我们把实际参数 ab 的值赋给了函数里面的形式参数 ab ,然后以形式参数 ab 的和返回了过来, 然后输出。

如果你的函数只是输出一些内容,没有返回值的话请把它的返回值写成 void 类型。

递归函数

先看 n n n 的阶乘的代码:

#include<iostraem>
using namespace std;

int work(int a)
{
    if(a<=1)return 1;
    return a*work(a-1);
}
int main(void)
{
    int n;
    cin >> n;
    cout << work(n) << endl;
    return 0;
}

看不懂?没关系,我们慢慢的把实际的算式捋出来(假设 n n n 4 4 4 ):

1.首先,我们往函数里面放了一个值 4 4 4 ,函数返回了 a × w o r k ( a − 1 ) a\times work(a-1) a×work(a1) 表达式现在是 4 4 4

2.然后,work 函数又返回了 a × w o r k ( a − 1 ) a\times work(a-1) a×work(a1) ,与前面的数相乘,就是 4 × 3 4\times 3 4×3

3.接着,里面的 work 函数又返回了 a × w o r k ( a − 1 ) a\times work(a-1) a×work(a1) ,与前面的数相乘, 就是 4 × 3 × 2 4\times 3\times 2 4×3×2

3.最后,最里面的 a a a 已经是 1 1 1 了,work 函数返回 1 1 1 ,整个调用函数产生的式子就是 4 × 3 × 2 × 1 4\times 3\times 2\times 1 4×3×2×1 ,正好是 n ! n! n!

这就是一个最简单的递归调用过程,需要多练才能熟哟~

指针

  • Update: 进行了一次大升级,内容更多了。

指针,是C语言中的一个重要概念及其特点,也是掌握C语言比较困难的部分。指针也就是内存地址,指针变量是用来存放内存地址的变量,在同一CPU构架下,不同类型的指针变量所占用的存储单元长度是相同的,而存放数据的变量因数据的类型不同,所占用的存储空间长度也不同。有了指针以后,不仅可以对数据本身,也可以对存储数据的变量地址进行操作。

指针描述了数据在内存中的位置,标示了一个占据存储空间实体,在这一段空间起始位置的相对距离值。在 C/C++语言中,指针一般被认为是指针变量,指针变量的内容存储的是其指向的对象的首地址,指向的对象可以是变量(指针变量也是变量),数组函数等占据存储空间的实体。 ——百度百科

光说说不懂,还是实践一下吧。👩‍💼

在介绍指针之前,我们需要了解一个特殊的运算符 &注意这里不能与逻辑与 && 混淆,& 只有一个!!!之前也讲了,& 也表示位或运算,但那个东西太复杂了,后面再讲。& 一般会放在一个对象、变量的前面(注意只有一个,而且是变量在后,不是符号在后)。它的名字叫做 取地址符。🙉

如果你使用 cout ,那么取出来的地址就会被识别成十六进制输出;如果你使用 printf ,那么你是用的 %d 只会输出整数。想要输出十六进制,需使用 %x 。现在看示范程序:👀

#include <iostream>
using namespace std;

int a = 1145141;

int main() {
    cout << &a << '\n';
    return 0;
}
(可能)0x403010

接下来就是关键性的问题了,为什么是可能呢?这就要说说最底层的知识了。

计算机的内存是不断波动的,因此当你在不同情况下,程序申请的内存都有可能不相等。因此无法确定一个准确的值。

现在,有了这些前缀芝士🧀,指针的学习就可以开始了!

指针的定义🖕

指针的定义与变量差不多,指向什么类型的东西就用什么类型名定义。定义规则为:

(指针指向的类型) *(指针名);

就好比定义了:

int a;

那么指向 a a a 的指针就该定义成

int *p;

指针里面装的是地址,因此我们可以定义指针 p p p 指向 a a a

int a;
int *p = &a;

但是——————* 运算符只对一个指针变量有效。因此这样定义:

int* a, b, c;

其实只有 a a a 是指针变量,其他的都只是普普通通的整数变量而已。所以,建议大家尽量把 * 写到靠近变量的那边,而非类型那边。

int *a, b, c;  // 更好的方式是:int b, c, *a;

*p 就是通过指针 p p p 来访问 p p p 指向的值。这个值是可以更改的,也可以输出。

现在,使用指针来控制变量的值吧!

int a;
int *p = &a;
*p = 1145141;
cout << a << ' ' << *p << '\n';
1145141 1145141

我们可以发现,a*p 输出出来其实是同一个数,而第三行我们对 p p p 指向的值,也就是存储 a a a 的值改为了 114514 114514 114514 ,因此原本没有值的变量 a a a 被赋予了值。现在还有一段代码:

int *n = new int;

这段代码又是做什么的呢?这里运用了内存申请符 new 来申请了一个 int 大小的空间,并把这个地址赋予了 n n n注意:不要这样做:

int n = new int;  // 这里的n是变量,定义时就已经有了空间,这样子会引发编译错误。

现在想必大家已经知道指针的只因本用法了吧?后面我会继续更新更高难度的指针操作,只因请期待!

类与对象

在 c++ 中,有很多基础数据类型。但我们能不能在这些基础数据的基础上,定义出我们自己的“类型”呢?当然可以,包括 cstring 里的 stringiostream 里面的 istream 和 ostream,都是“类”。现在,我们来定义一个学生的类,类中有设置属性、获取属性的一些方法:

#include<iostream>
#include<cstring>
using namespace std;

class student
{
private:
    int score, id; 
    string name;
public:
    int newStudent(string name, int score, int id)
    {
        this->score = score;
        this->id = id;
        this->name = name;
    }
    string getName(void)
    {
        return this->name;
    }
    int getScore(void)
    {
        return this->score;
    }
    int getId(void)
    {
        return this->id;
    }
}haokee("haokee", 100, 7), bluemoon("bluemoon", 0, 1);

int main(void)
{
   cout << haokee.getName() << ":score:" << haokee.getScore() << "id:" << haokee.getId() << endl;
   cout << bluemoon.getName() << ":score:" << bluemoon.getScore() << "id:" << bluemoon.getId() << endl;
   return 0;
}

可以看到,类里面分了两大块:privatepublic 。其实应该是三大块:

private :只有在类里面才可以访问的成员。

protected :只有在类里面或子类才可以访问。

public :在类内、类外或子类都可以访问。

这里我们写了一些成员函数用来返回当前类中的一些信息。this 指针指向的就是当前对象,而类的末尾我们定义了 haokeebluemoon 两个对象, 并给了他们初始值。然后我们通过调用成员函数的方式输出了他们的信息。

在调用对象中的成员的时候,我们需要使用 . 运算符,这样程序才能知道是调用哪个对象中的那个成员。

  • -> 运算符:他是通过指针来访问类中的元素,等同于:(*this).name

重载运算符

在类里面,我们不仅可以定义成员函数,还可以重载运算符。当符号两边的参数符合重载的参数时,就会自动调用重载的内容。

  • 注意:如果在类里面重载,那么是不写第一个参数的,第一个参数就是 this 指针。

我们可以在刚才那个程序的 main 的前面写:

ostream &operator<<(ostream &out, const student &stu)
{   
    cout << stu.getName() << ":score:" << stu.getScore() << "id:" << stu.getId() << endl;
    return in;
}

这里我们重载了左参数为 ostream 、右参数为 student<< ,每当被调用的时候,他就会执行里面的内容,返回 out 对象是因为这样就可以连续输出了。所以输出就可以直接写为:

cout << haokee << bluemoon;

继承

在 c++ 里面,可以定义类的“儿子”。比如我们定义一个 haokee 类:

class haokee {
public:
    void out(void) {
        cout << "我是haokee" << endl;
    }
};

然后我们在定义一个 haokee 类的派生类 son

class son : public haokee {

}S;

由于 Sson 类,是 haokee 类的“儿子”,所以 S 可以调用原来基类的函数:

S.out();

这时,protected 就有用了。你可以在派生类内访问一些成员,但是在类外无法访问,达到“保护”的效果。

class haokee {
protected:
    int x = 1;
public:
    void out(void) {
        cout << "我是haokee" << endl;
    }
};


class son : public /*标记*/ haokee {
public:
    void out2(void) {
        this->out();  //访问原类的公开成员
        cout << x;  //访问原类的保护成员
    }
}S;

S.out2();

注意到继承时的注释标记没有?这里的 public 表示的是 ”继承类型“。一般都写 public ,但是也可以写其他的:

继承类型符号规则
公有继承public除了私有成员,都可以访问
私有继承private基类的公有成员和保护成员都变成私有成员
保护继承protected基类的公有成员的保护成员都是派生类的保护成员

在调用基类的函数之上,我们也可以对基类的函数进行重写:

class haokee {
public:
    void print(){cout << "我是好渴鹅";}
};

class bluemoon : public haokee {
public:
    void print(){cout << "我不是好渴鹅,我是蓝月";}
}bl;

int main() {
    bl.print();  //我不是好渴鹅,我是蓝月
    return 0;
}

多继承

在 c++ 中,一个派生类也可以继承多个基类,中间用 , 分隔。

class 派生类 : 继承类型 , 继承类型 基类, 继承类型 基类, ……

virtual

虚函数
class F {
public:
    F(){}
    void print(){cout << "父类方法";}
    virtual ~F(){}
};
class S : public F {
public:
    S(){}
    void print(){cout << "派生类方法"}  //重写了父类的方法
};
int main() {
    F *f = new S();
    f->print();
    return 0;
}

可以看到,这里我们的指针类型与实际指向的地址的类型是不一样的。这是输出:

基类方法

但是我们明明实际指向的是派生类的指针,c++ 把他误以为是基类给输出了。现在我们把基类的函数改成这样:

virtual void print()

输出就会变成:

派生类方法

很显然,添加 virtual 可以区分基类和派生类的同名方法。

注意:
  • 只用在基类加上 virtual 关键字,派生类会自动加上;

  • 析构函数必须也改成虚函数,不然会有对象释放错误的问题;

  • 重写是对其他类的函数“改造”,而重载是在同一类同函数的不同参数列表的多个函数。

算法

照着附录(在后面)说的方法,打开洛谷(没登录的要先登录),点击 题库 页面,就可以看到一大堆题了。

我们点进第二题: A+B   Problem \texttt{A+B Problem} A+B Problem ,就可以看到题面了。

A+B Problem

题目背景

强烈推荐新用户必读帖

不熟悉算法竞赛的选手请看这里:

算法竞赛中要求的输出格式中,不能有多余的内容这也包括了“请输入整数 a \bm a a b \bm b b” 这一类的提示用户输入信息的内容。若包含了这些内容,将会被认为是 Wrong Answer,即洛谷上的 WA。在对比代码输出和标准输出时,系统将忽略每一行结尾的空格,以及最后一行之后多余的换行符。

若因此类问题出现本机(看起来)AC,提交 WA 的现象,请勿认为是洛谷评测机出了问题,而是你的代码中可能存在多余的输出信息。用户可以参考在题目末尾提供的代码。

另外请善用应用中的在线 IDE 功能,以避免不同平台的评测中所产生的一些问题。

还有一点很重要的是,请不要在对应的题目讨论区中发布自己的题解,请发布到题解区域中,否则将处以删除或禁言的处罚。若发现无法提交题解则表明本题题解数量过多,仍不应发布讨论。

题目描述

输入两个整数 a , b a, b a,b,输出它们的和( ∣ a ∣ , ∣ b ∣ ≤ 10 9 |a|,|b| \le {10}^9 a,b109)。

注意

  1. Pascal 使用 integer 会爆掉哦!
  2. 有负数哦!
  3. C/C++ 的 main 函数必须是 int 类型,而且 C 最后要 return 0。这不仅对洛谷其他题目有效,而且也是 NOIP/CSP/NOI 比赛的要求!

好吧,同志们,我们就从这一题开始,向着大牛的路进发。

任何一个伟大的思想,都有一个微不足道的开始。

输入格式

两个以空格分开的整数。

输出格式

一个整数。

样例 #1

样例输入 #1

20 30

样例输出 #1

50

提示

本题各种语言的程序范例:

C

#include <stdio.h>

int main()
{
    int a,b;
    scanf("%d%d",&a,&b);
    printf("%d\n", a+b);
    return 0;
}

C++

#include <iostream>
#include <cstdio>

using namespace std;

int main()
{
    int a,b;
    cin >> a >> b;
    cout << a+b << endl;
    return 0;
}

Pascal

var a, b: longint;
begin
    readln(a,b);
    writeln(a+b);
end.

Python2

s = raw_input().split()
print int(s[0]) + int(s[1])

Python3

s = input().split()
print(int(s[0]) + int(s[1]))

Java

import java.io.*;
import java.util.*;
public class Main {
    public static void main(String args[]) throws Exception {
        Scanner cin=new Scanner(System.in);
        int a = cin.nextInt(), b = cin.nextInt();
        System.out.println(a+b);
    }
}

JavaScript (Node.js)

const fs = require('fs')
const data = fs.readFileSync('/dev/stdin')
const result = data.toString('ascii').trim().split(' ').map(x => parseInt(x)).reduce((a, b) => a + b, 0)
console.log(result)
process.exit() // 请注意必须在出口点处加入此行

Ruby

a, b = gets.split.map(&:to_i)
print a+b

PHP

<?php
$input = trim(file_get_contents("php://stdin"));
list($a, $b) = explode(' ', $input);
echo $a + $b;

Rust

use std::io;

fn main(){
    let mut input=String::new();
    io::stdin().read_line(&mut input).unwrap();
    let mut s=input.trim().split(' ');

    let a:i32=s.next().unwrap()
               .parse().unwrap();
    let b:i32=s.next().unwrap()
               .parse().unwrap();
    println!("{}",a+b);
}

Go

package main

import "fmt"

func main() {
    var a, b int
    fmt.Scanf("%d%d", &a, &b)
    fmt.Println(a+b)
}

C# Mono

using System;

public class APlusB{
    private static void Main(){
        string[] input = Console.ReadLine().Split(' ');
        Console.WriteLine(int.Parse(input[0]) + int.Parse(input[1]));
    }
}

Visual Basic Mono

Imports System

Module APlusB
    Sub Main()
        Dim ins As String() = Console.ReadLine().Split(New Char(){" "c})
        Console.WriteLine(Int(ins(0))+Int(ins(1)))
    End Sub
End Module

Kotlin

fun main(args: Array<String>) {
    val (a, b) = readLine()!!.split(' ').map(String::toInt)
    println(a + b)
}

Haskell

main = do
    [a, b] <- (map read . words) `fmap` getLine
    print (a+b)

Scala

object Main extends App {
    println(scala.io.StdIn.readLine().split(" ").map(_.toInt).sum)
}

Perl

my $in = <STDIN>;
chomp $in;
$in = [split /[\s,]+/, $in];
my $c = $in->[0] + $in->[1];
print "$c\n";

很明显,实际就是输出 a + b a+b a+b ,根本就不用看程序范例,用我们之前学过的知识就可以轻松写出这样的代码:

#include <iostream>
using namespace std;

int a, b;

int main(int argc, char *argv[]) {
    cin >> a >> b;
    cout << a + b << '\n';
    return 0;
}

然后点击 提交评测 ,如果你的代码没有错误,应该会出现类似的界面:

然后点击右上角的头像(因人而异),点击 练习 就可以看到你做了哪些题目。

接着,我们写第二道题—— 超级玛丽游戏 吧!

题目很简单,就是让我们直接输出这个——

                ********
               ************
               ####....#.
             #..###.....##....
             ###.......######              ###            ###
                ...........               #...#          #...#
               ##*#######                 #.#.#          #.#.#
            ####*******######             #.#.#          #.#.#
           ...#***.****.*###....          #...#          #...#
           ....**********##.....           ###            ###
           ....****    *****....
             ####        ####
           ######        ######
##############################################################
#...#......#.##...#......#.##...#......#.##------------------#
###########################################------------------#
#..#....#....##..#....#....##..#....#....#####################
##########################################    #----------#
#.....#......##.....#......##.....#......#    #----------#
##########################################    #----------#
#.#..#....#..##.#..#....#..##.#..#....#..#    #----------#
##########################################    ############

大家伙。

但是如果我们使用 cout 一行一行地打,是要打很久的。

cout << "                ********" << endl;
cout << "               ************" << endl;
cout << "               ####....#." << endl;
... ...

不过,c++ 会将相邻的两个字符串合并成一个,所以我们可以这样写:

printf("                ********\n""               ************\n"... ...)

然后我们再简单地换一下行,就可以变成这样子:

#include<stdio.h>

int main(int argc, char *argv[]) {
    printf(
    "                ********\n"
    "               ************\n"
    "               ####....#.\n"
    "             #..###.....##....\n"
    "             ###.......######              ###            ###\n"
    "                ...........               #...#          #...#\n"
    "               ##*#######                 #.#.#          #.#.#\n"
    "            ####*******######             #.#.#          #.#.#\n"
    "           ...#***.****.*###....          #...#          #...#\n"
    "           ....**********##.....           ###            ###\n"
    "           ....****    *****....\n"
    "             ####        ####\n"
    "           ######        ######\n"
    "##############################################################\n"
    "#...#......#.##...#......#.##...#......#.##------------------#\n"
    "###########################################------------------#\n"
    "#..#....#....##..#....#....##..#....#....#####################\n"
    "##########################################    #----------#\n"
    "#.....#......##.....#......##.....#......#    #----------#\n"
    "##########################################    #----------#\n"
    "#.#..#....#..##.#..#....#..##.#..#....#..#    #----------#\n"
    "##########################################    ############\n"
    );
    return 0;
}

但是这时还是不够简便,怎么办呢?

C++11 raw string literal! (破音

开头是 R"( ,结尾 )" ,中间的字符可以跨行,而且里面没有转义字符。不过中间不能穿插 )" 。怎么办呢?用全角符号

可以这样写:

R"--(Embedded )" in string)--"

这样就很简单了:

#include<iostream>
using namespace std;

int main(int argc, char *argv[])
{
    cout<<R"(                ********
               ************
               ####....#.
             #..###.....##....
             ###.......######              ###            ###
                ...........               #...#          #...#
               ##*#######                 #.#.#          #.#.#
            ####*******######             #.#.#          #.#.#
           ...#***.****.*###....          #...#          #...#
           ....**********##.....           ###            ###
           ....****    *****....
             ####        ####
           ######        ######
##############################################################
#...#......#.##...#......#.##...#......#.##------------------#
###########################################------------------#
#..#....#....##..#....#....##..#....#....#####################
##########################################    #----------#
#.....#......##.....#......##.....#......#    #----------#
##########################################    #----------#
#.#..#....#..##.#..#....#..##.#..#....#..#    #----------#
##########################################    ############ )";
    return 0;
}

输出第二个整数 - 洛谷

这一题很简单,按照之前我们学过的方法,进行操作。

C o d e \mathcal{Code} Code

#include <iostream>
using namespace std;

int a, b, c;

int main() {
    cin >> a >> b >> c;  // 读入三个整数
    cout << b << '\n';  // 输出第二个
    return 0;
}

时间复杂度 O ( 1 ) \mathcal{O(1)} O(1) 。(这是一个时间复杂度, O \mathcal{O} O 里面表示的就是程序在最坏情况下需要运行的基本次数

时间复杂度就是用来方便开发者估算出程序的运行时间

我们该如何估计程序运行时间呢,我们通常会估计算法的操作单元数量,来代表程序消耗的时间, 这里我们默认 C P U \mathsf{CPU} CPU 的每个单元运行消耗的时间都是相同的。

假设算法的问题规模为 n n n ,那么操作单元数量便用函数 f ( n ) f(n) f(n) 来表示。

随着数据规模n的增大,算法执行时间的增长率和 f ( n ) f(n) f(n) 的增长率相同,这称作为算法的渐近时间复杂度,简称时间复杂度,记为 O ( f ( n ) ) O(f(n)) O(f(n))

例如以下程序

for (int i = 1; i <= n; ++i) {
    for (int j = 1; j <= n; ++j) {
        cout << "1";
    }
}

我们就说这个程序的时间复杂度是 O ( n 2 ) \mathcal{O(n^2)} O(n2)

计算 2 的幂 - 洛谷

题目大意

给定 n n n ,求出 2 n 2^n 2n

思路

暴力

2 n 2^n 2n 其实就是 n n n 2 2 2 相乘,因此我们可以这样写出一个 for 循环。

由于 2 0 = 0 2^0=0 20=0 ,因此需要特判:

int solve(int n) {
    int ans;
    if (n == 1) {
        return 1;
    }
    for (int i = 2; i <= n; ++i) {
        ans *= 2;
    }
    return ans;
}

事实上,我们可以使用位运算中的左移运算符( <<)。它的操作是把一个数的二进制位全部往左移动 n n n 位,低位用 0 0 0 补齐。由于是二进制,因此使用 m << n 等效于 m × 2 m m\times 2^m m×2m 。关于位运算更多的知识,请联系前面的基础知识。

int n;
cout << (1 << n); //由于cout也使用<<运算符,因此需要打上括号

Q \mathcal{Q} Qint 不是有范围的吗?为什么不会爆?

A \mathcal{A} A :因为 n ≤ 30 n\leq 30 n30 ,而 int 最大能存 2 31 − 1 2^{31}-1 2311 ,因此不会爆炸。💥

浮点数向零舍入 - 洛谷

题意

给出 n n n ,将 n n n 0 0 0 取整(整数向下舍入,负数向上舍入)。

思路

很简单,由于 c++ 的类型转换自带说明的方法,因此可以使用强制类型转换或者直接输入 int

double n;

int main() {
    cin >> n;
    cout << long long(n) << '\n';
    return 0;
}
long long n;

int main() {
    cin >> n;
    cout << n << '\n';
    return 0;
}

与圆相关的计算 - 洛谷

首先,我们需要知道这三个公式:

  1. d = 2 r d=2r d=2r

  2. C = π d C=\pi d C=πd

  3. S = π r 2 S=\pi r^2 S=πr2

依次完成计算即可。

const long double pi = 3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647093844609550582231725359408128481117450284102701938521105559644622948954930381964428810975665933446128475648233786783165271201909145648566923460348610454326648213393607260249141273724587006606315588174881520920962829254091715364367892590360011330530548820466521384146951941511609433057270365759591953092186117381932611793105118548074462379962749567351885752724891227938183011949129833673362440656643086021394946395224737190702179860943702770539217176293176752384674818467669405132000568127145263560827785771342757789609173637178721468440901224953430146549585371050792279689258923542019956112129021960864034418159813629774771309960518707211349999998372978049951059731732816096318595024459455346908302642522308253344685035261931188171010003137838752886587533208381420617177669147303598253490428755468731159562863882353787593751957781857780532171226806613001927876611195909216420198938095257201065485863278865936153381827968230301952lf ;

long double r;

int main() {
    cin >> r;
    printf("%.4lf %.4lf %.4lf", r * 2, pi * r * 2, pi * r * r)
    return 0;
}

在 OJ 中的基本事项我们已经学会了,那么就要开始疯狂刷题了。

这里比较推荐[题单广场](题单列表 - 洛谷),里面有很多的题可以刷。现在,我们讲讲顺序结构里面的几道题吧!

【深基2.例5】苹果采购

题目描述

现在需要采购一些苹果,每名同学都可以分到固定数量的苹果,并且已经知道了同学的数量,请问需要采购多少个苹果?

输入格式

输入两个不超过 1 0 9 10^9 109 正整数,分别表示每人分到的数量和同学的人数。

输出格式

一个整数,表示答案。保证输入和答案都在 int 范围内的非负整数。

样例 #1

样例输入 #1

5 3

样例输出 #1

15

十分简单,根据小学二年级所学的芝士,我们需要采购的苹果数量就等于 同学的数量 × \times × 每人分到的数量 。可以写出如下程序

#include <iostream>
using namespace std;

int a, b;

int main() {
    cin >> a >> b;
    cout << a * b << '\n';
    return 0;
}

【深基2.例6】字母转换

题目描述

输入一个小写字母,输出其对应的大写字母。例如输入 q[回车] 时,会输出 Q。

输入格式

输出格式

样例 #1

样例输入 #1

q

样例输出 #1

Q

从题目意思来看,我们并没有处理字符串大小写的标准函数。但是我们需要知道 ASCII 码!

ASCII (American Standard Code for Information Interchange):美国信息交换标准代码是基于拉丁字母的一套电脑编码系统,主要用于显示现代英语和其他西欧语言。它是最通用的信息交换标准,并等同于国际标准 ISO/IEC 646。ASCII第一次以规范标准的类型发表是在1967年,最后一次更新则是在1986年,到目前为止共定义了128个字符。 ——百度百科

ASCII 码就是用整数来记录字符,因此不同字母的 ASCII 码其实是有规律的。ASCII 码有 128 128 128 个字符,但我们没必要全部记住。我们只需要知道大写转小写是 + 32 +32 +32 (这里的 + + + 是加的 ASCII 值,会因为类型转换而变为字符,即 (空格)),小写转大写是 − 32 -32 32

代码就不用说了。

#include <iostream>
using namespace std;

char a, b;

int main() {
    cin >> a;
    b = a - 32;
    cout << b << '\n';
    return 0;
}

[NOIP2017 普及组] 成绩

题目背景

NOIP2017 普及组 T1

题目描述

牛牛最近学习了 C++ 入门课程,这门课程的总成绩计算方法是:

总成绩=作业成绩 × 20 % + \times 20\%+ ×20%+小测成绩 × 30 % + ×30\%+ ×30%+期末考试成绩 × 50 % \times 50\% ×50%

牛牛想知道,这门课程自己最终能得到多少分。

输入格式

三个非负整数 A , B , C A,B,C A,B,C,分别表示牛牛的作业成绩、小测成绩和期末考试成绩。相邻两个数之间用一个空格隔开,三项成绩满分都是 100 100 100 分。

输出格式

一个整数,即牛牛这门课程的总成绩,满分也是 100 100 100 分。

样例 #1

样例输入 #1

100 100 80

样例输出 #1

90

样例 #2

样例输入 #2

60 90 80

样例输出 #2

79

提示

输入输出样例 1 说明

牛牛的作业成绩是 100 100 100 分,小测成绩是 100 100 100 分,期末考试成绩是 80 80 80 分,总成绩是 100 × 20 % + 100 × 30 % + 80 × 50 % = 20 + 30 + 40 = 90 100 \times 20\%+100 \times 30\%+80 \times 50\%=20+30+40=90 100×20%+100×30%+80×50%=20+30+40=90

输入输出样例 2 说明

牛牛的作业成绩是 60 60 60 分,小测成绩是 90 90 90 分,期末考试成绩是 80 80 80 分,总成绩是 60 × 20 % + 90 × 30 % + 80 × 50 % = 12 + 27 + 40 = 79 60 \times 20\%+90 \times 30\%+80 \times 50\%=12+27+40=79 60×20%+90×30%+80×50%=12+27+40=79

数据说明

对于 30 % 30\% 30% 的数据, A = B = 0 A=B=0 A=B=0

对于另外 30 % 30\% 30% 的数据, A = B = 100 A=B=100 A=B=100

对于 100 % 100\% 100% 的数据, 0 ≤ A , B , C ≤ 100 0≤A,B,C≤100 0A,B,C100 A , B , C A,B,C A,B,C 都是 10 10 10 的整数倍。

思路

对于一个百分数如 25 % 25\% 25% ,那可以化成 25 100 \dfrac{25}{100} 10025 ,也就是 0.25 0.25 0.25 。知道了这个规律,代码轻轻松松:

#include <cstdio>
using namespace std;

int a, b, c;
int s;

int main() {
    scanf("%d%d%d", &a, &b, &c);
    s = (int)(a * 0.2 + b * 0.3 + c * 0.5);  
    printf("%.lf", (double)s);   
    return 0;  
}

附录

洛谷——步入 OI \text{OI} OI 大门

当你学完这些基础知识后,就可以去洛谷刷题了。首先,打开网站,是这个样子:

然后我们点一下右上角的 注册 按钮,就来到了用户注册界面。按照对应的填进去,你就注册成功了!

可以先试着摸索摸索功能。

然后点击“题库”,你就来到了题目的海洋。

随便点进一个题目进去,点击提交答案,就可以提交你的代码哦!😘

注意:洛谷的题目 99.99 % 99.99\% 99.99% 都是使用的标准输入输出(stdio),而非文件输入输出。

配置 OI \text{OI} OI 刷题环境

最开始的时候,老师一般都会给我们使用 Dev-c++ ,但是 Dev-c++ 已经停更很多年了,调试功能也有一些缺陷。况且现在一般 c++ 标准都是 c++14 ,而 Dev-c++ 是 c++11。可能好用的原因就是它可以支持单文件编译运行吧。。。

目前主流的高颜值、高扩展性的 IDE 应该就是微软的。

微软的 IDE 主要是 Visual   Studio \texttt{Visual Studio} Visual Studio 或者 Visual   Studio   Code \texttt{Visual Studio Code} Visual Studio Code 。前者更适合大型项目,而后者一般编译单文件。

Visual   Studio \texttt{Visual Studio} Visual Studio

下载链接:官网

下载之后打开它,就会弹出安装界面。有各种各样的工作负载可以选,但 c++ 开发一般只用 使用c++的桌面开发通用Windows平台开发 ,其他的酌情选择。勾选上,再改一改安装路径,尽量别安装在 C 盘上,避免卡得要死。

安装包可能有点大,等一小会就好了。

装完之后点击启动,然后没有项目的话就点击 创建新项目

我们选择 控制台应用 。输完相关信息后就来到了编辑区域:

当然,这款软件支持各种拓展以及颜色配置,感兴趣的话可以去网上找一找。(我的 VS 是装了插件,所以可能颜色跟你们不一样)

使用事项(避雷)
  • 千万不要直接在资源管理器里面新建文件,不然项目里面是看不到的。

  • 如果想只生成一个源代码,那么右键其他的所有源文件,点 属性 ,把 从生成中排除 改为是。

  • 一般情况下不要调试,按 以非调试模式运行 。调试器的内存占用实在是太大了!

这就是一个窗口的内存大小,大约 1.7  GB 1.7~\text{GB} 1.7 GB 。请保证你的电脑有 8  GB 8~\text{GB} 8 GB 的内存空间,不然用起来会有点卡。

Visual   Studio   Code \texttt{Visual Studio Code} Visual Studio Code

一样,还是去官网下载。

点击 我同意此协议 (应该没有人认真看吧?),然后下一步,这些选项酌情选择,不会太影响后续使用。最后安装!

安装好后打开它(你们应该是英文的):

我们先点开左边的“拓展按钮”,搜索 chinese ,点击 Install ,它会叫你 Restart ,按照它的操作走就行了。

但是 VS   Code \texttt{VS Code} VS Code 没有安装编译器,所以你需要自己安装。

官网下载较慢,可以试试这个链接:MinGW-w64 - for 32 and 64 bit Windows - Browse Files at SourceForge.net

然后我们解压一下(记住解压的路径),就需要配置环境变量。

打开文件资源管理器,右键此电脑,点击属性,点击高级系统设置,双击 Path 系统变量,点击新建,值为 解压的路径\bin\ 文件夹。然后一路点击 × \times × 或者 确定,一直点到没有窗口就行。

然后我们测试一下是否安装正确。按 Win + R 键打开运行,输入 cmd 回车,就来到了命令行。输入 gcc -v 或者 g++ -v ,如果没有报错则说明安装完毕 。

最后打开 VS Code ,安装 Code Runner 插件,然后写好代码并保存,点击右上角的运行按钮旁边的下切按钮,调成 code runner 之后再按运行按钮,就可以看到运行结果了!

做黑框框小游戏的函数:

使用头文件:

#include<windows.h>
#include<conio.h>   
#include<ctime>
#include<cstdlib>

函数:

void cls(void)  // 清屏
{
    system("cls");
}

char get(void)  // 返回按下的键
{
    return getch();
}


int random(int minN,int maxN)  // 在他俩中间随机选一个值
{
    srand((unsigned)time(NULL));
    return rand()%(maxN-minN)+minN;
}


void sleep(double s)   // 原函数是毫秒,我这里为了方便给他改成秒
{
    Sleep(s*1000);
}

void color(signed ForgC = 0, signed BackC = 15) //设定从设定开始的前景色和背景色
{
    WORD wColor = ((BackC & 0x0F) << 4) + (ForgC & 0x0F);
    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), wColor);
}


void pause(void)
{
    system("pause");
}

写了半天,点个赞吧~😜

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值