首页
登录
会员

1.初识C++

专栏:C++实战入门到精通
更新于:2024-05-18 06:13:01
1763

一、到底什么是C/C++?

如果你是一个刚入计算机行业不久的新手,应该总能看到C/C++,python,java等等类似的字眼,而这些便是编程语言的名字,就和中文、英文、日文一样。

而C/C++就是其中非常耀眼的一门编程语言,点击这里查看编程语言实时排行榜:

image-20231126083344355

可以看到,C与C++常年稳居前四的宝座。

虽然这看上去C与C++是两门不同的语言,但事实上,C++是完全兼容C的,大部分情况下都可以说,C++是C的升级版,毕竟是在C的后面多了两个加号嘛。

至于pythonjavaC#等其它众多语言,基本都是在C与C++的基础上开发实现的,所以当你彻底掌握C/C++之后,快速入门语言对于你来说其实是一件非常简单的事情。

编程语言简单来说,可以直接理解为是我们人类与计算机交流的语言。

比如,当你拥有1万张图片想要将图片名称改为特定的格式时,你应该不会想到自己手动一个一个的去更改,于是你就可以用编程语言告诉计算机,让计算机帮你改,计算机非常适合做这种有规则的重复劳动。

以上只分为了两个层次,也就是人与计算机。

但事实上,你写的编程语言,计算机其实并不认识,因为计算机只认识0和1,这该怎么办?

这就需要人与计算机的中间层:编译器

你所写的所有编程语言代码,无论是C/C++,还是java,python,都是给对应的编译器看的(又或者解释器),当编译器看到你所写的内容没有问题之后,才会将其翻译为0与1组成的机器码,计算机才能识别并执行它。

这就如同一个既不会中文、也不会英文、只能看懂二进制的新人类,我们所说的中文、英文,就需要有翻译将我们的所说内容翻译为二进制给这个新人类才能被其理解一样。

你经常在windows平台看到的.exe文件,就是编译器将程序员所写的代码翻译出来的结果,当你点击它,电脑就会执行它,过程大致如下图:

graph TD
A[人类 写的代码] -- 编译器 翻译 --> B[计算机 能识别的程序]

当然,上面这张图是极其简陋的,只是为了方便新手快速建立一个概念:我们通过写某种编程语言的代码,需要通过该语言的编译器翻译,最后才能够让计算机执行

如果对此感兴趣并想要深入了解的,可以查看本站另一篇文章:编译过程

二、C/C++能做什么?

如果你去浏览器中搜索,C/C++学完能够干什么,你会发现众多答案中,无所不能这个词可能是对它描述最多的。

但如果当你跟着网上免费教程学完之后,自认已经精通C/C++这门语言了,想要做点什么的时候,却又会发现自己似乎什么也做不了。

这并不是“无所不能”这个词用错了,而是你仅仅只学习了C/C++这门语言本身,而且只学习了其中最重要且最基础的部分。

如果你想要开发一款属于自己的PC端软件,那么本套教程我相信是非常适合你的,因为后续文章会大量介绍这些软件是如何被写出来的,其底层的原理是什么。

即使你对开发软件本身并不感兴趣,本系列教程也能让你对一款软件的整体开发流程有一个大致的了解,我相信这对你未来的工作同样大有脾益。

三、下载Visual Studio

虽然用记事本我们也一样能够码代码,然后下载个编译器,就可以进行编译了,但那会浪费我们非常多的时间去研究,对新手极不友好,所以推荐大家直接下载集成开发环境:Visual Studio

当你真正深入了解了这门语言之后,再尝试那些比较复杂的操作,也就会水到渠成。

Visual Studio是一款非常强大的集成开发环境,也就是大家常说的IDE,号称宇宙最强,该软件内集成了编译器,同时还有非常多其它的强大功能,可以极大的提高程序员码代码的效率,点击这里前往官网下载

image-20231126084352834

这里下载第一项社区版即可,完全免费的!

