【前言注明】本系列主体思路均来自于B站up主“鹏哥C语言”,写文章目的主要是帮助自己理解消化大一上所学的C语言课程。
本篇文章主要是初步的,大概的,认识一遍c语言的基本脉络,在下一篇文章我会详细地进行每个部分地讲解。这篇文章适合初学者理清c语言的基本语法组成与结构。
希望我的文章可以帮到正在入门的你,如有错误的地方也请指正。文章大体风格将会偏向于简明扼要,重点都会标明。
要是觉得我写的不错那就点个赞吧。
目录
1.初识c语言
什么是C语言?
不如先来谈谈到底什么是语言?语言是人与人之间交流所必不可少的工具,那么对于计算机来说,计算机语言就是人与计算机进行交流所使用的语言。
而其中的C语言作为一种计算机编程语言则被广泛地运用于底层开发。
接下来我们再来介绍一个非常重要的东西。ANSI—C(后续会有详细解释)
ANSI C是 美国国家标准协会(ANSI)对 C语言发布的标准。使用C的软件开发者被鼓励遵循ANSI C文档的要求,因为它鼓励使用 跨平台的代码。
C 的第一个标准是由ANSI发布的。虽然这份文档后来被 国际标准化组织(ISO)采纳并且ISO发布的修订版也被ANSI采纳了,但名称ANSI C(而不是 ISO C)仍被广泛使用。一些软件开发者使用 ISO C,还有一些使用 Standard C。
ANSI C是一种标准语法。使得C语言具备了国际标准,如C89,C90,C99,前两者在世界上非常流行。
C语言发展历史
如何去写一个C语言代码?
首先肯定是需要一个合适于自己的编译器啦,一定要有趁手的兵器才可以更好的提高效率嘛。
笔者在这里推荐初学者使用DEVC++(体量小,打开即用,非常方便,初期没有什么特别要求用它就够了。)
或者VS2022也是一个不错的选择。但其体量巨大而且稍微有点复杂,b站up主“鹏哥C语言”有关于使用Vs2022的C语言的编译器的详细使用指南,链接在下面,放心使用。
https://www.bilibili.com/video/BV11R4y1s7jz?spm_id_from=333.999.0.0 https://www.bilibili.com/video/BV11R4y1s7jz?spm_id_from=333.999.0.0
笔者太懒了就不自己再一一赘述了哈。照着视频做也是可以很快上手的。
那么现在有了一个趁手的兵器,我们该如何进行下一步呢?
在开始之前,我们来引入一个新的内容 main函数
C语言的第一步总是会从main函数的第一行开始执行,也就是main是整个程序的入口。
在一个工程中可以有多个.C文件,但是在这多个.C文件中却只可以有一个也必须要有main函数。
main在这里是函数名,而int则是函数的返回类型。(后续会有解释,先记住)
在两个{}之间的则被称为函数体。
在这里我们在引入一个新的函数---printf。
printf是一个用来往屏幕上打印信息的函数。
而printf相当于是别人的东西,你借用别人的东西总是要打招呼的对不对?所以在这里我们需要在整个源文件的开头输入#include<stdio.h>,这个头文件便包含了我们正在使用的printf函数。
所以非常重要的一点,在引用系统的函数库前一定要确保声明了相应的头文件(在后续会有更多的头文件与大家见面)。
其格式大体上均为#include<******>。
有了这些知识的铺垫,那么我们就可以开始着手自己的第一个代码啦。
瞧,一个代码就出来了,随着点击运行,屏幕上打出了“hello,world”的字样。
emmmm在看到这里,初学者的你是否有了一些感觉了呢,笔者也感觉回到了大一上刚开始学习C的样子,当时因为没有区分中文和英文的格式,让人整的很崩溃啊。哦对了,在写代码时一定要记住不可以以中文的格式进行输出哦。
要像这样。谨记。
第二到第四章地链接就放到下面了,这篇文章还是主要从函数开始讲吧
2.认识常量变量
数据类型
先来看一个小例子吧,我们学习计算机,最终是要有能力写程序来解决生活中所描述的问题。
就像在一个购物商城中,有一批上架的商品,他们的标价是15.6元。那么在计算机中我们该如何进行描述呢?
15.6是一个小数,那么C语言如果要实现他,那么需要引入浮点数。
如果是描述年龄呢,那么就像50岁就是c语言中的整型。
那么在c语言中有哪些类型呢?
a如果在c语言中要描述为一个字符a,那么在c语言是这样实现的:
char ch其实就是创建了一个名叫ch的字符型空间并且将a放了进去。
同理 int age=10;
short num=5;
上一节学习了printf函数的基本用法,可以打出一些简单的信息。
那么我们如何使用printf函数打印一个整数呢?
像这样,printf("%d",100);
这里还需要引入一个新的函数 sizeof函数
sizeof作为一个关键字也作为一个操作符,可以用来计算类型或变量的所占空间大小。
#include<stdio.h>
int main()
{
printf("%d\n", sizeof(char));
printf("%d\n", sizeof(short));
printf("%d\n", sizeof(int));
printf("%d\n", sizeof(long));
printf("%d\n", sizeof(long long));
printf("%d\n", sizeof(float));
return 0;
那么在编译器中所显示的一串结果就是各种类型的大小了。
显然,sizeof的单位就是字节。
在计算机中最小的单位是比特位 bit,一个比特位存放一个二进制位。
c语言中之所以提供如此多的类型,其实是按需索取,提高了空间的利用率。
数据类型的作用其实就是为了创建变量。
变量与常量
生活中有很多的数据,有些可变,有些不可以变。
比如性别,血型等。但是年龄或者工资却是可以变化的。
即在c语言中,可变的数据对应变量,不可以变的则对应常量。
那么我们该如何定义一个变量呢?
就像前文所提到的,int age =20;
int是类型,age则是我们取的名字,也可以取其他的名字,同样我们还可以为其赋值。
但我不推荐不进行赋值。在创建时最好给一个初始化的值。这也是一种良好的编程习惯。
那么变量是否可以真的改变呢?来看下一个程序。
可以看到age真的从0变到了1.所以age是可以改变的。
那么了解了变量和常量后,咱们来认识下一个点
变量的分类
变量大体上分为两类
全局变量和局部变量。
让我们通过几个例子来理解一下。
可以发现,当我们将age=0放进了一个新的{}内,在括号外的printf函数便无法正常接收到他。
此时,age就是一个局部变量了。
那么我们再来改变一下这个程序。
可以看到我们在主函数外写入了一个int age=10;
此时程序可以正常编译了。
可以看到显示为10。
这样这个新的age就是全局变量了。
那么如果把代码改成如下图所示呢?
同名的局部和全局变量同时发挥作用了。
那么编译结果会变成什么样呢?答案是0。
当局部和全局变量名字发生冲突时,局部变量将优先。
那么我们该如何使用变量呢?这里举一个简单的例子,求取两数的和。
首先我们仍然引入一个新的函数----scanf函数。
scanf的作用是对变量进行赋值,但是不同于printf的是需要在变量名前加上地址符&。
代码如下
但是如果使用vs2013,2019,2022都会出现错误,这是为什么呢?原因是在vs库中他有自己所沿用的输出函数,scanf-s,但我不推荐使用,因为这个函数只可以在vs中运行,若是移到其他的软件则无法正常编译了。
那么该如何解决这个问题呢?
将#define _CRT_SECURE_NO_WARNINGS 1放置在开头即可正常使用scanf函数了。
那么编写代码时总不可能每次都输入一遍吧,所以我们需要在文件路径中找到newc++file这个文件,以记事本的形式打开并将我上面的那串字符复制进去即可。
找到你安装vs的位置,大体路径如下,可作参考
什么是常量?
常量大体上可以分为4类
先来看看字面常量吧
如其名,字面常量就是一些如3.14,10,‘a'这样的常量。
而const修饰的常变量则具备无法被改变的属性。
先定义一个sum=10;
再令sum=20,此时sum是可以从10变到20的,但如果变为const int sum=10;,那么sum便会变成无法修改的量。
由define所定义的标识符常量也同const效力差不多,格式为#define xxx 数值
像是#define age 10
#define max 1000
枚举常量就是可以一一列举的常量。
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
enum sex {
male,
female,
secret
};
int main() {
printf("%d\n", male);
printf("%d\n", female);
printf("%d\n", secret);
return 0;
}
enum sex{}就是一个枚举体,sex是性别,我们往里面定义了male(男性),female(女性),secret(秘密)。
同时我们所列举的第一个常量值为0,并且逐次递增。
3.生命周期相关概念
作用域
作用域,顾名思义,哪里可以使用,那么哪里就是作用域。
就像上一节讲的变量一样,局部作用域就是变量所在的局部范围,而全局作用域就是整个project。
{
int a=10;
}
这个变量a只可以在{}中使用。
生命周期
就是变量创建与销毁之间的时间段。
局部变量如上面那个被{}框住的a,出了{}便不可用了,会被销毁。
而全局变量的生命周期却可以是整个程序生命周期。
4.初始字符串,转义字符,注释
字符串
字符串就是一串字符。用""括起来的一串字符。
而字符串的结束标志则是/0
如代码所示,创立了一个字符数组,[]中可以不必规定长度,依后面所给的字符串来定。
同时,字符串在结尾处隐藏了一个/0的字符,而这个字符也就是字符串的结束标志。
如代码所示,我们输入了arr1 和arr2,那么他们到底是否相同呢?
arr1,在abc后有/0,所以在打印完c后会终止,而arr2后面没有/0,所以会有意料之外的结果。,在arr2后面加上一个终止字符就可以了。
如何求一个字符串的长度呢?
那就要引入一个新的函数 strlen函数。
让我们引用strlen来修改一下上面的代码。
注意在调用strlen时要添加新的头文件#include<string.h>
如果用strlen去计算arr2的长度,则会出现一个随机值,他会随着/0的出现而停止。
认识转义字符
先来看代码
输出结果
可以看到\t并没有显示出来,可以看出其转变了原来的意思,故名转义字符。
更准确的说,转义字符(Escape character),是所有的ASCII码都可以用“\”加数字(一般是8进制数字)来表示。而C中定义了一些字母前加"\"来表示常见的那些不能显示的ASCII字符,如\0,\t,\n等,就称为转义字符,因为后面的字符,都不是它本来的ASCII字符意思了。(源自百度百科)
同样的,之前我们见过的\n也是一个转义字符,作用为换行。
大家可以自行百度更多的转义字符及其作用。
我们来讲个用法。如果我们想打印'
我们得这样来
int main()
{
printf("%c",'\'');
return 0;
}
在要打印的'前加一个\使其变成转义字符
再如先前所打印的\t,在前面再添加一个\即可打印出\t
有两种非常特殊的转义字符
\ddd ddd表示的是三个八进制的数字
\xdd dd表示两个十六进制的数字
可以看到打印出了x和0两个字符,可以看出130转换为十进制正好为x的ascii码值,0则同理。
注释
用来解释复杂代码。也用于将一段代码给注释掉。但并不将其从源文件中删除。
方法1 在代码行前添加//,本行代码在执行中不再被执行。
方法2 /* */ 在范围内的全部代码都不被执行。
5.认识函数与数组
函数
在数学中,像是f(x)=1+4x,这就是大家熟悉的函数。
在c语言中也是一样的。
像f(x+y)=x+y,就是一个将x与y相加的函数。
来看一个实例。
根据运行结果来看,add函数完美完成了我想做的事,我随意输出两个数并且让他们成功相加得出结果了。
再来看一个比喻吧。
我:张三 带饭(蛋炒饭 20)
这里的add就相当于张三,我让张三去带饭,add也完成了xy相加的工作。
蛋炒饭和20,还有xy就是参数。
参数的传递是非常重要的,就像我跟你说话,耳朵会作为一个媒介,来作为咱俩交流的工具。
当你写好可以完成某一项工作的函数,你可以一直使用它,而不是在下一次处理类似问题时还要重新编写代码来完成它,这也是出现函数的意义。
数组
如果让你存几个数字,你会怎么去存呢?一个一个的去存,如果有一百个那你难道要输入一百遍吗?
这就要用到数组了。
数组 一组相同类型元素的集合。
来看代码
按下f10,我们可以发现一些其他的不一样,比如他是以【0】开始的,arr中一直出现到了【10】。
数组是用下标来访问的。
如果我想打印出所有的数字呢?
这就要利用上一节讲的循环语句来快速打印了。
操作符
经过我们的运算,9除以2却没有得到4.5,而是4。
那是因为进行的是整数除法。
那该如何得到4.5呢?
将9或者2中一个改成2.0或9.0,再将输出函数中的%d换成%f,就可以顺利得到4.5啦。 注意还有数据类型int更改为float哦。
再看一个代码
得到的是余数。
再来讲讲移位操作符。
左移操作符----移动的是二进制位。
得到的答案是4。为什么会得到4而不是3或者1呢?明显不管是左移或是右移得到4都是不合理的。
我们来看一下移位操作符的原理。
首先,a是代表十进制中的2,那么二进制该如何表示呢?
首先要明白,int这个类型为4个字节的大小(计组的知识点),也就是需求32位,而2的01明显不够32位,那么就需要在前面补0了。
0000000000000000000000000000010
而代码中的b=a<<1所要表达的意思就是存储的这32位都要集体向左移动一位,那么也就意味着丢失了一位0.在最后的一个空位补齐一个0,那么这样b就变成了4了。
(简单了解,以后补足)位操作符: & | ^
举个例子吧,a+=6也就等于之前的a的值加上一个6,再将得到的这个值重新赋到a的身上。
a+b,对+来说他有两个操作数,分别是a和b,所以称他为双目操作符。那么不难知道单目操作符就是只有一个操作数了。
代码解释
得到的编译结果是0。
在c语言中0表示假,非0表示真。
但如果反过来将假变成真呢?在c中默认的真值是1.
它的用途还有如下所示
如果a为真则会引起一个结果,如果a为假则会引起一种另外的结果。
顾名思义,就是我们所理解的数学上的取反的意思了。
sizeof后面的括号可以省略也从侧面说明了其不是一个函数,而是一个操作符,函数后面的括号是不可以省略的。
再来看看在c语言中如何通过sizeof来计算数组元素个数呢?
arr代表的是整个数组,而arr【0】则是其中的一个元素。
第一个sizeof计算的是数组的总大小,第二个呢则是单个数组单元的大小,二者相除就可以得到元素个数了。
int main() {
int a = 0;
printf("%d\n", ~a);
return 0;
}
为什么结果是-1呢?
按位取反,其中的位是二进制位,而非我们所想的直接将1与0进行互换就可以了。
a的二进制会表示为32个0,将其取反后会变成32个1,也正好对应按位二字。那为什么会是-1呢?
原因如下,数据在内存中存储的是补码。原码反码补码的概念如果不明白请自行百度(笔者提一嘴,对于计算机的初学者来说,自学是非常重要的,你会遇到很多很多课堂上没有讲过或你没有遇到过的问题,那么你就需要自己上网去寻找答案或者相关解释)。
计算机如何存储-1呢?
-1的原码为1000.....01
补码也就变成了111111...11,也就是我们刚才按位取反的结果啦。
++ 前置,后置++
结果是什么呢?a和b都是11。
前置++的运算规律是先加后使用。a原先是10,那么就先对自身加1再来使用。
那么后置++的规律就是先使用后在对自身加1了。结果也正如我们的想法,是10与11。
但我仍然要提一点,类似于int b=(++a)+(++a)+(++a)这样的代码,去深究他是没有意义的,而且在不同的编译器上可能会产生不同的结果,在某些大学的c语言考试中这样的代码题目还有很多,但我希望大家明白不要在上面去花功夫,正常人是不会这么写代码的。不要过于深究。
这样会出现错误,int是整数类型,而3.14确是小数,所以会出现警告,会丢失其原先所拥有的精度。但是在vs2022上没有报错,而是直接出现了3这个答案。
如果报错我们可以进行强制类型转换。这种语法是允许存在的。
编译的结果c显示为1。a&&b的意思就是左右都为真的时候整体上会为真。根据上文我们所讲的可以得到c是为1的。
若是将&&换成||,再将a换为0,则结果仍然会为1,那么大家应该可以知道||与&&的区别了吧。
也被称为三目操作符。其格式为 exp1?exp2:exp3 他所描述的就是如果exp1成立,则整个表达式就是exp2的结果,如果exp1不成立,则会表达出exp3的结果来。
从代码上看会比之前所表达的更加简洁明了。
逗号隔开的一串表达式。来看一个代码体会一下。
他表达的是什么意思呢?他会从左到右依次计算并且将得到的值赋给abc。整个表达式的结果会是最后一个表达式的结果。
首先a会变成5,c就会等于5-4=1,b就会成为3,那么整个式子的结果就会成为3。
还有部分重要的操作符在本文中还未被提及,他们会随着文章的更新逐渐进入你的视野,我会详细的进行介绍。