目录
一、基础语法
位运算符:
& -(与运算)
| -(或运算)
^ -(异或运算)
~ -(取反运算)
<< -(左移运算符)
>> -(右移运算符)
运算符示例代码:
运算符小案例:
运算符优先级
类型转换:
控制语句:
程序执行的三大流程:
分支语句:
if语句:
if..else语句:
if…else if…else语句:
switch语句
分支综合案例:
循环语句:
while循环语句:
do...while循环语句:
for循环语句:
死循环:
循环案例:
一、基础语法
位运算符:
常见的位运算符号有&、|、^、~、>>、<<,分别代表着如下含义:
运算符 | 术语 | 示例 | 结果 |
& | 按位与运算 | 011 & 101 | 2个都为1才为1,结果为001 |
| | 按位或运算 | 011 | 101 | 有1个为1就为1,结果为111 |
^ | 按位异或运算 | 011 ^ 101 | 不同的为1,结果为110 |
~ | 取反运算 | ~011 | 100 |
<< | 左移运算 | 1010 << 1 | 10100 |
>> | 右移运算 | 1010 >> 1 | 0101 |
ps:取反、左右位移运算需要在补码的基础上运算。
& -(与运算)
按位与(&)运算:位与位进行比较,如果都为1,则为1,否则为0;
// 1. 按位与运算 &
/*
5 二进制 101
3 二进制 011
-------------
001
按位与运算结论:两个数位置相同的都为1,则为1,否则为0;
*/
printf("%d\n", 5 & 3); // 结果为1
| -(或运算)
按位或(|)运算:位与位进行比较,如果都为0,则为0,否则为1;
// 2. 按位或运算 |
/*
5 二进制 101
3 二进制 011
-------------
111
按位或运算结论:两个数位置相同的有一个为1,则为1,否则为0;
*/
printf("%d\n", 5 | 3); // 结果为7
^ -(异或运算)
按位异或运算:位与位进行比较,相同为0,不同为1;
// 3. 按位异或运算 ^
/*
5 二进制 101
3 二进制 011
-------------
110
按位异或运算结论:两个数位置相同的数不相同,则为1,否则为0;
*/
printf("%d\n", 5 ^ 3); // 结果为6
~ -(取反运算)
按位取反运算:补码取反,再将取反后的补码转为原码;
ps:无符号的数据,取反后最高位为1,也不需要逆运算。
// 4. 取反运算 ~
/*
5 二进制 101
010
011
110
取反结论:取反,再将取反后的补码转为原码;
注意:【使用的数据类型不一样得出的结果不一样】
*/
printf("%d\n", ~5); // 结果为-6
<< -(左移运算符)
将数字的二进制补码全部向左移动,空出来的位置补0,超出范围的二进制数丢弃;
有符号的数据左移后最高位如果为1,则需要进行逆运算;
注意事项:
- 无符号的数据,左移后最高位为1,也不需要逆运算;
- -128:1000 0000 特殊情况也不需要逆运算;
/**
* 示例:
* 40 << 4 = 0010 1000 << 4 = 1000 0000 = -128 (特殊的不需要逆运算)
* 41 << 4 = 0010 1001 << 4 = 1001 0000 = 1000 1111 = 1111 0000 = -112
* 7 6 5 4 3 2 1 0
* 1 0 0 1 0 0 0 0
*/
int8_t p = 40;
p <<= 4; // p = p << 4;
printf("40 << 4 = %d\n", p);
>> -(右移运算符)
将数字的二进制补码全部向右移动,空出来的位置补什么,取决于原来的最高位是什么。原来的最高是1就补1, 原来的最高位是0 就补0 。也可以转化成这样的一句话: 正数补0, 负数补1;
/*
23: 0001 0111【原码】 ---- 0001 0111【反码】 ---- 0001 0111 【补码】
>> 2
-----------------------------------------------
0000 0101【补码】 ---> 5
*/
printf(" 23 >> 2 = %d \n" , 23 >> 2) ;
/*
123: 1001 0111【原码】 ---- 1110 1000【反码】---- 1110 1001【补码】
>> 2
-----------------------------------------------
1111 1010【补码】 ---> 1111 1001【反码】- ----- 1000 0110 【原码】===> -6
*/
printf(" -23 >> 2 = %d \n" , -23 >> 2) ;
运算符示例代码:
#include <stdio.h>
#include <inttypes.h>
int main() {
uint8_t a = 3; // 0000 0011
uint8_t b = 10; // 0000 1010
// 打印显示2个字符,个数不够,左边补0
printf("%02x\n", a & b); // 0000 0010,16进制为02
printf("%02x\n", a | b); // 0000 1011,16进制为0b
printf("%02x\n", a ^ b); // 0000 1001,16进制为09
uint8_t c = 10; // 0000 1010
uint8_t temp = ~c; // 1111 0101
printf("%02x\n", temp); // 1111 0101,16进制为f5
printf("%02x\n", c << 1); // 0001 0100,16进制为14
printf("%02x\n", c >> 1); // 0000 0101,16进制为05
return 0;
}
运算符小案例:
#include <stdio.h>
#include <inttypes.h>
int main()
{
/*
置1:
用按位或运算(|)或者左移(<<)
按位或运算结论:两个数有一个为1 则为1
*/
// 1. 将变量a的第2位设置为1,其他位保持不变
// 使用或运算,两个数有一个为1 则为1
// 0b10110011 0xb3
// 0b00000100 0x4
// 0b10110111 0xb7
uint8_t a = 0b10110011;
printf("结果为:%#x\n", a | 0x4);
// printf("%d\n", (1 << 2)); // 4 二进制 100 0b00000100
printf("结果为:%#x\n", a | (1 << 2));
// 2. 将变量b的第2位、第6位设置为1,其他位保持不变
// 使用或运算,两个数有一个为1 则为1
// 0b10110011 0xb3
// 0b01000100 0x44
// 0b11110111 0xf7
uint8_t b = 0b10110011;
printf("结果为:%#x\n", b | 0x44);
// 根据这个0b01000100所知 先左移两位 再左移六位
// printf("%d\n", (1 << 2)); // 4 二进制 100 0b00000100
// printf("%d\n", (1 << 6)); // 64 二进制 1000000 0b01000000
// 以上两个结合 就是0b01000100
printf("%#x\n", b | (1 << 2 | 1 << 6));
/*
置0:
按位与运算(&)或者左移取反(~<<)
按位与运算结论:两个数位置相同的都为1,则为1,否则为0;
*/
// 3. 将变量c的第5位设置为0,其他位保持不变
uint8_t c = 0b10110011;
// 0b10110011 0xb3
// 0b11011111 0xdf
// 0b10010011 0x93
printf("%#x\n", c & 0b11011111);
printf("结果为:%#x\n", c & 0xdf);
printf("%d\n", ~(1 << 5));
printf("%#x\n", c & ~(1 << 5));
// 4. 将变量d的第0~3位设置为0,其他位保持不变
/* 区间:
就用 左移+ 按位(|)运算并取反(~) */
uint8_t d = 0xff; // 0xff;
// 1111 1111 // 0xff
// 1111 0000 // 0xf0
// 1111 0000 // 0xf0
printf("%#x\n", d & 0xf0);
printf("%#x\n", d & ~(1 << 0 | 1 << 1 | 1 << 2 | 1 << 3));
// 5. 将变量e的第2位取反,其他位保持不变
uint8_t e = 0b10110011; // 0xb3;
// 0b10110011 0xb3
// 0b00000100 0x4
// 0b10110111 0xb7
printf("%#x\n", e ^ 0b00000100);
printf("%#x\n", e ^ 0x4);
printf("%#x\n", e ^ (1 << 2));
// 6. 将变量f取出8-15位
uint32_t f = 0x12345678;
// 变量f为十六进制 代表一个32位的二进制 1对4 4*8=32
// 0000 0000 0000 0000 0000 0000 0000 0000 代表0x12345678
// 0000 0000 0000 0000 1111 1111 0000 0000 代表想要取出的位数
// 在十六进制中 1111对应f
// 0000 0000 0000 0000 f f 0000 0000
printf("%#x\n", (f & 0x0000ff00) >> 8);
return 0;
}
运算符优先级
- 不同的运算符默认具备不同的优先级,符号较多不用记,现用现查就可以。
- 当无法确定谁的优先级高时,加一个小括号就解决了。
类型转换:
数据有不同的类型,不同类型数据之间进行混合运算时涉及到类型的转换问题。
- 转换的方法有两种:
-
- 自动转换(隐式转换):遵循一定的规则,由编译系统自动完成
- 强制类型转换:把表达式的运算结果强制转换成所需的数据类型
-
-
- 语法格式: (类型)变量或常量
-
- 类型转换的原则:
-
- 占用内存字节数少(值域小)的类型,向占用内存字节数多(值域大)的类型转换,以保证精度不降低。
#include <stdio.h>
int main()
{
// 类型转换的原则:占用内存字节数少(值域小)的类型,向占用内存字节数多(值域大)的类型转换,以保证精度不降低。
char a = 129;
printf("%d\n", a); // 隐式转换
int b = 129;
char c = (char)b; // 强制转换
printf("%d\n", c);
return 0;
}
控制语句:
程序执行的三大流程:
- 顺序 : 从上向下, 顺序执行代码
- 分支 : 根据条件判断, 决定执行代码的分支
- 循环 : 让特定代码重复的执行
分支语句:
条件语句用来根据不同的条件来执行不同的语句,C语言中常用的条件语句包括if语句和switch语句。
if语句:
语法格式:
if (条件) {
条件成立时,要做的事
……
}
案例:
#include <stdio.h>
int main() {
// 根据条件 去执行某些代码
int salary = 181818;
if (salary > 100000)
{
printf("买保时捷");
/* code */
}
return 0;
}
if..else语句:
基础语法:
语法格式:
if (条件) {
条件成立时,要做的事
……
} else {
条件不成立时,要做的事
……
}
案例:
#include <stdio.h>
int main() {
// if 条件不成立 执行else 代码
int salary = 888888;
if (salary > 3000) {
printf("买保时捷\n");
}
else
{
printf("回家睡觉\n");
}
return 0;
}
三元运算符:
运算符 | 术语 | 示例 | 结果 |
?: | 三目运算符 | a>b?a:b; | 如果a>b,整体为结果a,否则整体结果为b |
语法格式:
条件表达式?条件成立:条件不成立
案例:
#include <stdio.h>
int main() {
// 通过三目运算符求2个数的最大值
int a = 10;
int b = 20;
int c = a > b ? a : b;
printf("最大值:%d\n", c);
return 0;
}
if…else if…else语句:
语法格式:
if (条件1) {
条件1成立时,要做的事
……
} else if(条件2) {
条件2成立时,要做的事
……
} else {
条件不成立时,要做的事
……
}
案例:
#include <stdio.h>
int main()
{
// 3. 从屏幕上输入一个学生的成绩(0 - 100),对学生成绩进行评定:
// < 60为E
// 60~69为D
// 70~79为C
// 80~89为B
// 90以上为A
// < 0或>100提示成绩输入出错
// 1. 定义变量接收学校输入的成绩
int score;
printf("请输入学生的成绩!\n");
scanf("%d", &score);
if (score < 60)
{
printf("E\n");
}
else if (score >= 90 && score <= 100)
{
printf("A\n");
}
else if (score >= 80 && score < 90)
{
printf("B\n");
}
else if (score >= 70 && score < 80)
{
printf("C\n");
}
else if (score >= 60 && score < 70)
{
printf("D\n");
}
else if (score < 0 || score > 100)
{
printf("成绩输入出错\n");
}
return 0;
}
switch语句
- 测试一个表达式是否等于一些可能的值,并根据表达式的值执行相应的代码块,可以使用switch语言实现
- switch可以支持数据类型:
-
- int
- 枚举类型
- char类型
- switch和if区别:
-
- 需要根据布尔条件来执行不同的代码块,则应使用if语句
- 需要根据表达式的值来执行不同的代码块,则应使用switch语句
语法格式:
switch (expression) {
case value1:
// 代码块1
break;
case value2:
// 代码块2
break;
default:
// 代码块3
}
案例:
#include <stdio.h>
int main() {
// ○ 输入1:输出Monday
// ○ 输入2:输出Tuesday
// ○ 输入3:输出Wednesday
// ○ 输入4:输出Thursday
// ○ 输入5:输出Friday
// ○ 输入6:输出Saturday
// ○ 输入7:输出Sunday
// ○ 输入其它:输出error
printf("请输入对应的数字1-7:");
int num;
scanf("%d", &num);
switch (num)
{
case 1:
printf("Monday\n");
break;
case 2:
printf("Tuesday\n");
break;
case 3:
printf("Wednesday\n");
break;
case 4:
printf("Thursday\n");
break;
case 5:
printf("Friday\n");
break;
case 6:
printf("Saturday\n");
break;
case 7:
printf("Sunday\n");
break;
default:
break;
}
return 0;
}
分支综合案例:
#include <stdio.h>
// 1.定义变量保存年份、月份、天数
// 2.输入年份和月份
// 3.根据月份输出天数
// 1、3、5、7、8、10、12月 31天
// 4、6、9、11月 30天
// 2月 非闰年 28天 闰年 29天
// 闰年判断:能被4整除,但不能被100整除的;或者能被400整除的年份
int main() {
int year, month, day;
printf("请输入年月");
scanf("%d %d", &year, &month);
switch (month)
{
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
day = 31;
break;
case 4:
case 6:
case 9:
case 11:
day = 30;
break;
case 2:
if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) {
day = 29;
}
else {
day = 28;
}
default:
break;
}
printf("年=%d 月= %d 天数=%d\n", year, month, day);
return 0;
}
循环语句:
- 什么是循环
-
- 重复执行代码
- 为什么需要循环
- 循环的实现方式
-
- while
- do...while
- for
while循环语句:
语法格式:
while (条件) {
循环体
……
}
案例:
#include <stdio.h>
int main() {
// 需求跑步5圈
// 1. 条件变量的定义
int i = 1;
// 2. while 控制重复的次数
while (i <= 5) {
// 3. 打印跑步第几圈
printf("跑步第 %d 圈\n", i);
// 4. 条件改变
i++;
}
return 0;
}
do...while循环语句:
语法格式:
do {
循环体
……
} while (条件);
- do-while 循环语句是在执行循环体之后才检查 条件 表达式的值
- 所以 do-while 语句的循环体至少执行一次,do…while也被称为直到型循环
案例:
#include <stdio.h>
int main() {
// 需求跑步5圈
// 1. 条件变量的定义
int i = 1;
do {
// 2.1 打印跑步第几圈
printf("跑步第 %d 圈\n", i);
// 2.2 条件改变
i++;
} while ( i <= 5 ); // 3. 控制重复的次数
return 0;
}
for循环语句:
语法格式:
for ( init; condition; increment ) {
循环体
}
- init会首先被执行,且只会执行一次
- 接下来,会判断 condition,如果条件condition为真
- 在执行完 for 循环主体后,控制流会跳回上面的 increment 语句
- 条件再次被判断
案例:
#include <stdio.h>
int main() {
// 需求跑步5圈
for (int i = 1; i <= 5; i++) {
printf("跑步第 %d 圈\n", i);
}
return 0;
}
死循环:
- 条件永远为真的循环就是死循环
示例代码:
#include <stdio.h>
int main() {
// while (1) {
// printf("根本停不下来\n");
// }
for(;;) {
printf("根本停不下来\n");
}
return 0;
}
循环案例:
1. 实现1+2+3……100所有数字的累加
案例:
#include <stdio.h>
int main() {
// 需求:实现1+2+3……100所有数字的累加
// 定义条件变量初始值为1
int i = 1;
// 定义累加变量,初始值为0
int sum = 0;
// 循环控制100次
while (i <= 100) {
// 累加
sum += i;
// 条件改变
i++;
}
// 循环外面,打印最终的累加和
printf("sum = %d\n", sum);
// for循环实现
int temp = 0;
for (int i = 1; i <= 100; i++) {
temp += i;
}
printf("temp = %d\n", temp);
return 0;
}
2. 循环嵌套
需求如下:
通过for循环嵌套打印内容:
* * * * *
* * * * *
* * * * *
* * * * *
* * * * *
说明:
1)每行有5个*,总共有5行
2)*之间有空格隔开
3)printf()1次只能打印1个*
代码实现:
#include <stdio.h>
int main() {
for (int i = 0; i <= 4; i++) {
for (int j = 0; j <= 4; j++) {
printf("* ");
}
printf("\n");
}
return 0;
}