当然,如果你已经下载好了较为低的版本,比如20192017等,可以不用再下载了,区别其实不是很大。

我用VS2022,主要是为了跟上时代的步伐,让该系列教程能够适应的更久一点罢了。

下载完成后,点击安装即可,中间的步骤可根据需要随意选择,唯一需要注意的是,需要勾选下图红框中的内容:

image-20231126084829093

其它的内容可根据自己的需要选择下载,同时还可以自行更改安装路径,因为该组件还是比较大的,可以更改到D盘等地方:

image-20231126084900140

我C盘挺大,就直接安装到了C盘,你可以看自己实际情况选择其它安装位置,点击右下角安装,然后等待安装完成即可。

四、从Hello World开始

在开始写代码之前,我们有必要理清一下VS(Visual Studio的简称)中的部分关系:

graph LR
A[解决方案]
A-->B[项目1]
A-->C[项目2]
B-->f1([文件1])
B-->f2([文件2])
C-->f3([文件1])
C-->f4([文件2])

上图所要说明的一件事是,一个解决方案内可以有多个项目,一个项目中可以有多个文件。

为了更加直观的理解,我们以QQ为例子,一个QQ就是一个解决方案:

image-20231126085150490

但如图可以看到,在QQ的安装目录下,除了QQ.exe外,还有相当多其它的.exe文件,.dll文件。

包括QQ.exe在内,这些都是QQ这个解决方案下的许多项目所生成的东西,各自完成QQ这个软件整体的一部分功能,而每个项目又都是由相当多的文件所编译生成的。

了解了这个,我们就可以来写hello world了,首先,进入vs创建新项目:

image-20231126085349556

然后,选择创建一个控制台的空项目:

image-20231126085437700

这里就用到了上面所说的知识点,解决方案项目可以分别命名,除非你确信这个解决方案里面只会有一个项目,那么可以不用区分这两者:

image-20231126085719062

同时最好不要勾选将解决方案和项目放在同一目录下,因为如果当你在该解决方案内建立多个项目的话,就会乱套的。

当然你也可以自己选择存放项目文件的位置,然后就可以点击该页面右下角的创建按钮了。

创建成功后,你会发现空无一物,这就是空项目,所以我们需要新建一个文件。

首先,你需要找到解决方案资源管理器,如果你的界面没有这个界面框,请按下图步骤打开:

image-20231126085835159

然后,就可以添加一个文件了

image-20231126085906895

右键点击源文件,添加,新建项。当然你也可以直接按快捷键 Ctrl+Shift+A

最新版vs已经可以直接输入文件名并添加了:

image-20231126085952747

如果是老版本,即点击左下角的显示所有模板的界面:

image-20231126090159131

两种方式都可以,这里我们添加了一个叫做main.cpp文件到该项目中,然后输入以下代码:

#include<iostream>
int main() {
	printf("Hello World!\n");

	std::cout << "Hello World!\n";
}

然后点击运行:

image-20231126090328126

可以看到运行结果:

image-20231126090406138

至此,你就可以完成输出字符串的功能了,printf为C语言的输出方式,std::cout为C++的输出方式,但在C++项目中,这两者都可以使用。

当然,你可能会问为什么要这么写或这样做?各个语句的意思是什么?

但很遗憾,暂时我无法做出解释,因为上面短短几行的内容与步骤,就包含了相当多的知识点,所以只能留在后面慢慢解释。

但你需要记住这个结构和这些步骤,因为这是最基础的,就和你真正理解乘法前,先把最基础的乘法口诀记住一个道理。

你现在所必须知道的一个事实是:程序是从main后面的{}里面开始运行的,遇到一句,就执行一句

并且需要注意的是,代码中,一旦涉及到字符,统统使用英文字符!否则将出现错误。

一劳永逸的办法就是,设置自己的输入法,在中文模式下依旧使用英文符号!

image-20231126090635269

我用的windows系统自带的输入法,如今的输入法基本都有这个功能的,可以自己摸索。

