Cpp Basic Tutorial

居然要我这种水平的人来写一份C++入门教程,属实是有点抬举我了。

不妨先让你有一处宝地写代码?

请参见https://www.bilibili.com/video/BV12DYqzUEin/,安装一个简易的轻量化的C++编辑器及编译器的集成环境(C++ IDE)。此教程中略过不表。

从基本的顺序结构开始吧!

程序的运行起始于一个整型的主函数 (main()) 。在主函数中的代码会被逐行执行。你也可以在完整的代码文件中声明一些子函数,并在主函数中予以调用。声明主函数的办法为:

int main()
{
	//在这个位置写你的代码
	return 0;
}

从这一段代码来看,已经出现了多个问题。我在此试着逐行解释。

变量基本类型

不同于Python, C++在声明变量时严格要求要声明变量类型。声明为整数类型的变量不可以存放浮点数或小数,声明为字符型的变量不可以存放整数或小数。

我试着列一张表格,来展示你可能会用到的一些。

类型 名称 值域 / 精度 占用空间 (Byte)
bool bool / 布尔值 ${0,1}$ 1
char character / 字符型 所有字符 1
int interger / 整数型 $[-2^{31},2^{31}-1]$ 4
float float / 浮点数 一般保证小数点后8位精确 4
double double / 双精度浮点数 一般保证小数点后16位精确 8

(Ref: Type - cppreference.com)

除此之外,对于int类型,还有不同位宽的short int, long int,及是否留有符号位的signed int, unsigned int等多种子类型。至于其原理,详见:变量 - OI Wiki.

不同的变量将占用不同的内存空间,在写代码时请注意根据数据范围,尽可能地少使用内存空间。当然打比赛除外,打比赛要的就是冗余保证过过过就好了。

回到主函数上。当我们为一个函数赋予这样的类型,是对其返回值的类型存在要求。例如,当我们在主函数中调用一个子函数,我们可以决定子函数返回一个怎样的值。对于主函数,一般返回0,所以在代码块最后存在一个return 0。(这里具体向谁返回我也没太研究清楚,可能是操作系统?)

注释

C++的注释分为单行和多行注释,注释中的内容不会被执行,也不参与程序编译。你可以在注释里放一尊大佛,祈祷你的程序能够跑起来。或者骂骂人也行,但小心被发现。

int main()
{
	//这是单行注释
	
	/*
		这是多行注释,以斜杠和星号开头,以星号和斜杠结尾。
		注释中的内容都不会被执行。
	*/
	return 0;
}

好了!现在你已经可以声明变量,完成一些基本的运算,例如加减乘除。比方说:

int main()
{
	int a,b,c; //C++中,声明同一类型的多个变量时,可以用逗号分隔开
	a=1,b=2; //对多个变量赋值时,也可以用逗号
	c=a+b;
	return 0;
}

但是当你运行一下程序,你会发现你什么都得不到。这是怎么回事?

你突然发现,你只让程序完成了计算,但是并没有命令程序把答案告诉你。换言之,程序没有告诉你运算结果的义务。于是你打算动用你作为统治者的强权暴力手段,让它告诉你运算结果。

你又发现,你不能跟他讲“快把答案告诉我!”,并且你不知道怎么逼迫他告诉你答案。

输入/输出

C++有两种主要的输入输出方式,我们分别介绍。

(Ref. C++ 语法基础 - OI Wiki)

格式化输入输出 (scanf/printf)

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

scanf的使用上,需要注意,必须在后面的变量前加一个&。这是由于scanf接收的参数是一个在内存中的地址。

在两行代码中通用的%d,称为类型标识符,除了%d之外,还有%s,%c,%lf等等。详见上文中本部分的Reference。

printf中,如果你不想要输出一个变量,你只需直接在引号中写上你想要输出的内容即可。类型标识符占据的位置,会在字符串之外的逗号按顺序输出。例如,你可以使用:

int main()
{
	int a=1,b=1;
	printf("%d个人有%d个头",a,b);
}

输出结果为:

1个人有1个头

输入输出流 (cin/cout)

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

相较于格式化输入输出,输入输出流要简单一些,它不需要指定输入输出的内容的类型。你只需要用<<将输出的内容连接起来即可。变量与字符串之间需要一个<<,如上面的代码所示。

cin/cout的速度要慢于scanf/printf,且使用endl换行的速度要慢于\n换行。在部分场景下可能会导致程序运行时间超时。

到这里,你可能会发现,我们的代码居然仍然无法运行。这是由于scanfprintfcincout都是在C++库中的内容,我们需要通过引入头文件将他们引入到代码当中来。

头文件和命名空间

scanfprintf被包含在stdio.h头文件中,你需要在代码的最开头加入

#include<stdio.h>

以在程序当中使用它们。

cincout被包含在iostream头文件中,你需要在代码的最开头加入

#include<iostream>

以在程序当中使用它们。

命名空间,aka namespace,目的是在大型项目中防止重复名称的内容指代不清。上述的四个输入输出函数,均在std命名空间中。想要调用他们,有两种使用方法:

  1. 在使用时,在前面加上std::

    例如:std::cout<<"abc"<<endl;

  2. 在程序的开头写上using namespace std; 。此时,在后面使用上述四种函数时,你只需要直接cout<<"abc"<<endl; 即可。

第一种方式较为繁杂,但在大型工程中能更严谨地区分所指代的内容;第二种方式将整个std库引入到程序中来,在较小的项目中影响不大且更加便捷。

(Ref: C++ namespace-CSDN博客命名空间 - OI Wiki)

好了!接下来你可以开始体验每个程序员都将走的路了。你好,世界!

为进一步明确刚才的命名空间事项,我讲述两个写法。

写法一:

#include<bits/stdc++.h> 
//<bits/stdc++.h>
//aka 万能头,包含了绝大多数C++的库
//不建议在大型工程中使用万能头
using namespace std;
int main()
{
	cout<<"Hello, World!"<<endl;
	return 0;
}

写法二:


#include<bits/stdc++.h>

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