------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------
一、基本运算
1.算数运算
基本运算包括加、减、乘、除、取余运算,下面我们通过代码来感受一下:
<span style="font-size:14px;">int main()下面是输出结果。
{
// 1.算数运算符的基本使用
int a = 10 + 1 + 2 - 3 + 5;
printf("a=%d\n", a);
int b = -10;
int c = 10 * b;
printf("c=%d\n", c);
// 整数除以整数,结果还是整数
float d = 10 / 3;
printf("d=%.2f\n", d);
// 取余运算(模运算)
// %两边必须都是整数
// %取余结果的正负性只跟%左边的数值有关
int e = 10 % -3;
printf("e=%d\n", e);
return 0;
}</span>
注意d的结果,说明10/3的结果只能精确到个数为,与d的类型无关,d的float类型只是把得出的结果3转成了float类型的3.00。
tips:关于运算顺序
int b = 6 /3 *2; 这个式子是先算乘法还是除法呢? 别犯懒了,自己敲一下,看看结果不就知道了!!!2.强制类型转换
那么,我们如何得到精确的除法计算结果呢? 在做运算之前,我们可以用强制类型转换把被除数或除数转换成小数。具体方法如下:#include <stdio.h>这样就得到了我们想要的答案:
int main()
{
// 把10强制类型转换为float类型
float d1 = (float)10 / 3;
printf("d1=%.2f\n", d1);
// 把3强制类型转换为float类型
float d2 = 10 / (float)3;
printf("d2=%.2f\n", d2);
return 0;
}
做两到练习题来感受一下算数运算的应用吧:
1.下面的横线中填什么运算符,就可以保证无论a取什么值,b的值都小于10?
int a =987654321;
int b = a _10;
答案是:
int b = a % 10; //a除以10的所得的余数一定比10小3.赋值运算、自增自减运算
#include <stdio.h>
int main()
{
// 1-赋值运算------------------------------------------------
// 这一句其实是两句,int a; a = 5;
int a = 5;
// 这个等式看似不成立,但这里的等号不是相等的意思,是赋值的意思
// a的值+5以后再重新赋值给自己
a = a + 5; //这句过后 a =5+5=10
printf("a=%d\n", a);
// 2-复合赋值运算---------------------------------------------
int b = 1;
b += 5; // 相当于 b = b + 5; 这句过后 b=1+5=6
b -= 2; // 相当于 b = b - 2; 这局过后 b=6-2=4
printf("b=%d\n", b);
// 3-自增自减运算---------------------------------------------
// a++ 和 ++a 都相当于 a = a + 1; 他们的差别是,a++的赋值效果在下一次调用a时才生效,++a的赋值效果立即生效
// 下面的代码可以直观的看出 ++a 和 a++ 的区别
int c = 1;
printf("c++时,c=%d\n", c++); // c = c + 1 ,c的新值下次生效,本次c的值仍然是1
printf("c++以后,c=%d\n", c);
int d = 1;
printf("++d时,d=%d\n", ++d); // d = d + 1 ,d的新值立即生效,本次d的值是2
printf("++d以后,d=%d\n", d);
// a-- 、 --a 和 a++ 、++a是一个道理,别犯懒了,自己敲代码试一下吧!!!
return 0;
}
上面代码的执行结果如下:
4.sizeof的用法
#include <stdio.h>
int main()
{
// sizeof的用法
int size1 = sizeof(10.3);
int size2 = sizeof 10.7;
printf("10.3在内存中占%d个字节\n", size1);
printf("10.7在内存中占%d个字节\n", size2);
int a = 10;
int size3 = sizeof(a);
int size4 = sizeof a;
printf("a在内存中占%d个字节\n", size3);
printf(“a在占内存中%d个字节\n", size4);
int size5 = sizeof(char);
printf("char数据类型在内存中占%d个字节\n", size5);
// 下面这个写法是错误的,数据类型作为sizeof的参数必须加括号
// int size = sizeof char;
return 0;
}
上面代码的运行结果如下:
5.关系运算
#include <stdio.h>
int main()
{
// 关系运算符有:大于、大于等于、小于、小于等于、等于、不等于
// > >= < <= == !==
// 关系运算只有两种运算结果:
// 1.条件成立就返回1,真
// 2.条件不成立就返回0,假
int a = 10;
int b = 11;
int result1 = b >= a + 2;
printf(“result=%d\n", result1);
// 算数运算符的优先级高于关系运算 int c = 2 != 4 + 4 * 7 > 30 == 1; printf(“c=%d\n", c); return 0;}
运行结果为:
tips:
看到类似 4 * 7 != 28 - 3 == 5 + 7 > 8 这样的式子是不是很恼人?
本篇末尾会提供运算符优先级顺序列表,但其实你根本不必被那烦人的表格,记不准的时候写个式子测试一下结果就ok了。
我认为实际编程中没有人会这样写式子的,为了可读性,大家会默默的加上小括号。
6.逻辑运算
逻辑运算有三种:逻辑与、逻辑或、逻辑非
1)逻辑与
#include <stdio.h>运行结果如下:
int main()
{
// 1.逻辑与 格式:条件1 && 条件2
// && 两边都为真时,结果为1,否则为0
int a, b, c;
a = 10>3 && 7<6;
printf("a=%d\n", a);
b = 100 && 0;
printf("a=%d\n", b);
a = 10;
b = 10;
// 一旦&&左边不成立,直接判断最终结果为0,就不会继续判断&&右边的语句了
c = (a<5) && (++b>=11);
// 由于&&右边的语句没有被执行,所以b的值仍然是10而不是11
printf("a=%d, b=%d, c=%d\n", a, b, c);
return 0;
}
2)逻辑或
#include <stdio.h>
int main()
{
// 逻辑或 条件1 || 条件2
// ||左右的两个条件只要有一个成立(为真),结果即为真,否则结果为假
int a = 100;
int b = 0 || a;
int c = 10;
int d = 10;
int e = (c<5) || (d++ - 10);
printf("b=%d, d=%d, e=%d\n", b, d, e);
return 0;
}
运行结果说明第12行中逻辑或运算符右边的d++被执行了。
3)逻辑非
int main()
{
// 逻辑非 格式:!条件
// 如果条件成立,就返回0;如果条件不成立,就返回1
int a = !(10>8);
// -10不等于0,所以 -10=真,!-10 = !真 = 假 = 0
int b = !-10;
// 逻辑非的优先级大于逻辑运算符
int c = !10>8;
int d = !!10;
printf("a=%d\n", a);
printf("b=%d\n", b);
printf("c=%d\n", c);
printf("d=%d\n", d);
return 0;
}
运行结果如下:
7.三目运算
三目运算又称三元运算,即需要三个操作数(一个条件,两个数值)来参与运算。 三目运算的用法如下:int main()
{
// 三目运算符 格式:条件 ? 数值1 : 数值2
// 如果条件成立,返回数值1,否则返回数值2
// int x = !3 ? 8 : 9 // 这样用是可以的
// 计算3个整数之间的最大值 int a = 10; int b = 999; int c = 1000; // 求出a、b的最大值 int abMax = (a > b) ? a : b; // 求出abMax和c的最大值 int abcMax = (abMax > c) ? abMax : c; // 这一句和上面是等效的,但是可读性太差了,不推荐这样写。 // int abcMax = (((a > b) ? a : b) > c) ? ((a > b) ? a : b) : c; printf("最大的数是%d\n", abcMax); return 0;}运行结果为:
tips:
一下子学了这么多种运算符,对于他们运算优先级排序是不是有点头大呢? 分不清的时候查下表格或写几行代码验证一下,计算机是不会记错的。 以后用多了自然就记住了,不必在这上面太过纠结。运算符优先级顺序表:
优先级 (从高到低) |
描述 |
运算符 |
1 |
括号 |
()、[] |
2 |
正负号 |
+、- |
3 |
自增自减,非 |
++、--、! |
4 |
乘除,取余 |
*、/、% |
5 |
加减 |
+、- |
6 |
移位运算 |
<<、>>、>>> |
7 |
大小关系 |
>、>=、<、<= |
8 |
相等关系 |
==、!= |
9 |
按位与 |
& |
10 |
按位异或 |
^ |
11 |
按位或 |
| |
12 |
逻辑与 |
&& |
13 |
逻辑或 |
|| |
14 |
条件运算 |
?: |
15 |
赋值运算 |
=、+=、-=、*=、/=、%= |
16 |
位赋值运算 |
&=、|=、<<=、>>=、>>>= |
二、流程控制
1.选择结构
默认情况下,计算机只会傻傻的按顺序从前向后执行我们的代码,这被称为顺序结构。 但当我们需要因某些条件而触发某个功能时,就需要用到一种新的结构——选择结构。1)if条件 我们先来看一下下面的代码示例,注意看注释。
#include <stdio.h>
int main()
{
int a = 10;
// 如果条件1成立,执行这个代码块内的语句,后面的else if以及else代码块都不再执行;
// 如果条件1不成立,则进入下一个条件判断
if (a>9) // 条件1
{
printf("a大于9\n");
// 其他你想要执行的语句……
// 你甚至可以在if中嵌套一个if
if (a==10)
{
printf("程序进入了if中嵌套的if代码段\n");
}
}
// 如果条件2成立,执行这个代码块内的语句,后面的else if以及else代码块都不再执行;
// 如果条件2不成立,则进入下一个条件判断
else if (a>8) // 条件2
{
printf("a大于8\n");
}
// 如果条件3成立,执行这个代码块内的语句,后面的else if以及else代码块都不再执行;
// 如果条件3不成立,则进入下一个条件判断
else if (a>7) // 条件3
{
printf("a大于7\n");
}
// 条件1、2、3都不成立时,才执行这个代码块内的语句
else // 这里不需要写条件,只要else之前的条件都不满足,就会进入else代码块
{
printf("能来到这里,a一定小于或等于7\n");
}
return 0;
}
if条件判断有三种关键字:if 、else if 、else ,从字面上大概可以猜出,他们是互斥的,简单说就是他们其中只有一个可以被执行。上面代码的执行结果也证明了这一点。
如果多个同级的(不发生相互嵌套的)if按顺序排列下来,如果条件满足,他们都可以被执行。我把之前的代码稍微做了修改,把else if 中的else都删掉了,看看结果有什么不同。
#include <stdio.h>
int main()
{
int a = 10;
// 如果条件1成立,执行这个代码块内的语句,后面的else if以及else代码块都不再执行;
// 如果条件1不成立,则进入下一个条件判断
if (a>9) // 条件1
{
printf("a大于9\n");
// 其他你想要执行的语句……
// 你甚至可以在if中嵌套一个if
if (a==10)
{
printf("程序进入了if中嵌套的if代码段\n");
}
}
// 如果条件2成立,执行这个代码块内的语句,后面的else if以及else代码块都不再执行;
// 如果条件2不成立,则进入下一个条件判断
if (a>8) // 条件2
{
printf("a大于8\n");
}
// 如果条件3成立,执行这个代码块内的语句,后面的else if以及else代码块都不再执行;
// 如果条件3不成立,则进入下一个条件判断
if (a>7) // 条件3
{
printf("a大于7\n");
}
// 条件1、2、3都不成立时,才执行这个代码块内的语句
else // 这里不需要写条件,只要else之前的条件都不满足,就会进入else代码块
{
printf("能来到这里,a一定小于或等于7\n");
}
return 0;
}
if的使用注意:
如果jf后面不写大括号,if的条件成立与否只决定if条件后第一条语句是否被执行,后面的其他语句按顺序照常执行
在if条件后面定义变量需要注意:
// 下面的代码是错误的:作用域不明确
if (10 > 6)
int a = 5;
// 如果要在if后面的语句中定义新的变量,必须用大括号{}扩住变量
tips:
我们尽可能的用else if而不是多个if并列。当使用多个else if并列时 ,如果有一个条件成立,系统就不会再判断后面的条件,这样可以提高程序的运行效率。2)switch
#include <stdio.h>
int main()
{
// 前面case中的值都不等于switch中的值时,进入default代码块
// break:退出整个switch语句
// 如果case后面没有break,就会执行后面所有case中的语句,直到遇到break为止
int b = 10;
switch (b)
{
case 10:
printf("A\n");
b++;
// break;
case 5:
printf("B\n");
b++;
// break;
case 0:
printf("C\n");
b++;
// break;
default:
printf("D\n");
b++;
break;
}
printf("b的值是%d\n", b);
return 0;
}
3)if 和 switch 的区别
1>if 能完成的功能,switch 并不一定能完成。
2>有些情况下,if 与 swith 可以互换。
3>switch 能做的功能,if 都可以做。
2.循环结构
有些时候我们需要程序重复执行一段代码,如果我们用拷贝粘贴的方式实现,一旦有一天代码需要更改,所有你拷贝过得代码都需要改。有没有更高大上的方法呢?我们可以用循环结构来解决这种问题。1)while 循环
格式如下:
while (条件)
{
循环体
// continue; //结束当前的循环体,进入下一次循环体的执行
// break; //直接结束整个while循环
}
运行原理
1.如果一开始条件就不成立,永远不会执行循环体
2.如果条件成立,就会执行一次循环体,执行完毕,再次判断条件是否成立......
3.看是否有其他条件可能会用到continue、break、或嵌套选择结构、循环结构
下面我来拟一个需求,用while循环实现这个需求。
小明做俯卧撑,最多能做50个,每做一次他就数一次“我做了XX个俯卧撑”,每做到10的倍数,他就默念,不喊出声音。今天他状态不佳,做到第33个就累趴下了。
#include <stdio.h>
int main()
{
// 1.先确定需要重复执行的操作:输出做了几次俯卧撑
// 2.再确定约束条件:最多做50个俯卧撑
// 3.其他条件:每到10得倍数时,不输出字符串
// 做到第33个时,累趴下了 =。=
// 定义一个变量记录做的次数
int count = 0;
while (count<=50)
{
++count;
if (count%10 == 0)
{
// 直接结束这一次循环体,进入下一次循环
continue;
}
printf("我做了%d个俯卧撑\n", count);
// 今天状态不好,只做了33个 =.=
if (count==33)
{
printf("尼玛,我累趴下了 =。=\n");
break;
}
}
return 0;
}
这是输出结果,太长了,所以我截屏了最后的部分。
2)do while 循环
do while和while的用法几乎一样,唯一的区别是do while至少会执行一次循环体,执行一次后再开始判断条件是否成立。
do while (条件)
{
循环体
// continue; // 结束当前的循环体,进入下一次循环体的执行
// break; // 直接结束整个while循环
}
3)for 循环
for ( 语句1;条件 ;语句2){ 循环体 continue; //结束本次循环体,进入下次循环体 break; //结束整个循环
} 语句1:初始化语句(只在整个for循环开始时执行一次)语句2:增量语句(每次循环体执行后,执行一次该语句)
执行过程:初始化语句—>条件成立—>循环体—>增量语句—>条件成立—>循环体—>增量语句—>……
我们再让小明用for循环做一次俯卧撑吧 =。=
#include <stdio.h>
int main()
{
for (int count = 1; count <= 50; count++)
{
if (count%10 == 0)
{
// 直接结束这一次循环体,进入下一次循环
continue;
}
printf("我做了%d个俯卧撑\n", count);
if (count==33)
{
printf("尼玛,我累趴下了 =。=\n");
break;
}
}
运行结果是一样的,这里我就偷个懒,不截图了。
tips:
for的一些使用注意:#include <stdio.h>
int main()
{
/* 不要随便在for()后面写分号,写分号相当于for循环体是一个空语句
for (int i=0; i<5; i++);
{
printf("哈哈\n");
}*/
/* 错误:变量a的作用域不明确
如果要在循环体中定义新的变量,必须用大括号{}包住
for (int i=0; i<5; i++)
int a = 10;
*/
// 最简单的利用for循环实现死循环
// for(;;);
return 0;
}
三.函数
1.什么情况下定义函数:
当我们需要重复执行某一个功能时,我们就可以把用以支持这个功能的代码块封装到一个函数中,每次需要执行这个功能时,只要调用对应的函数就可以了。
printf 其实就是系统帮我们封装好的一个函数。
2.函数的定义格式
返回值类型 函数名(形式参数列表)
{
函数体
}
3.定义函数需要明确的东西
1>起一个有意义的函数名
2>返回值类型
3>需要传什么参数进来
#include <stdio.h>
int average(int num1, int num2)
{
return (num1 + num2)/2;
}
int main()
{
int a = 10;
int b = 8;
int c = average(a, b);
printf("c is %d\n", c);
int a1 = 11;
int b1 = 20;
int c1 = average(a1, b1);
printf("c1 is %d\n", c1);
return 0;
}
4.函数的注意点
1.默认情况下,不允许有函数的名称一样
2.函数不能嵌套定义
3.函数不能重复定义,但是可以重复声明
4.如果有函数的声明,没有函数的定义
1>编译可以通过,因为编译器只会检测语法合不合理,并不会检测函数有没有定义
2>链接报错,因为链接的时候会检测函数是否定义
四、多人团队开发文件结构
第三章的函数除了可以封装代码外,还有提高团队开发效率的作用。比如在一个项目中,李四负责写main函数,张三的数学很好,负责写计算用的函数,李四和张三可以把他们的代码写在两个文件中,最后在一起完成连接就可以了。
但李四的main函数中并没有张三函数的定义,如果李四直接调用张三的函数,编译时是会警告的:
其实,函数不但有定义,还有声明,只要在main函数所在的文件中声明要调用的函数,编译器就认为我们有这个函数,也就不会警告。
函数的声明格式:返回值类型 函数名(形参); //注意最后要写上分号
但张三可能写了很多个计算用的函数,没次有改动,李四都要去重新拷贝一份声明过来,很麻烦,也容易出错。
张三想了一个办法,把所有的函数声明写在一个被称作”头文件”的文件中(后缀是.h),这样李四只要在它的文件头部写上这一句: #include “zhangsan.h”,就ok了。
这是我用多文件完成的一个求平均数的简单程序:
tips:
用 #include 包含文件时,如果是自己写的头文件,要用 ” “ 括住,只有系统自带的头文件才用< >括住多个.c文件一起编译连接时,终端指令可以在每个文件前打个空格
小结:
1.注意运算符直接的优先级,记不清时写两句简单的代码验证一下 2.a++ 与 ++a是有区别的,前者累加效果下次生效,后者即时生效 3.如果逻辑与的第一个条件不成立,第二个条件中的语句根本不会被执行 4.选择结构 if ,连续写多个if会一次判定其条件;if后连续写else if,只会执行第一个满足条件的代码块。 5.注意break、default在case中的用法,注意continue、break在循环结构中得用法To be continue……