至此,你就可以用std::cout,或者printf,按上面的格式打印任意内容了, 字符中添加的\n,可直接理解为换行的意思。

以目前的情况,暂时并不适合讲解std::coutprintf这两个的原理,所以你只需要记住各自的输出方式即可。

五 、数据类型

C/C++里面,数据类型大致分为以下几种

类型 大小 表述
bool 1个字节 boolean类型,除了0为false,其它数均为true
char 1个字节 字符类型
short 2个字节 短整数类型
int 4个字节 整数类型
long 4个字节 整数类型
long long 8个字节 长整数类型
float 4字节 单浮点数类型
double 8字节 双浮点数类型
char* 多字节 字符串
void 表示不确定类型,就是无类型

当然,这样直接拿给你看,是没什么意义的,所以我们需要知道的是为什么要有数据类型?以及如何使用数据类型。

为了方便理解,举个简单的例子,当你用windows自带的那个计算器时,你可能会需要计算整数,比如199*233, 你也可能需要计算小数,比如3.14159*233

如果我们想要实现这样一个计算器,肯定就得要有东西能够表示这些数字,于是就有了 char short int longlong long用来表示整数,floatdouble用来表示小数。

计算机本质就是由大量0和1的数字组成形成的一个计算群,你所能在计算机上看到的一切,实际上都是一堆数据不断的在进行运算而已,比如你所能看到的屏幕,本质上也是一堆组成像素点的数字在不断的运算、才让你感受到屏幕的变化。因此只要能存放、运行数字,那么就能构建整个计算机系统及软件。

你可能会想,明明就整数和小数两个类型,为什么要分出这么多类型?

因为C/C++发展了几十年啊,以前的内存是非常珍贵的,能用char,1个字节,那肯定不用int,4个字节来表示一个数字。

比如在零几年,各种存储、内存都还是以KB、MB为单位的,就更别说上个世纪了。

因为历史的种种因素,最终导致了C/C++形成了如今这纷繁多样的数据类型。

但事实上如今的各种高级语言都在逐渐简化基本数据类型的个数。

更多详细的介绍可以参考文章:数据类型数据大小,以及文章程序员必懂的常识中关于内存的介绍。

接下来就是如何使用:

#include<iostream>
int main() {
	char a = 1;
	short b = 2;
	int c = 3;
	long d = 4;
	long long e = 5;
	float f = 3.1425f;
	double g = 6.9876;
	char* str = (char*)"day1";
}

当你将上面的代码复制进你的vs中,就会很容易的发现,数据类型在VS中是会变色的

而紧跟着数据类型的就是变量名,也就是我们给申请到的一块内存取的一个名字,方便后面使用。

比如int,申请一块4字节的内存,并将它命名为了c ,这可以方便我们后续使用这块内存,比如可以输出它的内容:

#include<iostream>
int main() {
	char a = 1;
	short b = 2;
	int c = 3;
	long d = 4;
	long long e = 5;
	float f = 3.1425f;
	double g = 6.9876;
	char* str = (char*)"day1";

	printf("%d;%d;%d;%d;%d;%f;%f;%s\n",a,b,c,d,e,f,g,str);
	std::cout << a << ";" << b << ";" << c << ";" << d << ";" << e << ";" << f << ";" << g <<";"<<str<<"\n";
}

输出结果如下:

image-20231126091426750

上面展示的分别为C与C++输出的结果对比,回答几个你可能会感到疑惑的地方。

  • printf中的一长串东西都是些什么?

答:%是格式控制符,d表示整数,f表示小数,s表示字符串,以变量名a为例子,你可以理解为,将a作为整数替换%d所在的位置,这是按顺序依次替换的。

  • std::cout的第一个为什么不是1,而是空?

答:这是因为achar类型,即为字符类型,会被自动识别为字符。如果你将a=1改为a=49,就会发现它将输出1,因为字符1的ascii码值为49,更多字符可以参考ASCII码表

