C语言语法 -基础语法(在选择循环语句处截止)
1.第一个helloworld程序的解读
#include <stdio.h>int main() {printf("Hello World!");return 0;
}
我们的C语言程序入口点就是main
函数
然后我们看到,如果我们需要打印一段话到控制台,那么就需要使用printf(内容)
来完成,这其实就是一种函数调用,但是现在我们还没有接触到,我们注意到括号里面的内容就是我们要打印到控制台的内容:我们要打印的内容需要采用双引号进行囊括,被双引号囊括的这一端话,我们称为字符串,
#include <stdio.h> 这个是引入系统库为我们提供的函数,包括printf
在内
2.注释
在c语言中,我们既可以使用单行注释,也可以使用多行注释。被注释掉的内容不会再程序运行中算进代码中,仅供开发人员对代码进行一些功能注释和使用解释。
// 这是C语言的单行注释,在//符号后面的这一行内容全被注释掉了/*这是C语言的多行注释,在/* 与 */之间所有的内容都被注释掉了*/
3.标识符和关键字
标识符:
-
不能重复使用其他变量使用过的名字。
-
只能包含英文字母或是下划线、数字,并且严格区分大小写,比如
a
和A
不算同一个变量。 -
虽然可以包含数字,但是不能以数字开头。
-
不能是关键字(比如我们上面提到的所有基本数据类型,当然还有一些关键字我们会在后面认识)
-
(建议)使用英文单词,不要使用拼音,多个词可以使用驼峰命名法或是通过下划线连接。
关键字:
4.基本数据类型
整数类型
我们首先来看看整数类型,整数就是不包含小数点的数据,比如1
,99
,666
等数字,整数包含以下几种类型:
-
int - 占用 4 个字节,32个bit位,能够表示 -2,147,483,648 到 2,147,483,647 之间的数字,默认一般都是使用这种类型
-
long - 占用 8 个字节,64个bit位。
-
short - 占用2个字节,16个bit位。
浮点类型
浮点类一般用于保存小数,不过为啥不叫小数类型而是浮点类型呢?因为我们的一个小数分为整数部分和小数部分,我们需要用一部分的bit位去表示整数部分,而另一部分去表示小数部分,至于整数部分和小数部分各自占多少并不是固定的,而是浮动决定的(在计算机组成原理中会深入学习,这里就不多介绍了)
-
float - 单精度浮点,占用4个字节,32个bit位。
-
double - 双精度浮点,占用8个字节,64个bit位。
字符类型
除了保存数字之外,C语言还支持字符类型,我们的每一个字符都可以使用字符类型来保存:
- char - 占用1个字节(-128~127),可以表示所有的ASCII码字符,每一个数字对应的是编码表(ASCII)中的一个字符:
5.数据类型的转换(自动转换和强制转换)
自动转换(隐式转换)
-
不同的类型优先级不同(根据长度而定)
-
char和short类型在参与运算时一律转换为int再进行运算。
-
浮点类型默认按双精度进行计算,所以就算有float类型,也会转换为double类型参与计算。
-
当有一个更高优先级的类型和一个低优先级的类型同时参与运算时,统一转换为高优先级运算,比如int和long参与运算,那么int转换为long再算,所以结果也是long类型,int和double参与运算,那么先把int转换为double再算。
强制转换
(强制转换类型) 变量、常量或表达式;
#include <stdio.h>int main() {int a = (int) 2.5; //2.5是一个double类型的值,但是我们可以强制转换为int类型赋值给a,强制转换之后小数部分丢失int b = (int) (a + 2.8); //注意得括起来表示对整个算式的结果进行类型转换(括号跟数学中的挺像,也是提升优先级使用的,我们会在运算符部分详细讲解),不然强制类型转换只对其之后紧跟着的变量生效printf("%d", a);
}
6.运算符
基本运算符
基本运算符包含我们在数学中常用的一些操作,比如加减乘除,分别对应:
-
加法运算符:+
-
减法运算符:-
-
乘法运算符:*
-
除法运算符:/(注意不是“\”,看清楚一点)
-
取余运算符:%
关于算数优先级:在数学中,加减运算的优先级是没有乘除运算优先级高的,所以我们需要先计算那些乘除法,最后再来进行加减法的计算,而C语言中也是这样,运算符之间存在优先级概念。我们在数学中,如果需要优先计算加减法再计算乘除法,那么就需要使用括号来提升加减法的优先级
自增自减运算符
我们可以快速使用自增运算符来将变量的值+1
int a =10;
//正常情况下,想要一个变量值自增
a = a+1;
//现在,使用自增运算符,我们可以将其替换为如下
a++;
++a;
//以上两种都是在语句结束后,变量a的值加一
/*
区别:自增运算符++在前,那么先自增再出结果;自增运算符++在后,那么先出结果再自增。
*/
当然,我们也可以快速使用自减运算符来将变量的值 -1
int a =10;
//正常情况下,想要一个变量值自减
a = a-1;
//现在,使用自减运算符,我们可以将其替换为如下
a--;
--a;
//以上两种都是在语句结束后,变量a的值减一
/*
区别:自减运算符--在前,那么先自减再出结果;自减运算符--在后,那么先出结果再自减。
*/
复合赋值运算符
那要是现在我们不想自增1而是自增2或是其他的数字呢?我们可以使用复合赋值运算符
int a = 10;
//正常情况下,想要一个变量值自减
a = a + 5;
//使用复合赋值运算符,可以将上面替换为
a +=5;//效果与上面的一样
复合赋值运算符不仅仅支持加法,还支持各种各样的运算:
-= += *= /= %=
位运算符
前面我们学习了乘法运算符*
,当我们想要让一个变量的值变成2倍,只需要做一次乘法运算即可
int a = 10;
a *= 2; //很明显算完之后a就是20了int a = 10;
a = a << 1; //也可以写成复合形式 a <<= 1
/*
我们会发现这样运算之后得到的结果居然也是20,这是咋算出来的呢?实际上<<是让所有的bit位进行左移操作,上面就是左移1位,我们可以来看看:● 10 = 00001010 现在所以bit位上的数据左移一位 00010100 = 20是不是感觉特别神奇?就像我们在十进制中,做乘以10的操作一样:22乘以10那么就直接左移了一位变成220,而二进制也是一样的,如果让这些二进制数据左移的话,那么相当于在进行乘2的操作。
*/
a = a >> 1; //右移其实就是除以2的操作int a = 6, b = 4;
int c = a & b; //按位与操作
/*
按位与实际上也是根据每个bit位来进行计算的:● 4 = 00000100
● 6 = 00000110
● 按位与实际上就是让两个数的每一位都进行比较,如果两个数对应的bit位都是1,那么结果的对应bit位上就是1,其他情况一律为0
● 所以计算结果为:00000100 = 4
*/int a = 6, b = 4;
int c = a | b;
/*
● 4 = 00000100
● 6 = 00000110
● 按位与实际上也是让两个数的每一位都进行比较,如果两个数对应bit位上其中一个是1,那么结果的对应bit位上就是1,其他情况为0。
● 所以计算结果为:00000110 = 6
*/int a = 6, b = 4;
int c = a ^ b; //注意^不是指数运算,表示按位异或运算,让两个数的每一位都进行比较,如果两个数对应bit位上不同时为1或是同时为0,那么结果就是1,否则结果就是0,所以这里的结果就是2
a = ~a; //按位否定针对某个数进行操作,它会将这个数的每一个bit位都置反,0变成1,1变成0,猜猜会变成几
逻辑运算符
逻辑与 &&
逻辑或 ||
取反 !
条件运算符(三目运算符) ?:
7.运算符的优先级
运算符 | 解释 | 结合方式 |
---|---|---|
() | 同数学中的括号,直接提升到最高优先级 | 由左向右 |
! ~ ++ – + - | 否定,按位否定,增量,减量,正负号 | 由右向左 |
* / % | 乘,除,取模 | 由左向右 |
+ - | 加,减 | 由左向右 |
<< >> | 左移,右移 | 由左向右 |
< <= >= > | 小于,小于等于,大于等于,大于 | 由左向右 |
== != | 等于,不等于 | 由左向右 |
& | 按位与 | 由左向右 |
^ | 按位异或 | 由左向右 |
| | 按位或 | 由左向右 |
&& | 逻辑与 | 由左向右 |
|| | 逻辑或 | 由左向右 |
? : | 条件 | 由右向左 |
= += -= *= /= &= ^= |= <<= >>= | 各种赋值 | 由右向左 |
, | 逗号(顺序) | 由左向右 |
8.关于变量和输入输出函数(printf函数与scanf函数)
9.if-else
if-else语句有以下几个变形
if(); if-else;else if();if也可以嵌套
下面逐个介绍
if-else
if(表达式1)
{语句1}
else
{语句2}
执行流程:先求解表达式,如果表达式为“真”,就执行语句1;否则(即表达式的值为“假”),就执行语句2。语句1和语句2总要执行一个,但是不会都执行。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gRjlD8sq-1673269602583)(C:\Users\12745\Desktop\线性代数\ifelse.jpg)]
if()
if(表达式1)
{语句1}
执行流程:先求解表达式,如果表达式的值为“真”,就执行语句1;否则(即表达式的值为“假”),就什么也不做。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hanBAmjI-1673269602584)(C:\Users\12745\Desktop\线性代数\if.jpg)]
else-if
if(表达式1)
{语句1}
else if(表达式2)
{语句2}
..........
else if(表达式n-1)
{语句n-1}
else
{语句n}
执行流程:首先求解表达式1,如果表达式1的值为“真”,则执行语句1,并结束整个if语句的执行,否则,求解表达式2……最后的else处理给出条件都不满足的情况,即表达式1,表达式2,……表达式n-1的值都为“假”时,执行语句n。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Jk0risuX-1673269602584)(C:\Users\12745\Desktop\线性代数\elseif.jpg)]
if-else语句嵌套
if(表达式1)
{if(表达式2) {语句1}else {语句2}
}
else
{if(表达式3) {语句3}else {语句4}
}
else和if的匹配准则:else与最靠近它的,没有与别的else匹配过得if相匹配。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zTB7IkbQ-1673269602584)(C:\Users\12745\Desktop\线性代数\if嵌套.jpg)]
10.switch
switch(表达式){case 常量表达式1: 语句段1; break;case 常量表达式2: 语句段2; break;case 常量表达式3: 语句段3; break;..............case 常量表达式n: 语句段n; break;default: break;
}
执行流程:首先求解表达式,如果表达式的值与某个常量表达式的值相等,则执行该常量表达式后的相应语句段,如果表达式的值与任何一个常量表达式的值都不相等,则执行default后的语句段,最后执行break语句,跳出switch语句。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JGJA9A2f-1673269602585)(C:\Users\12745\Desktop\线性代数\switch语句.jpg)]
注意:
1.在switch语句中,表达式和常量表达式的值一般是整形或字符型,所有的常量表达式的值都不能相等。每个语句段都可以包括一条或多条语句,也可以为空语句。
2.switch语句中,default可以省略,如果省略了default,当表达式的值与任何一个常量表达式的值都不相等时,就什么也不执行。
3.在switch语句中不使用break语句:
break语句在switch语句中是可选的,不使用break语句的switch语句是:
switch(表达式){case 常量表达式1: 语句段1;case 常量表达式2: 语句段2;…………case 常量表达式n: 语句段n;default: 语句段n+1;
}
不使用break时,如果表达式的值与常量表达式2的值相等,不但执行语句段2,还执行其后的所有语句,即执行语句段2——语句段n-1。
11.while
while语句 与 do-while语句
while语句
while(表达式){循环体语句;
}
执行流程:当表达式的值为“真”时,循环执行,直到表达式的值为“假”,循环中止并继续执行while的下一条语句。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MWzEITeQ-1673269602585)(C:\Users\12745\Desktop\线性代数\while.jpg)]
现在讨论while语句
1.while语句中的表达式可以是任何合法的表达式,循环体语句只能是一条语句。
2.从两种循环语句的形式和执行流程可以看出,while语句的构成简单,只有一个表达式和一条循环体语句,分别对应循环的两个核心要素:循环条件和循环体,可以直接把循环问题的分析设计转换成语句实现。
3.循环的实现一般包括4个部分,即初始化,条件控制,重复的操作以及通过改变循环变量的值最终改变条件的真假性,使循环能正常结束。这4个部分可以直接和for语句中的4个部分(表达式1,表达式2,循环体语句和表达式3)相对应,当使用while语句时,由于它只有2个成分(表达式和循环体语句),就需要另加初始化条件,至于第4个部分,从4.1和4.2图可知,while语句的循环体语句可包含for语句的循环体语句和表达式3,所以while的循环语句中必须包含最终能改变循环条件真假性的操作。
do-while
do{循环体语句;
}while(表达式);
执行流程:第一次进入循环时,首先执行循环体语句,然后再检查循环控制条件,即计算表达式,若值为“真”,继续循环,直到表达式的值为“假”,循环结束,执行do-while的下一条语句。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eOBnEvNk-1673269602585)(C:\Users\12745\Desktop\线性代数\do-while.jpg)]
讨论:
(1)do-while语句和while语句的区别:do-while语句是,先执行循环体,后判断循环条件。所以无论循环条件的值如何,至少执行一次循环体。
关于while语句和do-while应用的环境:
do-while语句适合于先循环,后判断循环条件的情况,一般在循环体的执行过程中明确循环控制条件。它每执行一次循环体后,再判断条件,以决定是否进入下一次循环。
while语句和for循环语句都能实现循环。一般情况下,如果题目中指定了循环次数,使用for语句更清晰,循环的4个组成部分一目了然;其他的情况下多使用while语句。例如某些情况下没有直接给出循环次数,而是由某一项的值来控制循环,因此就选用了while语句。
12.for语句
for语句
for(表达式1;表达式2;表达式3)
{循环体语句
}
执行流程:先计算表达式1;在判断表达式2,若值为“真”,则执行循环体语句,并接着计算表达式3,然后继续循环;若值为“假”,则结束循环,继续执行for的下一条语句。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bEW0Cyn7-1673269602586)(C:\Users\12745\Desktop\线性代数\for.jpg)]
注意:在for语句执行的时候,表达式2,循环体语句和表达式3将重复执行,而表达式1只在进入循环之前执行一次。
讨论:
(1)表达式1:初值表达式,对循环变量赋值,从而指定循环的起点。如fahr=lower,置fahr的初值为温度取值范围的下限值lower,即循环从lower开始。
(2)表达式2:条件表达式,给出循环的条件,通常判断循环变量是否超过循环的终点。若该表达式为“真”,则继续循环;为“假”,则结束循环。如fahr<=upper,uppper作为温度取值范围的上限值,一旦fahr的值超过upper,表达式2为“假”,循环随之结束。
(3)表达式3:步长表达式,设置循环的步长,改表循环变量的值,从而可改变表达式2的结果。如fahr++,使fahr的值增加1,这样,最终fahr>upper,表达式2为“假”,循环随之结束.
(4)循环体语句:被反复执行的语句,只能是一条语句。
for语句反应了循环(重复执行)的规则,从哪儿开始(起点),到哪结束(终点),每次跨多大的步子(步长),重复做什么。
yn7-1673269602586)]
注意:在for语句执行的时候,表达式2,循环体语句和表达式3将重复执行,而表达式1只在进入循环之前执行一次。
讨论:
(1)表达式1:初值表达式,对循环变量赋值,从而指定循环的起点。如fahr=lower,置fahr的初值为温度取值范围的下限值lower,即循环从lower开始。
(2)表达式2:条件表达式,给出循环的条件,通常判断循环变量是否超过循环的终点。若该表达式为“真”,则继续循环;为“假”,则结束循环。如fahr<=upper,uppper作为温度取值范围的上限值,一旦fahr的值超过upper,表达式2为“假”,循环随之结束。
(3)表达式3:步长表达式,设置循环的步长,改表循环变量的值,从而可改变表达式2的结果。如fahr++,使fahr的值增加1,这样,最终fahr>upper,表达式2为“假”,循环随之结束.
(4)循环体语句:被反复执行的语句,只能是一条语句。
for语句反应了循环(重复执行)的规则,从哪儿开始(起点),到哪结束(终点),每次跨多大的步子(步长),重复做什么。