一、操作符(运算符)
(一)算术操作符(双目操作符)
这些操作符都是双目操作符,前后有两个操作数,如2+3中,2和3是+的左右操作数。
+ | - | * | / | % |
---|---|---|---|---|
加 | 减 | 乘 | 除 | 取模(取余) |
- 算术运算符包含+、-、*、/和%。
- 当一个表达式中同时出现这5种运算符时,先进行乘(*)、除(/)、取余(%),取余也称取模,后进行加(+)、减(-),也就是乘、除、取余运算符的优先级高于加、减运算符。
- 除%运算符外,其余几种运算符既适用于浮点型数又适用于整型数。
- 当操作符/的两个操作数都是整型数时,它执行整除运算,在其他情况下执行浮点型数除法。如两个运算符之前任意为浮点数,就会进行浮点数除法。
- %为取模运算符,它接收两个整型操作数,将左操作数除以右操作数,但它的返回值是余数而不是商。
- 由算术运算符组成的式子称为算术表达式,表达式一定有一个值。
- %只用于整数,不能用在浮点数。负数求模的规则是:结果的正负号是由第一个运算数决定的。如-11%-5 结果是-1。
#include <stdio.h>
int main()
{
int a = 2 * 3 + 4 - 5 / 3 + 4 % 2;
printf("%d\n", a);//结果为9
return 0;
}
(二)关系运算符
> | < | == | >= | <= | != |
---|---|---|---|---|---|
大于 | 小于 | 是否等于 | 大于等于 | 小于等于 | 不等于 |
- 关系表达式的值只有真(非零)和假(0);
- 关系表达式的值 优先级 小于算术表达式;
【注】
(1)在判断整型变量i是否等于3时,可写为3 == i,常量在前,变量在后。
(2)在判断三个数是否相等时,绝对不可以写成if(X == X ==X),这种写法无论何时都为假。
#include <stdio.h>
int main()
{
//若写为下列表达式,前两个的5 == 5,得到5等于5,结果为真,即为1
if(5==5==5)//而1不等于5,结果为假(0)
{
printf("equal");
}
return 0;
}
#include <stdio.h>
int main()
{
int a = 5;
int b = 5;
int c = 5;
if (a==b==c)//同理
{
printf("equal\n");
}
else
{
printf("no equal\n");
}
return 0;
}
正确写法
#include <stdio.h>
int main()
{
if(5==5 && 5==5)//此处注意if后侧不要使用分号
{
printf("equal");//输出结果为相等
}
return 0;
}
(三)逻辑运算符和逻辑表达式
! | && | || |
---|---|---|
逻辑非 | 逻辑与 | 逻辑或 |
逻辑非! 优先级 高于 算术运算符;
|| && 优先级 低于 关系运算符。
(四)赋值操作符
在变量创建的时候给一个初始值叫初始化,在变量创建后,再给一个值,这叫赋值。
=:赋值操作符,是一个可以随时给变量赋值的操作符。
1.赋值操作符可以连续赋值
#include <stdio.h>
int main()
{
int a = 5;
int b = 3;
int c = 2;
c = b = a + 3;//连续赋值,从右向左赋值
printf("%d", c);//结果输出为8,
return 0;
}
关于连续赋值,虽然C语言可以输出这种赋值,但是写出来的代码有时候不够容易理解,因此建议还是拆开写,更方便观察代码之间的关系。
2.复合赋值符
对一个变量进行自增、自减的运算。
可以写成
复合赋值符
+= | -= | *= | /= | // | >>= | <<= | &= | |= | ^= |
---|---|---|---|---|---|---|---|---|---|
=+ | =- | =* | =/ | 后期再介绍 |
(五)单目操作符
前置++ | 后置++ | 前置– | 后置– | + | - |
---|---|---|---|---|---|
先加1后使用 | 先使用后加1 | 先减1后使用 | 后减1后使用 | 正号 | 负号 |
只有一个操作数,所以是单目操作符。
(六)条件操作符
条件操作符也叫三目操作符,需要接受三个操作数,形式如下:
exp1 ? exp2 : exp3
条件操作符的计算逻辑是:如果exp1为真,exp2计算,计算结果是整个表达式的结果;如果exp1为假,exp3计算,计算的结果是整个表达式的结果。
(七)逗号表达式
逗号表达式,就是⽤逗号隔开的多个表达式。逗号表达式,从左向右依次执⾏。整个表达式的结果是最后⼀个表达式的结果。
exp1, exp2, exp3, …expN
//代码1
int a = 1;
int b = 2;
int c = (a>b, a=b+10, a, b=a+1);//逗号表达式 c是多少?
//a=1,b=2,c=2?
//a=12,b=12,c=13?
//代码2
if (a =b + 1, c=a / 2, d > 0)//表达式的结果是最后一个表达式的结果
//代码3
a = get_val();
count_val(a);
while (a > 0)
{
//业务处理
a = get_val();
count_val(a);
}
//如果使⽤逗号表达式,改写:
while (a = get_val(), count_val(a), a>0)
{
//业务处理
}
二、强制类型转换
在操作符中还有一种特殊的操作符是 强制类型转换 。不到万不得已时不建议使用。
格式:(类型)
int main()
{
int a = 3.14;
//int是整型,a是整型,3.14是double型,两边类型不一样
//编译器会报警报
return 0;
}
//强制类型转换,可改为下列代码
int a = (3.14);
三、语句和语句分类
C语言的语句可分为一下五类:
- 空语句
- 表达式语句
- 函数调用语句
- 复合语句
- 控制语句
(一)空语句
一个分号就是一条语句,是空语句。
#include <stdio.h>
int main()
{
;//是空语句,出现的情况是,这里需要一个语句,
//但是这个语句不需要做任何事情,就可以写一个空语句
return 0;
}
(二)表达式语句
表达式语句就是在表达式后加上分号。
#include <stdio.h>
int main()
{
int a = 20;
int b = 2;
b = a + 3;//表达式语句
printf("%d",b);
return o;
}
(三)函数调用语句
函数调用语句时,也会加上分号。
#include <stdio.h>
int Add(int x, int y)
{
return x + y;
}
int main()
{
printf("do it\n");//函数调用语句
int ret = Add(2,3);//函数调用语句
}
(四)复合语句
成对括号中的代码就构成一个代码块,也被称为复合语句。
#include <stdio.h>
void print(int arr[] , int sz)//函数的大括号中的代码也构成复合语句
{
int i = 0;
for(i=0; i<sz; i++)
{
printf("%d",arr[i]);
}
}
int main()
{
int i = 0;
int arr[10] = {0};
for(i=0; i<sz; i++)//for循环的循环体的大括号中的就是复合语句
{
arr[i] = 10-i;
printf("%d",arr[i]);
}
return 0;
}
(五)控制语句
控制语句用于控制程序的执行流程,以实现程序的各种结构方式(顺序结构、选择结构、循环结构)
可分为以下三种类型(后续详细介绍):
- 条件判断语句(分支语句):if语句、switch语句;
- 循环执行语句:do while语句、while语句、for语句;
- 转向语句:break语句、goto语句、continue语句、return语句。
三、整型常量的不同进制关系
计算机中只能存储二进制数,即1和0,在对应的物理硬件上是高低电平。除常用的十进制,计算机还提供八进制和十六进制。
计算机中一个字节byte就是8个bit位,1KB=1024byte,1MB=1024KB,1GB=1024MB。
0,1 | 0-7 | 0-9 | 0-9,a-f |
---|---|---|---|
二进制 | 八进制 | 十进制 | 十六进制 |
当一个十进制数为123时,其二进制为0111 1011。
当二进制为0111 1011,转化为八进制。
二进制转化十六进制
四、scanf函数
- C语言未提供输入/输出关键字;
- scanf()函数用于读取用户的键盘输入(又称标准输入);
- 当scanf函数读取标准输入时,如果还没有输入任何内容,那么scanf函数会被卡住(专业用于阻塞);
- 头文件stdio.h;
- scanf用来读取标准输入,scanf把标准输入内的内容,需要放到某个变量空间,因此变量必须取地址;
- scanf()的语法跟printf()类似。
格式:scanf(“%d”,&i); 其中&就是取地址的意思。
(一)scanf的基本用法
- 变量前面必须加上 & 运算符(指针变量除外),因为 scanf() 传递的不是值,而是地址,即将变量 i 的地址指向用戶输入的值。如果这里的变量是指针变量(比如字符串变量),那就不用加& 运算符。
- scanf() 处理数值占位符时,会自动过滤空白字符,包括空格、制表符、换行符等。所以,用戶输入的数据之间,有一个或多个空格不影响 scanf() 解读数据。另外,用戶使用回车键,将输入分成几行,也不影响解读。
(二)scanf的返回值
- scanf()的返回值是一个整数,表示成功读取的变量个数。
- 如果没有读取任何项,或者匹配失败,则返回0。
- 如果在成功读取任何数据之前,发生了读取错误或者遇到读取到文件结尾,则返回常量EOF。
(三)占位符
scanf() 常用的占位符如下,与 printf() 的占位符基本一致。
• %c :字符。
• %d :整数。
• %f : float 类型浮点数。
• %lf : double 类型浮点数。
• %Lf : long double 类型浮点数。
• %s :字符串。
• %[ ] :在方括号中指定一组匹配的字符(比如 %[0-9] ),遇到不在集合之中的字符,匹配将会停止。
- 上面所有占位符之中,除了 %c 以外,都会自动忽略起首的空白字符。
- %c 不忽略空白字符,总是返回当前第一个字符,无论该字符是否为空格。如果要强制跳过字符前的空白字符,可以写成 scanf(" %c", &ch) ,即 %c 前加上一个空格,表示跳过零个或多个空白字符。
- 占位符 %s不能简单地等同于字符串。它的规则是,从当前第一个非空白字符开始读起,直到遇到空白字符(即空格、换行符、制表符等)为止。
- %s 不会包含空白字符,无法用来读取多个单词,除非多个 %s 一起使用。
- 另外,scanf() 遇到 %s 占位符,会在字符串变量末尾存储一个空字符 \0 。
scanf() 将字符串读入字符数组时,不会检测字符串是否超过了数组长度。所以,储存字符串时,很可能会超过数组的边界,导致预想不到的结果。为了防止这种情况,使用 %s 占位符时,应该指定读入字符串的最长长度,即写成 %[m]s ,其中的 [m] 是一个整数,表示读取字符串的最大长度,后面的字符将被丢弃。
#include <stdio.h>
int main()
{
char name[11];
scanf("%10s",name);
return 0;
}
(四)赋值忽略符
#include <stdio.h>
int main()
{
int year = 0;
int month = 0;
int day = 0;
scanf("%d-%d-%d",&year,&month,&day);
printf("%d %d %d\n",year,month,day);
return 0;
}
如果用戶输入 2020-01-01 ,就会正确解读出年、月、日。问题是用戶可能输入其他格式,比如 2020/01/01,这种情况下,scanf() 解析数据就会失败。
为了避免这种情况,scanf()提供了一个赋值忽略符(assignment suppression character) * 。
只要把 * 加在任何占位符的百分号后面,该占位符就不会返回值,解析后将被丢弃。
#include <stdio.h>
int main()
{
int year = 0;
int month = 0;
int day = 0;
scanf("%d%*c%d%*c%d",&year,&month,&day);
printf("%d %d %d\n",year,month,day);
return 0;
}
上面示例中,%d*C就是在占位符的百分号后面,加大了赋值忽略符 * ,表示这个占位符没有对应的变量,解读后不必返回。