至此可以得出的结论是,你目前所看到的都是字符,且都是通过ascii码表的字符与数字之间的映射得到的。

  • 为什么printf中a不为空?

答:因为我用的%d格式控制符,表示将其按数字输出,那自然就是1了,但如果你使用%c这个格式控制符,就表示输出该数字对应的字符,也会为空。

  • 为什么"day1" 前面要加(char*)

这是因为你直接写在代码中的字符串,默认类型为const char *,加上const,意思就是常量字符串,常量意味着不允许更改,所以需要强制转换为char *,才能正常赋值给char *变量,强制转换的内容将在后面的章节中讲解。

事实上,C/C++很大一部分魅力就在于这种强制转换,但同样也是痛苦的根源。

六、格式控制

上面突然冒出这么多%d%f%s%c\n什么的,你可能会问:我上哪去知道这些东西啊?

还有如果我想更高级一点的控制方法,比如指定输出多少位小数,指定一个数占多宽,又该上哪里找资料呢?

当你感到困惑时,请记住:浏览器永远是你手中最强的工具,它是你的第二个大脑。

你无论你遇到任何问题,第一时间想到的一定是去浏览器搜索。

其次,如今ChatGPT强势来袭,遇到不懂的,还可以问ChatGPT,如果依旧无法解决,再自己琢磨。

如何自己琢磨,当然是参考官方文档了!

C/C++其实除了一个标准委员会,并没有一个带头的组织,都是各家自己搞自己的,所以资料就变得五花八门。

这里推荐一个正规的网站:cppreference.com

由于很多东西还没有讲到,所以我会在后面的章节中介绍如何快速使用该网站查询到我们所需要的内容。

亲身经历,只有自己动手过的才会记忆深刻,所以下面我会教你如何查找资料,比如,我想知道怎么输出两位小数。

最简单的办法是直接问ChatGPT:C++中如何输出两位小数?

其次,就是在浏览器中搜索:C printf 两位小数,或者:C++ cout 两位小数

之所以这样搜索,是因为浏览器一般都是用关键字进行搜索的,如果你写一大段话,可能反而会错过很多内容。

七、数组

上面讲了数据类型,此时考虑一下这样一个例子:需要有100个int型变量。

如果按上面的方法,你就需要像下面这样写:

int a1;
int a2;
int a3;
//.....

//或者也可以写成这样:
int a1,a2,a3,a4; 

这样实在繁琐,所以就有了数组:

int a[100];

是不是就简单多了?这就代表申请了100个int型数据,那么应该如何访问它们呢?

并不难,直接用下标即可:

a[0]; //第一个
a[1]; //第二个
//......以此类推

需要注意的是,数组下标是从0开始的,也就是说,你只能访问099之间的内容!

更详细深入的介绍可以参考数组

八、指针

说到指针,可能对C/C++有所了解的都会觉得它很难,但C/C++最有魅力的一点也在指针上,相信到后面大家会有所体会的!

先来谈谈指针是个什么东西,还有我们为什么需要指针?

前面提到过,所谓变量,就是一块内存,然后给这块内存取了个名字,就叫做变量名。

但除了通过名字可以找到内存之外,每块内存都是有地址的,我们还可以通过地址找到内存!

先来试一下,实践看一看变量的地址:

#include<iostream>
int main() {
	int a = 100;
	printf("地址:%p, 该地址的值:%d\n", &a, a);
}

结果如下:

image-20231126092741550

%p表示要输出地址格式,这种的话确实没办法,就遇到一个记一个就好了!

地址格式输出的为16进制,用&a取出a的地址然后进行的输出。

现在我们知道了如何得到地址,那我们应该如何使用地址呢?答案就是指针!

指针的形式如下:

数据类型 * 变量名;

比如:

int a;
double b;
char c;

int *pA=&a;
double *pB=&b;
char* pC=&c;
void* pD=&a;

可能你注意到我把char *也写在这里了。

