本章为该系列教程的第一章,本系列教程目录可点击这里查看
如果你是一个刚入计算机行业不久的新手,你可能总能看到C/C++,python,java等等众多字眼,是的,这些就是编程语言
而C/C++就是其中非常耀眼的一门编程语言,点击这里看编程语言实时排行榜
虽然这看上去C与C++是两门不同的语言,但事实上,C++是完全兼容C的,大部分情况下都可以说,C++是C的升级版,毕竟是在C的基础上多了两个加号嘛
至于python,java,C#等其它众多语言,基本都是在C与C++的基础上开发实现的,所以当你彻底掌握C/C++之后,其它语言对于你来说也只是小菜一碟(确信 )
而所谓的编程语言,C/C++,我们可以直接理解为是我们人类与计算机交流的语言
比如,当你拥有1万张图片想要将图片名称改为特定的格式时,你不可能手动更改,于是你就可以用编程语言告诉计算机,让计算机帮你改
以上只分为了两个层次,也就是人与计算机
但事实上,你写的编程语言,计算机其实并不认识,因为计算机只认识0和1,这该怎么办?
这就需要人与计算机的中间层,编译器,你所写的所有编程语言,无论是C/C++,还是java,python,都是给对应的编译器看的,当编译器看到你所写的内容没有问题之后,才会将其翻译为0与1组成的机器码,计算机才能识别并执行它
你经常在windows平台看到的.exe
文件,就是编译器将程序员所写的内容,翻译出来的,当你点击它,电脑就会执行它
大概如下图:
当然,上面这张图是极其简陋的,只是为了方便新手快速建立一个概念:我们通过写某种编程语言的代码,需要通过该语言的编译器翻译,最后才能够让计算机执行
如果对此感兴趣并想要深入了解的,可以直接在浏览器中搜索 C/C++ 编译过程 ,就可以得到很多优秀的解释
如果你去浏览器中搜索,C/C++ 学完能够干什么?
你会发现众多答案中, 无所不能 这个词可能是对它描述最多的
但如果当你跟着网上免费教程学完之后,自认已经精通C/C++这门语言了,想要做点什么的时候,却又会发现自己似乎什么也做不了
这并不是 ”无所不能“ 这个词用错了,而是你仅仅只学习了C/C++这门语言本身,而且只学习了其中最重要且最基础的部分
既然本系列是付费文章,我自然也会尽力避免这种情况,请相信我,只需要短短几章,你就能够独立写出东西来!
虽然用记事本我们也一样能够码代码,然后下载个编译器,就可以进行编译了,但那会浪费我们非常多的时间去研究,对新手极不友好,所以推荐大家直接下载集成开发环境,Visual Studio
当你真正深入了解了这门语言之后,再尝试那些比较复杂的操作,也就会水到渠成
Visual Studio是一款非常强大的集成开发环境,也就是大家常说的IDE,号称宇宙最强,该软件内集成了编译器,同时还有非常多其它的强大功能,可以极大的提高程序员码代码的效率
点击这里前往官网下载
这里下载社区版即可,完全免费的!
当然,如果你已经下载好了较为低的版本,比如2019,2017等,可以不用再下载了,区别其实不是很大
我用VS2022,主要是为了跟上时代的步伐,让该系列教程能够适应的更久一点罢了
下载完成后,点击安装即可,中间的步骤可根据需要随意选择,唯一需要注意的是,需要勾选下图红框中的内容:
同时还可以自行更改安装路径,因为该组件还是比较大的,可以更改到D盘等
然后等待安装完成即可
在开始写代码之前,我们有必要理清一下VS(Visual Studio的简称)中的部分关系:
上图所要说明的一件事是,一个解决方案内可以有多个项目,一个项目中可以有多个文件
为了更加直观的理解,我们以QQ为例子,一个QQ就是一个解决方案
但如图可以看到,除了QQ.exe
外,还有相当多的.exe
文件,.dll
文件
包括QQ.exe在内,这些就是QQ这个解决方案下的许多项目所生成的东西,各自完成QQ这个软件整体的一部分功能,而每个项目又都是由相当多的文件所编译生成的
了解了这个,我们就可以来写hello world了
然后,选择创建一个控制台的空项目
这里就用到了上面所说的知识点,解决方案和项目可以分别命名,如果你确信这个解决方案里面只会有一个项目,那么可以不用区分这两者
同时不要勾选将解决方案和项目放在同一目录下,因为如果当你在该解决方案内建立多个项目的话,就会乱套的
当然你也可以自己选择存放项目文件的位置
然后就可以点击右下角的创建按钮了
创建成功后,你会发现空无一物,这就是空项目
所以我们需要新建一个文件
首先,你需要找到解决方案资源管理器,如果你的界面没有这个界面框,请按下图步骤打开
然后,就可以添加一个文件了
右键点击源文件,添加,新建项。当然你也可以直接按快捷键 Ctrl+Shift+A
输入以下代码:
#include
int main() {
printf("Hello World!\n");
std::cout << "Hello World!\n";
}
然后点击运行:
至此,你就可以输出了,printf为C语言的输出方式,std::cout为C++的输出方式
当然你可能会问为什么要这么写或这样做?各个语句的意思是什么?
但很抱歉,暂时我无法做出解释,因为上面短短几行的内容与步骤,就包含了相当多的知识点,所以只能留在后面慢慢解释
但你需要记住这个结构和这些步骤,因为这是最基础的,这和在你真正理解乘法前,先把最基础的乘法口诀记住一个道理
你现在所必须知道的一个事实是:程序是从main后面的{}里面开始运行的,遇到一句,就执行一句
并且需要注意的是,代码中,一旦涉及到字符,统统使用英文字符!否则将出现错误
一劳永逸的办法就是,设置自己的输入法,在中文模式下依旧使用英文符号!
我用的windows系统自带的输入法,其它输入法应该也是有这个功能的,可以自己摸索
至此,你就可以用std::cout,或者printf,按上面的格式,打印任意内容了, 字符中添加的\n,可直接理解为换行的意思
以目前的情况,暂时并不适合讲解std::cout与printf这两个的原理,所以你只需要记住各自的输出方式即可
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
long
与 long long
用来表示整数,float
与double
用来表示小数
你可能会想,明明就整数和小数两个类型,为什么要分出这么多类型?
因为C/C++发展了几十年啊,以前内存可是非常珍贵的,能用char
,1个字节,那肯定不用int
,4个字节来表示一个数字
因为历史的种种因素,最终导致了如今这多样的数据类型,记住即可
事实上现在的各种高级语言都在逐渐简化基本数据类型的个数
接下来就是如何使用:
#include
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中是会变色的,而紧跟着数据类型的就是变量名,也就是我们申请一块内存
比如int
,申请一块4字节的内存,就将它命名为c
,方便我们后面使用这块内存
然后我们就可以输出了
#include
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";
}
上面展示的分别为C与C++输出的结果对比,回答几个你可能会感到疑惑的地方
printf
中的一长串东西都是些什么? 答:%
是格式控制符, d
表示整数,f
表示小数,s
表示字符串,以变量名a
为例子,你可以理解为,将a作为整数替换%d
所在的位置,这是按顺序替换的std::cout
的第一个为什么不是1,而是乱码? 答:这是因为a为char 类型,
即为字符类型,会被自动识别为字符,如果你将a=1
改为a=49
就会发现,将会输出1, 因为字符1的ascii
码值为49 ,更多字符表可以参考这里;至此可以得出的结论是,你所看到的都是字符,都是通过
ascii
码表的字符与数字之间的映射得到的
printf
中a不乱码? 答:因为我用的%d
,表示输出本来的数字,如果你使用%c
,就表示输出该数字对应的字符,也会乱码"day1"
前面要加(char*)
,这是因为你直接写在代码中的字符串,默认类型为const char *
, 加上const
,意思就是常量字符串,所谓常量,就是不允许更改,所以需要强制转换为char *
,才能正常赋值给char *
变量 ,强制转换的内容将在后面的章节中讲解事实上,
C/C++
很大一部分魅力就在于这种强制转换,但同样也是痛苦的根源
上面突然冒出这么多%d
,%f
,%s
,%c
,\n
什么的,你可能会问:我上哪去知道这些东西啊!
还有如果我想更高级一点的控制方法,比如指定输出多少位小数, 指定一个数占多宽 ,又该上哪里找资料呢?
那我可以告诉你,浏览器永远是最强的工具,你无论你遇到任何问题,第一时间想到的一定是去浏览器搜索,只有当你搜索不到时,再自己琢磨
如何自己琢磨?当然是参考官方文档了!
C/C++其实除了一个标准委员会,并没有一个带头的组织,都是各家自己搞自己的,所以资料就变得五花八门
这里推荐两个比较正规的网站:C++参考与C++参考1
由于很多东西还没有讲到,所以我会在后面的章节中解释应该如何正确使用该网站查询需要的内容
亲身经历,只有自己动手过的才会记忆深刻,所以下面我会教你如何查找资料
比如,我想知道怎么输出两位小数
就可以在浏览器中搜索: C printf 输出两位小数
之所以这样搜索,是因为浏览器一般都是用关键字进行搜索的,如果你写一大段话,可能就会错过很多内容
如果你想用C++的方式输出两个小数,同样如此搜索: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开始的!
也就是说,你只能访问0到99之间的内容!
说到指针,可能对C/C++有所了解的都会觉得它很难!
但C/C++最有魅力的一点也在指针上,相信都后面大家会有所体会的!
先来谈谈指针是个什么东西,还有我们为什么需要指针?
前面提到过,所谓变量,就是一块内存,然后给这块内存取了个名字,就叫做变量名
但除了通过名字可以找到内存之外,每块内存都是有地址的,我们还可以通过地址找到内存!
先来试一下,实践看一看变量的地址:
#include
int main() {
int a = 100;
printf("地址:%p, 该地址的值:%d\n", &a, a);
}
%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
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";
}
其中,sizeof
用于得到变量所在内存的大小
可以看到,无论是1个字节的char
,还是8个字节的double
,其指针大小都是8个字节!
当然,现在我们并不能看到指针的优越性,因为指针大小居然跟最大的double
一样大!也不节约空间啊!
说的很对!所以指针一般不会用于这种地方,但鉴于很多东西还没讲到,所以只能留到后面再说了
来到下一个问题,我们怎么使用指针?
有两种方法!
这里先介绍第一种:
第一个方法是用星号 *
,实际就是一个乘号
#include
int main() {
int a=1000;
int* pA = &a;
std::cout << "a: " << a << " pA:" << *pA;
}
这里必须要理清一个观念,pA
所在的内存,存的是a
的地址,所以如果没有*
号,你将输出a
的地址
而有了星号,就表示我要取这个地址所在位置的值,也就是a
的值。
而对于第二种方法,暂时而言我们无法用到,只能留在后面章节讲解
介绍了数据结构,以及如何输出,接下来需要介绍的就是一个非常重要的部分-运算
毕竟作为计算机,运算才是它的本职工作,至少经历了九年义务教育的我们,总是知道运算肯定是需要运算符的吧
C/C++可用运算符如下:
运算符 | 描述 |
---|---|
+ | 加法运算符 |
- | 减法运算符 |
* | 乘法运算符 |
/ | 除法运算符 |
% | 取余运算符 |
++ | 自增运算符 |
– | 自减运算符 |
?: | 三目运算符 |
> | 大于符号 |
< | 小于符号 |
== | 等于符号 |
!= | 不等于符号 |
>= | 大于等于 |
<= | 小于等于 |
! | 取反 |
|| | 或 |
&& | 且 |
加减乘除就不用过多介绍了
%
前面也用到过,当它位于字符串中的时候,表示格式控制符,而当作运算符时,则是取余,比如 7%3
的结果就是1
,因为7/3=2...1
,1
就是余数
++
表示自己加个1,--
表示自己减个1
用法如下:
int a=1;
a++; //a==2,等价于a=a+1,还可简写为a+=1
a--; //a==1,等价于a=a-1,还可简写为a-=1
?:
为三目运算符,如其名,可以操作三个数, 用法如下:
结果 =表达式 ? 结果1 : 结果2
上式的意思是,当表达式为true
,则结果等于结果1
,false
,则结果等于结果2
实例:
int a=4>5? 100: 200
意思:如果4>5
,则a=100
,否则,a=200
,显然.4>5
的结果为false
,所以a
将等于200
大于小于等于这些也不用过多介绍,只是需要注意的是,等于不是一个=
,而是两个=
,一个等于叫赋值,两个等于才是比较,这很重要
而不等于就是将等于的前一个等号换位感叹号 !=
还有最后一个感叹号!
,意思是取反,比如true
是真,那么!true
则为假,false
,反之亦然
实例:
#include
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
是不是很简单! 想让谁先算,就给它加小括号就行了
上一节中的代码里面,我写了很多 // ,可能你会感到莫名其妙,但你又的的确确能够感受到它的作用
没错,就是用来解释说明的,你写的代码现在你也许认识,但当几个月后,可能你自己都不知道自己当初写的什么玩意
当你将想要说的话写在 //
之后,编译器是不会管你的,这就是给你,以及给其它程序员看的
但它也有一个缺陷,就是只能写一行,如果想要写多行,就得每行前面都加 //
比如:
//第一行注释
//第二行注释
//第三行注释
不是很方便
这时候就可以用另外一种常见的注释方法:
/*
第一行注释
第二行注释
第三行注释
*/
只要在/*
与*/
之间的内容,都被编译器当作注释,而不会管你
Hello World
的基本程序结构能默写出来吗?a,b,c
分别为int
类型 ,double
类型, char *
类型, 我应该在printf
中填哪些格式字符将它们输出?a大于50
,就输出 a>50
,否则就输出 a<=50
,请尝试用三目运算符完成(变量a可以自己随意赋值)3+100*2+29%10
改为3和100的和
,乘以2和29的和
,最后对10取余
1000个char
类型的变量,用来存放字符串,应该怎么写?short s;
如何得到它的地址?如何用指针访问它的值?