前言
都不知道有没有人在看。(悲)
经过之前的学习,我们知道了C语言的起源,C语言的基本结构以及一些基础知识。
本期我们会在此基础上向大家讲解14种运算符(主流使用)、格式以及字符的输入输出、数据类型转换,
以及最重要的三大结构:
- 顺序结构
- 选择结构
- 循环结构
那么接下来,就让我们继续以爬塔的方式,去开始学习C语言吧!
注:如果你是萌新小白,建议先查看格式及字符的输入输出。
Link Start!
目录
浮游塔第11层:算术、关系、复合赋值、自增自减运算符
算术运算符
最熟悉的运算符
在C语言所支持的14种运算符中,算术运算符绝对是我们最为熟悉的了,它的功能与数学中并无二异,依旧保持的乘除大于加减的等等运算规则。
算术运算符有以下几种:
+(加) -(减) *(乘) /(除) %(取余) ++(自增) --(自减)
表达式:由操作数和运算符组成的式子,如a-b,1+2。
注意:C语言中单一的一个变量或者单一的一个常量是最简单的表达式。
其中:
- /的运算结果的类型和除数、被除数中精度最高的数据类型一致。
- %的运算结果的符号与被除数的符号一致,并且参与该运算的两个数一定是整数。
- + - * /只要有一个运算对象是实型型,则表达式的值也为实型型。
关系运算符
表示二者关系的运算符
关系运算符:> < == >= <= !=
关系运算表达式的值为“真”或者“假”用“1”和“0”表示。
复合赋值运算符(=)
赋值运算符:=
赋值运算符结合性为由右向左结合,赋值运算符左值为变量,右边为变量或常量,且左右两边数据类型相同才能实现赋值。
注:式子左边一定是变量!
复合赋值运算符 | 示例 | 等价形式 | |
+= | X+=3 | X=x+3 | |
-= | X-=3 | X=x-3 | |
*= | X*=3 | X=x*3 | |
/= | X/=3 | X=x/3 | |
%= | X%=3 | X=x%3 | |
注意:以上复合赋值运算符都是单个运算符,看成一个整体。 |
自增自减运算符
(最难的运算符)
一个整数类型的变量自身加 1 可以这样写:
a = a + 1;或者a += 1;
不过,C语言还支持另外一种更加简洁的写法,就是:
a++;或者++a;
这种写法叫做自增,意思很明确,就是每次自身加 1。
相应的,既然有自增,当然也有自减,a--和--a,表示自身减 1。
自增自减完成后,会用新值替换旧值,将新值保存在当前变量中。++
和--
分别称为自增运算符和自减运算符,它们在循环结构中使用很频繁。
在自增自减运算中,最需要注意的就是符号的前后位置:
++ 在前面叫做前自增(例如 ++a),前自增先进行自增运算,再进行其他操作。
++ 在后面叫做后自增(例如 a++),后自增先进行其他操作,再进行自增运算。
自减(--)也一样,有前自减和后自减之分。
例如在下图的第三条输出语句中,先是输出的a和b的值,然后在进行后自增及后自减。
浮游塔第12层:逻辑、条件、逗号运算符
逻辑运算符(&& || !)
逻辑运算符和逻辑运算表达式:&&(逻辑与) ||(逻辑或) !(逻辑非)
逻辑运算表达式的值为“真”或者“假”用“1”和“0”表示。
参与运算的对象只要不为0,则运算对象为真。
在C语言中,一切非零的数都是真(1)。
&&(逻辑与)运算符:参与运算的对象都为真,结果才为真。
||(逻辑或)运算符:参与运算的对象只要有一个为真,结果就为真。
优先级:!(逻辑非)>&&(逻辑与)>||(逻辑或)
注意:&&(逻辑与)、||(逻辑或)两者都具有“短路”特性
条件运算符(? :)
条件运算符和条件运算表达式:(表达式1?表达式2:表达式3)
求值过程:如果表达式1的值为真,则以表达式2的值作为条件表达式的值,否则以表达式3的值作为条件表达式的值。
C语言中唯一的一个三目运算符
例子1:编程实现求任意三个整数中的最大值。
逗号运算符(,)
#include <stdio.h>
int main()
{
int a=2;
int b=(a++,a+2,9+1);
printf("y=%d\n",b);
return 0;
}
如果给你上述代码,你知道输出的b的值会是多少嘛?请好好思考一下。
3
2
1
答案是10。
逗号表达式的语法如下:
(表达式1,表达式2,表达式3,...)
逗号表达式中的这些表达式虽然都会与运行,但最终值是最后一个表达式的值,与其他表达式无关。
注:逗号运算符的优先级是最低的。
浮游塔第13层:按位运算
位运算的对象只能是整型或字符数据
按位与运算符(&)
按位与运算符“&”是双目运算符,其功能是参与运算的两数各对应的二进位相与。
参与运算的两个数均以补码出现
当参加运算的两个二进制数的对应位都为1,则该位的结果为1,否则为0。
例如:
0&0=0 0&1=0 1&0=0 1&1=1 3&5=1
用途:
清零、取一个数的指定位、判断奇偶
按位或运算符(|)
和按位与运算符相似。
当参加运算的两个二进制位中只要有一个1,则该位的结果为1,否则为0。
例如:
0|0=0 0|1=1 1|0=1 1|1=1
按位异或运算符(^)
异或运算只有在两个比较的位不同时其结果才是1,否则为0 .
例如: a=1,b=4
a的二进制为000000001,b的二进制为00000100
则a^b做异或操作的结果为00000101,即十进制的5.
例如: s=32
S^=32——>s=0
按位异或有以下性质:
- 1、交换律
- 2、结合律 (a^b)^c == a^(b^c)
- 3、对于任何数x,都有 x^x=0,x^0=x
- 4、自反性: a^b^b=a^0=a;
位取反运算符(~)
~按位取反的计算结论是:~n = -(n+1)
将原数二进制位的数值取反,是1则取0,是0则取1.
将整数用char类型定义:
char a=18,b; b=~a;
printf(“~a=%d”,b);
输出的结果为:-19
浮游塔第14层:左移、右移
左移<<(带符号)
定义:将一个运算对象的各二进制位全部左移若干位(左边的二进制位丢弃,右边补0)。
设 a=1010 1110,a = a<< 2 将a的二进制位左移2位、右补0,即得a=1011 1000。
若左移时舍弃的高位不包含1,则每左移一位,相当于该数乘以2。
<<左移的计算结论是:x<<n=x*(2^n)
例如:3<<2=16
右移>>(带符号)
定义:将一个数的各二进制位全部右移若干位,正数左补0,负数左补1,右边丢弃。
例如:a=a>>2 将a的二进制位右移2位,左补0 或者 左补1得看被移数是正还是负。
操作数每右移一位,相当于该数除以2。
>>右移的计算结论是:x>>n=x/(2^n)
例如:16>>2=4
以下这张出自菜鸟教程的图,会告诉我们这些运算的在运算过程中的先后顺序,以及运算时的结合性。
优先级从上至下,逐渐减弱。
浮游塔第15层:数据类型转换
数据类型转换分为两种:
自动数据类型转换(隐式转换):一般是将精度短的数据赋值给精度长的变量。
如:double d=10;
强制数据类型转换(显式转换):一般是将精度长的数据赋值给精度短的变量。
如:int a=(int)9.845;此时a的值为:9
不同类型的数据混合运算时为了保证运算的精度,计算机会自动转向精度高的数据类型进行。
例如:char一定会转换为int,float一定会转换为double。
语法:
(类型名)(表达式)
例:
#include <stdio.h>
int main()
{
int num1, num2,sum;
double mean;
printf("请输入两个数:");
scanf("%d,%d",&num1,&num2);
sum=num1+num2;
mean = (double) sum/2;
printf("他们的平均值是: %f\n", mean);
}
浮游塔第16层:格式输入、输出
当我们提到输入时,这意味着我们要向程序填充一些数据。
C 语言提供了一系列内置的函数,来读取给定的输入,并根据需要填充到程序中。
当我们提到输出时,这意味着要在屏幕上、打印机上或任意文件中显示一些数据。
C 语言也提供了一系列内置的函数,来输出数据到计算机屏幕上和保存数据到文本文件或二进制文件中。
格式输入函数scanf
原型:int scanf(const char *format,address-list)
功能:按格式字符串format从键盘读取数据,并列入地址列表address-list指定的存储单元。
返回值:成功返回输入数据的个数;错误返回0.
格式控制符中,有两类字符:
- 普通字符:按原样输入
- 格式字符:由%引导的格式字符串组成。
地址列表address-list中的地址,用取址符&加变量名的形式表示,指的是该变量所代表的内存空间的地址。
格式输出函数printf( )
原型:int printf(const char *format,arg-list)
功能:按照格式控制字符串format,将参数表arg-list中的参数输出到屏幕。
返回值:成功则返回实际打印的字符个数;错误则返回一个负数。
①格式控制字符串format:
- 格式说明:%[修饰符]格式字符,用于指定输出数据的格式。
- 控制部分:普通字符或转义字符
②参数列表arg-list:列出要输出的表达式
例子:
#include <stdio.h>
int main()
{
int a;//定义一个整形变量,用来保存数据。
scanf("%d",&a);//格式输入,从键盘接受一个字符保存在a当中
printf("%d\n",a);//格式输出,在屏幕上将a中的字符输出
return 0;
}
浮游塔第17层:字符输入、输出
字符输入、输出就是指输入字符和输出字符(大雾)
putchar()函数把字符输出到屏幕上,并返回相同的字符。
这个函数在同一个时间内只会输出一个单一的字符。您可以在循环内使用这个方法,以便在屏幕上输出多个字符。
getchar()函数从屏幕读取下一个可用的字符,并把它返回为一个整数。
这个函数在同一个时间内只会读取一个单一的字符。您可以在循环内使用这个方法,以便从屏幕上读取多个字符。
字符输入函数getchar( )
功能:该函数可以从键盘上接受一个字符,用于从终端读入字符。
字符输出函数putchar(参数)
功能:该函数可以将参数对应的字符输出到屏幕上。
例:
#include<stdio.h>
int main()
{
char ch;
printf("请输入字符:");
ch=getchar();
printf("该字符为:");
putchar(ch);
return 0;
}
浮游塔第18层:顺序结构
最基本的程序设计结构
顺序结构是程序中最简单最基本的流程控制,没有特定的而语法结构,更像是一种概念。
按它的字面来说,其中的程序就是按书写的先后顺序,依次执行的。
C语言程序的大多数代码都是这样执行的。
在顺序结构中常常会用到复合语句(compound statement)。
复合语句是由大括号{ }中的零个或多个声明和语句列表共同构成。
注意:
- 复合语句不以分号作为结束符,即最后的 } 后面不加分号。
- 在复合语句中可以定义变量,但仅在复合语句中有效,即作用域是{ }括起来的部分。
所谓作用域,就是该语句或者变量能有效使用的一个区间。
浮游塔第19层:选择结构
选择结构又称之为分支结构
选择结构是用判断给定的条件,
根据判断的结果判断某些条件,根据判断的结果来控制程序的流程。
其也有多种不同的结构。
一、if单分支选择结构
语法:
if(表达式) //此时的表达式可以是任意类型的表达式
{
语句体(或者代码块);
}
执行流程:
首先判断关系表达式看其结果是1还是0。
如果是1就执行语句体,如果是0就不执行语句体。
注意事项:
关系表达式无论简单还是复杂,结果必须是0或1(非0数据也行)。
if语句控制的语句如果是一条语句,大括号可以省略;如果是多条语句,就不能省略。
二、if双分支选择结构
语法:
if(表达式)
{
语句体1;
}
else
{
语句体2;
}
执行流程:
首先判断关系表达式看其结果是0还是1。
如果是1就执行语句体1(非0也执行),如果是0就执行语句体2。
三、if多分支选择结构
语法:
if(条件表达式1)
{
语句1;
}
else if(条件表达式2)
{
语句2;
}
else if(条件表达式3)
{
语句3;
}
……
else
{
语句n;
}
执行流程:
依次判断条件表达式的值,当某个值为真时,则执行相应的语句,然后跳出整个if语句之外,继续执行后面的程序。如果所有的表达式都为假,则执行语句n,然后继续执行后面的程序。
if嵌套
当if语句中的执行语句又是if语句时,则形成了if语句嵌套。
它也分为多种形式。
1:
if(表达式)
if(表达式)
语句1;
else
语句2;
else
语句3;
2:
if(表达式)
{
if(表达式)
语句1;
}
else
{
语句2;
}
3:
if(表达式)
{
语句1;
}
else
{
if(表达式)
语句2;
}
4:
if(表达式)
{
if(表达式)
{
语句1;
}
else
{
语句2;
}
}
else
{
if(表达式)
{
语句3;
}
else
{
语句4;
}
}
5:
if(表达式)
{
if(表达式)
{
语句1;
}
}
6:
if(表达式)
{
if(表达式)
{
语句1;
}
else
{
语句2;
}
}
注意:
if 和 else 的结合满足“就近原则”。
Switch选择结构(开关语句)
语法:
switch(表达式) //该表达式的值只能为:整数、字符、枚举类型数据
{
case 常量表达式1:语句1(集合);
case 常量表达式2:语句2(集合);
…
case 常量表达式n:语句n(集合);
default:语句n+1;
}
执行过程:
首先计算表达式的值,与常量表达式i进行比较。
如果与其中一个常量表达式i的值相等,就执行其后的语句直到遇到break语句才结束switch语句。
如果case后无break语句,则继续执行随后所有的case后的语句。
如果没有找到与表达式的值相匹配的常量表达式,则执行default后的语句n+1。
注意:
- switch后面括号中的表达式可以是整型、字符型和枚举类型。
- 在case后的各常量表达式的值不能相同 。
- 在case后,允许有多个语句,可以不用{ }括起来,而整个switch结构一定要有一对{}
- 各case和default语句的先后顺序可以改变,不影响程序执行结果。
- break语句在switch语句中起到结束的作用,一旦遇到,则跳出switch语句。
下面给大家用一个日常生活中非常实用的程序来展示一下这个结构。
#include<stdio.h>
int main(void)
{
int week=0;
printf("今天是星期几:");
scanf("%d",&week);
switch(week)
{
case 1:printf("今天是星期一\n"); break;
case 2:printf("今天是星期二\n"); break;
case 3:printf("今天是星期三\n"); break;
case 4:printf("今天是星期四\n"); break;
case 5:printf("今天是星期五\n"); break;
case 6:printf("今天是星期六\n"); break;
case 7:printf("今天是星期天\n"); break;
}
return 0;
}
浮游塔第20层:循环结构
三大结构中最为复杂的结构
循环结构,是指在程序中需要反复执行某个功能而设置的一种程序结构。
在循环结构中存在着三大要素,
循环变量
循环条件
循环体
C语言为我们提供了四种循环结构,while循环、do...while循环、for循环以及goto循环。
注:当前一般不推荐使用goto循环,因为它会使得程序的可读性和复杂性变得更差。
接下来,我会分别给各位介绍一下主流的三种循环结构。
一、while循环
while循环也称为当型循环,
其语法如下:
while(条件表达式)
循环体语句;
执行过程:
先判断后执行
进入while语句首先判断表达式是否为真,
当表达式的值为真(非0),便执行循环体语句,然后重复判断表达式的值,
为真便执行循环体语句,直到表达式为假(值为0)则循环结束。
简而言之就是,当条件满足,便进入循环体,条件不满足便结束循环。
注意事项:
①:循环体可以是空语句。例如,while((c=getche())!=’\n’);这个循环直到按回车键才结束。
②:可以有多层循环嵌套。
③:循环体语句可以是多条语句,此时必须用大括号把循环部分括起来。
④:该循环最少执行0次。
好了,循环的原理和注意事项都已经讲完了,
下面有道简单的编程问题,看看能不能试着做出来吧!
题目:求1+2+3+…+10之和
3
2
1
好了,解析如下:
#include<stdio.h>
int main()
{
//定义两个整型变量,i保存的是1~10的数,每次循环都会自增一次。
//sum保存每次的总和,必须要初始化为零,否则会出现错误。
int i=1,sum=0;
//条件表达式设为i<=10,因为此次所需的是1~10的和。
while(i<=10)
{
sum=sum+i; //原本的sum和(上一次的sum和)再加上当前循环时的i值,变成新的sum和。
i++; //i自增一次
}
printf("最终结果为:%d\n",sum); //输出结果
return 0;
}
二、do...while循环
其语法如下:
do{
循环体语句;
}while(循环条件表达式);
执行过程:
先执行循环体语句,再检查循环条件表达式的值是否成真,
如果为真则继续执行循环体语句,否则结束循环。
while循环与do..while循环的区分:
在初步学习循环的过程中,很多同志会将这两种循环搞混,下面讲解一下二者的不同之处。
while循环是先判断条件,再来看是否执行循环体,最少执行0次。
即:先判断,后执行。
do...while循环是先执行循环体,再判断条件是否成立,最少执行1次。
即:先执行,后判断。
在编写程序的时候,需要清楚的将其区分开来。
好了,下面依旧有道简单的编程题,试着做出来吧!
题目:求1000以内满足以下条件(该三位数的第1位和第3位是相等的)的三位正整数之和:
3
2
1
好了,解析如下:
#include<stdio.h>
int main( )
{
/*
定义两个变量,
虽然题目要求的是一千以内,但必须是三位数,所以初始值"i"为100,和"sum"初始化为0.
*/
int i=100,sum=0;
do
{
/*判断该三位数的百位和个位是否相等
该三位数除以一百便可得到百位的值
该三位数取10的余数便可得个位的值*/
if(i/100==i%10)
{
printf("%-4d",i); //为了方便检查,在此输出一下,每个数值之间的间隔是4d
sum=sum+i;//原本的sum加上新的i的值
}
i++; //在判断结束后,i自增一次
}while(i<1000);//循环条件:i<1000
printf("\n结果: sum=%d\n",sum); //输出结果
return 0;
}
三、for循环
语法:
for(表达式;表达式2;表达式3)
{
循环体语句;
}
执行过程:
先执行依次表达式1,判断表达式2的值是否为真,为真就执行循环体语句。
然后再执行表达式3,之后再判断表达式2的值是否为真...
循环次数:
for(i=m;i<n;i++)//循环次数:n-m次
for(i=m;i<=n;i++)//循环次数:n-m+1次
表达式:
表达式1(单次表达式):
也叫初始化表达式,设置初始条件,只执行一次,为0个或多个变量设置初值。
表达式2(条件表达式):
就是循环条件判断表达式,用于判定是否继续循环。
表达式3(条件更新表达式):
也属于循环体的一部分,每次for内的循环体执行完毕后都会执行该表达式,所以一般用于循环条件的更新。
三个表达式不是必须的,都可以省略,但中间的分号不可省略。
注意事项:
①for循环中循环体如果是多条语句,必须用“{}”括起来。
②for循环中的表达式1、表达式2和表达式3都是可选项,即可以缺省,但“;”不能省。
例如:
for(;;)语句 for(i=1;;i+=2)语句 for(j=5;;)语句;
③省略了表达式1,表示不对循环控制变量赋初值。
省略了表达式2,则表达循环条件始终为真,循环体中如果不做退出循环的处理则会成为死循环。
省略了表达式3,则不对循环控制变量进行操作,这时可在循环体语句中加入修改循环控制变量的语句。
④for循环可以有多层嵌套。
说到for循环,最经典的例题应该就是星号问题了。
题目:请打印出一下图形。
3
2
1
好了,解析如下:
#include<stdio.h>
int main()
{
int i,j; //i控制行数,j控制*号的个数
for(i=1; i<=5; i++)
{
for(j=1; j<=i; j++)
printf("*");
printf("\n");
}
return 0;
}
Break和continue(中断语句):
中断语句是指可以改变循环执行流程的语句。
break语句:在switch语句、循环结构中都可以使用,表示强制结束循环。
continue语句:只能在循环结构中使用,表示结束本次循环,立即执行下一次循环,在continue后的代码将不再执行。
例:计算100以内的偶数和
#include<stdio.h>
int main( )
{
int i=0,sum=0;
for(i=1;i<=100;i++)
{
if(i%2!=0)continue;
sum=sum+i;
}
printf("100以内的偶数和:%d\n",sum);
return 0;
}
循环嵌套:
在C语言中,if-else、while、do-while、for 都可以相互嵌套。
嵌套循环又叫多重循环,时一个循环内体又包含另一个完整的循环结构,即就是一条语句里面还有另一条语句。
例如 for 里面还有 for,while 里面还有 while,或者 for 里面有 while,while 里面有 if-else,这都是允许的。
while(循环条件1)
{
//循环操作1
for(循环条件2)
{
//循环操作2
do
{
//循环操作3
}while(循环条件3)
}
}
注意事项:
各种循环可以互相嵌套。
外层循环执行一次,内层循环都要执行。
下面用我们熟悉的99乘法表来举个例子:
#include<stdio.h>
int main(void)
{
int i=0,j=0;
for(i=1;i<=9;i++)
{
for(j=1;j<=i;j++)//变化的更快
{
printf("%d*%d=%d\t",j,i,i*j);
}
printf("\n");
}
return 0;
}
后记
呼,好了,这就是浮游塔第11至20层的内容,能如数看完并理解的话就代表你已经正式的开始学习C语言了,往后的内容会更加有难度,希望各位能够坚持下去。
下期的内容是数组的天下,预计在1~2天后发布,敬请期待。
(莫名发现写这个好累啊,上一期不过四千多字,这期就已经九千多了,希望有人,555。)
第③期链接:
[编程神域 C语言浮游塔 第③期]数组