没错,char* 就是一个指针,它存放的是字符串中第一个字符的地址,只是C/C++默认将char*作为字符串看待。

还有令人疑惑的可能就是void*void不是不确定类型吗?难不成用来存放void型变量?

但你如果试过就会发现,void是不能用来声明变量:

void m; //错误,void为不确定类型,计算机不能确定它要占几个字节的内存

void *却是能够存在的,这是为什么?

就因为它是指针!指针是用来存放地址的,所以任何指针的大小都是一样的,void * 有了大小,便可以存在,并由于void是不确定类型,所以它可以存放任何类型变量的地址!

这些指针的大小都是一样的,这个很重要!无论它前面是什么类型,它们所占内存的大小都是固定的!

不信的可以试一试:

#include<iostream>
int main() {
	int a;
	double b;
	char c;

	int* pA = &a;
	double* pB = &b;
	char* pC = &c;
	void* pD = &a;

	std::cout << sizeof(a)<<"\n";
	std::cout << sizeof(b)<<"\n";
	std::cout << sizeof(c)<<"\n\n";


	std::cout << sizeof(pA)<<"\n";
	std::cout << sizeof(pB)<<"\n";
	std::cout << sizeof(pC)<<"\n";
	std::cout << sizeof(pD)<<"\n";
}

结果为:

image-20231126093043511

这里的sizeof可以用来得到变量所在内存的大小。

可以看到,无论是1个字节的char,还是8个字节的double,其指针大小都是8个字节。

当然,现在我们并不能看到指针的优越性,因为指针大小居然跟最大的double一样大,也不节约空间啊!

说的很对,所以指针一般不会用于这种地方,但鉴于很多东西还没讲到,所以只能留到后面再说了。

来到下一个问题,我们怎么使用指针?

一般有两种方法,这里先介绍第一种,用星号*来操作,实际就是一个乘号:

#include<iostream>
int main() {
	int a=1000;
	int* pA = &a;

	std::cout << "a: " << a << " pA:" << *pA;
}

运行结果:

image-20231126093214685

这里必须要想明白逻辑,pA所在的内存,存的是a的地址,所以如果没有*号,你将输出a的地址。

而有了星号,就表示我要取这个地址所在位置的值,也就是a的值。

而对于第二种方法,暂时而言我们无法用到,只能留在后面章节讲解。

更多详细的内容可以参考文章指针与引用

九、运算符

介绍了数据结构,以及如何输出,接下来需要介绍的就是一个非常重要的部分:运算

毕竟作为计算机,运算才是它的本职工作,至少经历了九年义务教育的我们,总是知道运算肯定是需要运算符的吧。

C/C++可用运算符如下:

运算符 描述
+ 加法运算符
- 减法运算符
* 乘法运算符
/ 除法运算符
% 取余运算符
++ 自增运算符
自减运算符
?: 三目运算符
> 大于符号
< 小于符号
== 等于符号
!= 不等于符号
>= 大于等于
<= 小于等于
! 取反
||
&&

加减乘除就不用过多介绍了吧,和数学里面的概念是一样的。

%前面也用到过,当它位于字符串中的时候,表示格式控制符,而当作运算符时,则是取余。

比如7%3的结果就是1,因为7/3=2...11就是余数。

其中++表示自己加个1,--表示自己减个1,用法如下:

int a=1;
a++; //a==2,等价于a=a+1,还可简写为a+=1
a--; //a==1,等价于a=a-1,还可简写为a-=1

?:为三目运算符,如其名,可以操作三个数, 用法如下:

结果 =表达式 ? 结果1 : 结果2

上式的意思是,当表达式为true,则结果等于结果1false,则结果等于结果2,实例:

int a=4>5? 100: 200

意思:如果4>5,则a=100,否则,a=200,显然4>5的结果为false,所以a将等于200

大于小于等于这些也不用过多介绍,只是需要注意的是,等于不是一个=,而是两个=,一个等于叫赋值,两个等于才是比较,这很重要!

而不等于就是将等于的前一个等号换为感叹号 !=

还有最后一个感叹号!,意思是取反,比如true是真,那么!true则为假,false,反之亦然,实例:

#include<iostream>
int main() {

	int a = 100;
	int b = 200;
	int c = true ? a : b; //为true,则c=a
	int d = a>b ? a : b; //结果为false ,则d = b
	std::cout << a << " " << b << "\n";
	//true与false 是已被C/C++定义的关键字,可以直接使用

	a++; //自增,等同于a=a+1;
	std::cout << a << "\n";

	a--; //自减,等同于a=a-1
	std::cout << a << "\n";

	std::cout << (a == b) <<"\n"; //输出a==b的比较结果,明显不等于,结果为false,输出为0

}

当然,还有,这两个的用法其实我们在数学课中应该就已经知道:且的一假则假,或的一真则真,后面用到的时候再给大家看看在代码中是如何使用的。

既然有了运算符,那肯定就会有优先级啊,比如从小我们就知道乘除的优先级大于加减。

这时候浏览器又派上用场了,我想你应该已经知道怎么总结关键字了,尝试搜索C++ 运算符 优先级试试。

不出意外的话,你将看到一张关于优先级的表,但不用慌张,你只需要知道优先级最高的是小括号() 即可。

这就意味着,当你写任何表达式时,你想让哪个符号先计算,就给它加个括号即可,是不是很简单!

举个例子,比如我要运算4+8*5+5 %10,现在想要让两个加法先计算,然后再算乘法,最后算取余,那么就可以写成(4+8)*(5+5)%10

十、注释

上一节中的代码里面,我写了很多//,可能你会感到莫名其妙,但你又的的确确能够感受到它的作用。

没错,就是用来解释说明的,你写的代码现在你也许认识,但当几个月后,可能你自己都不知道自己当初写的什么东西。

当你将想要说的话写在 // 之后,编译器是不会管你的,这就是给你,以及给其它程序员看的。

但它也有一个缺陷,就是只能写一行,如果想要写多行,就得每行前面都加//,比如:

//第一行注释
//第二行注释
//第三行注释

这样写不是很方便,那么就可以用另外一种常见的注释方法:

/*
第一行注释
第二行注释
第三行注释
*/

只要在/**/ 之间的内容,都被编译器当作注释,而不会管你。

十一、简单总结

本文的重点在于这样几个概念:

  1. 解决方案项目源码文件之间的关系
  2. C/C++程序的基本结构
  3. 数据类型、指针、运算符、注释

下面是一些关于本文知识点的练习题,可以帮你巩固知识点,可以自己尝试回答一下:

  1. 编译器在人与计算机之间扮演着什么角色?
  2. IDE是什么?
  3. 如果你的同学需要你帮助安装VS的C++开发环境,你只能通过发送消息的方式教她,你打算怎么说?
  4. 为项目添加一个文件(新建项),快捷键是什么?鼠标点击流程是什么?
  5. 解决方案、项目、源码文件这三者之间的关系是什么样的?
  6. 一个能输出Hello World的基本程序结构能默写出来吗?
  7. 能默写出来本文提到的9种基本数据类型吗?
  8. 现在有三个变量:a,b,c分别为int类型,double类型,char * 类型,我应该在printf中填哪些格式字符将它们输出?
  9. 现在有一个变量a,它的值暂时未知,但如果a大于50,就输出a>50,否则就输出a<=50,请尝试用三目运算符完成,变量a可以自己随意赋值。
  10. 算数优先级最高的是哪个符号?请尝试将表达式 3+100*2+29%10改为3和100的和,乘以2和29的和,最后对10取余
  11. 注释的作用是什么?在C/C++中它有两种写法,你还记得吗?
  12. 我现在想要1000char类型的变量,用来存放字符串,应该怎么写?
  13. 现在有一个short s;如何得到它的地址?如何用指针访问它的值?