单目操作符:++ -- +(正) -(负)
++是一种自增操作符 又分为前置++和后置++
不管前置++ 还是后置++ 都是+1
前置++:是先+1后使用
如:
int a=5;
int b=++a;
最终输出的a,b都为6
等效于a=a+1,b=a
后置++:先使用后+1
如L;
int a=5;
int b=a++;
输出的a为6 b为5
等效于 b=a a=a+1
-- 如上
强制类型转换
语法形式: (类型)
例:
int main()
{
3.14; 编译器识别为double型
3.24f; f表示其是float型
int a=(int)3.14; 将浮点数强制转换成整数 输出3
return 0;
}
注意:1.直接写出的字面浮点数 会被编译器直接识别为double
2.强制转换是万不得已才使用
scanf(输入)和printf(输出)介绍
在使用这俩函数时 记住一定要用头文件<stdio.h>
printf:将数据输出到电脑屏幕上
如果想让打印的数据不在一行 在数据后添上\n(换行符)
printf()可以在输出文本中指定占位符
所谓占位符 就是这个位置可以被指定 占位符的第一个字符是% 第二个表示类型
如: printf(“there are %d apples”,a); 这里%d就是占位符
输出文本可以使用多个占位符
常用占位符列举:
%c:字符
%d:十进制整数
%f:小数
%hd:十进制short int 类型
%hu:unsigned short int类型
%ld:十进制long short 类型
%lu:unsigned long int 类型
%Lf:long double类型浮点数
%p:指针
%s:字符串
%u:无符号整数(unsigned int)
%x:十六进制整数
%zd:size_t类型
%%:输出一个%
输出格式
printf()可以定制占位符的输出格式
如果想让正数前显示正号 在%d前填一个+ 即可
限定小数位数:举例: %.2f 表示限定该小数位为2个
%6.2f 表示至少打印6位 小数位为2
在用%s打印字符时 也可以限制字符长度 %.[m]s m表示限制长度
scanf()
scanf()函数用于读取用户键盘输入
例如:
scanf(“%d”,&a);
注:变量前面必须加&(指针变量除外)取地址符 因为scanf()传递的不是值 而是地址 即将变量i的地址指向用户输入的值
如果这里的变量是指针变量(比如字符串变量)或者数组 就不用加&
scanf()处理数值占位符时 会自动过滤空白字符 包括空格 制表符 换行符等
scanf()处理用户输入的原理时,用户输入先放入缓存 等到按下回车键后 按照占位符对缓存进行解读 解读用户输入时 会从上一次解读遗留的第一个字符开始 知道读完缓存 或者遇到第一个不符合条件的字符为止
scanf()的返回值
scanf()的返回值是一个整数 表示成功读取的变量个数
如果没有读取任何项 或者匹配失败 则返回0
如果在成功读取任何数据之前 发生了读取错误或者遇到读取到文件结尾 则返回常量EOF(-1)
EOF是文件结束标志
注意:除了%c以外 都会自动忽略起首的字符 %c不忽略空白字符
如果要强制跳过字符前的空白字符 可以在百分号前加一个空格
特殊%s 规则:从当前第一个非空白字符开始读起 直到遇到空白字符(即空格 换行符 制表符等)为止
因为%s不会包含空白字符 所以无法用来读取多个单词 除非多个%s一起使用 这也意味着 scanf()不适合读取可能包含空格的字符串 比如书名或歌曲名 另外scanf()遇到%s占位符 会在字符串变量末尾存储一个空字符\0
scanf()将字符串读入字符数组时,不会检测字符串是否超过数组长度 所以 存储字符串时 很可能会超过数组边界 导致意想不到的结果 为了防止这种情况 使用%s占位符时 应该指定读入字符串的最长长度 即写成%[ m ] s,其中的[ m ]是一个整数 表示读取字符串的最大长度 后面的字符将被丢弃(防止数组溢出)
赋值忽略符 只需要知道有这么个东西就行 感兴趣的可以查询一下 并不重要
分支和循环(上)
if语句
语法形式:if(表达式)
如果表达式为0(c语言中 0为假 1为真) 不执行
else语句
if(表达式)
语句1
else(表达式)
语句2
分支中包含多条语句
默认if else语句控制一条语句 此时需要使用 { } 控制多条语句 这个块也叫程序块或者复合语句
嵌套if
例
if() if() if()
语句 语句 {
else else if() if()
{ 语句 语句
if( ) else if()
语句 语句 语句
else( ) }
语句 else
} 语句
悬空else问题
如果有多个if和else else总是跟最接近的if匹配(在没有{}的情况下)
关系操作符: 判断是否符合
> < >= <= ==相等 !=不等于
关系表达式通常返回0或1 表示真假
C语言中 0表示假 所有非零值表示真
注意:多个运算符不宜连用 例:a<b<c 不要这样写
例
int a=5;int b=10;int c=10;
if(a<b<c)
printf(“hehe”);
else
printf(“haha”);
此时运行结果为hehe
因为a<b 成立 此时a<b表达式的值为1 接着进行比较1<c 同样成立 所有打印hehe
条件操作符(三目操作符):需要接受三个操作数
表达式1?表达式2:表达式3
计算逻辑:如果表1为真 表2计算 表3不算 计算结果是整个表达式的结果
如果表2为假 表3计算 结果为整个表达式的结果
例: b=(a>5 ? 3 : -3) a>5时 b=3 a<=5时 b=-3
逻辑操作符: && || !
!:逻辑取反运算符(改变单个表达式的真假)
&&:逻辑与运算符 意为 并且 (两侧表达式都为真 则为真 否则为假)
||:逻辑或运算符 意为或者(至少一个表达式为真,则为真)
逻辑取反运算符:!
a !a
非0 0
0 1
与 运算符:&&
a b a&&b
非0 非0 1
非0 0 0
0 非0 0
0 0 0
逻辑或运算符:||
a b a||b
非0 非0 1
非0 0 1
0 非0 1
0 0 0
短路
C语言逻辑运算符总是先对左侧的表达式求值 再对右侧表达式求值
如果左侧表达式满足逻辑运算符的条件 就不再对右边的表达式求值 这种情况称为短路
例如:
if(month>=3&&month<=5)
左操作数 结果为0时 不用判断右操作数了 整个表达式结果都为0
if(month==12||month==1||month==2)
如果month=12时 整个表达式值为1
switch语句
switch(expression){
case value1:statement
case value2:statement
....
...
default:statement
}
switch 后的expression必须是整型表达式
case 后的值 必须是整型常量表达式
注意:case 和后面的数字之间必须有空格
每一个case语句中的代码执行完成后 需要加上break 才能跳出这个switch语句
switch语句中的break
如果某一个case语句的后边没有break语句 代码会继续往下执行 有可能执行其他case语句中的代码 直到遇到break语句 或者switch语句结束
当然 break也不是每个case语句都得有 这就得根据实际情况来看了
几个case共用一个输出时即可去掉某几个break
switch语句中的default(一般放到最后)
处理所有case都不能匹配的情况
while循环
while(表达式)
语句
while语句的执行流程
for循环(使用最多)
语法形式
for(表达式1;表达式2;表达式3)
语句;
表达式1:初始化部分
表达式2:判断部分
表达式3:调整部分
for循环的执行流程
do while循环(使用最少)
语法形式
do
语句;
while(表达式);
do while循环的执行流程
break和continue语句
while循环中的break和continue
break的作用是用于永久的终止循环 只要break被执行 直接就会跳出循环 继续往后执行
continue的作用是跳出本次循环
for循环中的break和continue(continue会返回到调整部分)
do while的break和continue与while一致
goto语句(尽量少的使用)
C语言提供了一种非常特别的语法 就是goto语句和跳转标号 goto语句可以实现
在多层循环的代码中,如果想快速跳出使用goto就非常方便
分支和循环(下)
随机数生成
rand函数会返回一个伪随机数 范围:0~RAND_MAX(32767) 伪随机数不是真正的随机数 是通过某种算法生成的随机数 真正的随机数是无法预测下一个值是多少的 rand函数是对一个叫“种子”的基准值进行运算生成的随机数
每次运行程序产生的随机数序列是一样的 因为rand函数生成随机数的默认种子是1
如果要生成不同的随机数 就需要让种子变化起来
srand用来初始化随机数的生成器
void srand(unsigned int seed)
在调用rand函数前需先调用srand函数 通过srand函数的参数seed来设置rand函数生成随机数的时候的种子 只要种子在变化 每次生成的随机数序列也就变化起来了
那也就是说给srand的种子 如果是随机的 rand就能生成随机数 在生成随机数的时候又需要一个随机数 这就矛盾了
time
time函数会返回当前的日历时间 其实返回的是1970年1月1日0时0分0秒到现在程序运行时间之间的差值 单位是秒 返回类型是time_t类型的 本质上其实是32位或者64位的整型类型
参数timer如果是非NULL的指针的话 函数也会将这个返回的差值放在timer指向的 内存中带回去
如果timer是NULL 就只返回这个时间的差值 time函数返回的这个时间差也被叫做 时间戳
time_t time(time_t* timer);
因为时间是时刻变化的
设置随机数的范围
rand()%100; 余数的范围是0~99
rand()%100+1;余数范围是1~100
100+rand()%(200-100+1)
如果要生成a~b的随机数 方法如下:
a+rand()%(b-a+1)
数组
数组:其实就是能存放一组数(相同类型)
数组中存放的是1个或者多个数据 但是数组元素个数不能为0
数组中存放的多个数据 类型是相同的
数组分为一维数组 多维数组 其中比较常见的多维数组是二维数组
一维数组的创建和初始化
数组创建
一维数组基本语法:
type arr_name[常量值]
type 指定的是数组中存放数据的类型
arr_name指的是数组名的名字
如: int data[10];
数组在创建时候可以指定数组大小和数组元素类型
数组的初始化
有时候 数组在创建的时候 需要给定一些初始值 这种就称为初始化
如:int a=0;
数组的类型
去掉数组名留下的就是数组的类型
如: int arr1[10]; 它的数组类型就是 int [10]
一维数组的使用
数组下标 下标从0开始 假设数组有n个元素 最后一个元素的下标就是n-1
在C语言中数组的访问提供了一个操作符[ ] 这个操作符叫:下标引用操作符
数组元素的打印:使用下标来进行访问即可
如 :
for(int i=0;i<10;i++)
{
printf(“%d ”,arr[i]);
}
数组的输入
for(int i=0;i<10;i++)
scanf(“%d”,&arr[i]);
一维数组在内存中的存储:一维数组在内存中是连续存放的
sizeof计算数组元素个数
sizeof是C语言的一个关键字 可以计算类型或者变量大小 也可以计算数组大小
int arr[10]={1,2,3,4,5};
printf(“%zd\n”,sizeof(arr)); sizeof(数组名) 计算的是整个数组 单位是字节
二维数组的创建
二维数组的概念
如果我们把一维数组做为数组的元素(即n个一行元素) 这时候就是二维数组
二维数组的创建
语法
type arr_name[常量值1][常量值2]; 常量值1代表行 常量值2代表列
如: int arr[3][5];
该二维数组arr有3行5列
二维数组的初始化
类似于一维数组
如:
int arr[3][5]={1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7}; 完全初始化
int arr[3][5]={1,2}; 不完全初始化 剩余元素默认初始化为0
初始化时可省略行 不省略列
二维数组的使用
二维数组的下标:只要锁定行和列就能唯一锁定数组中的一个元素
当然 行与列下标同样从0开始
二维数组的输入和输出
int main()
{
int arr[3][5]={0};
int i=0;
for(i=0;i<3;i++)
{
int j=0;
for(j=0;j<5;j++)
{
scanf(“%d”,&arr[i][j]);
}
} 输入
for(i=0;i<3;i++) 输出
{
int j=0;
for(j=0;j<5;j++)
{
printf(“%d”,arr[i][j]);
}
printf(“\n”);
return 0;
}
二维数组的每个元素在内存中都是连续存放的
一行存完 存下一行
C99变长数组
int main()
{
int n=0;
scanf(“%d”,&n); VS不支持C99中的变长数组
int arr[n]; gcc是支持的
return 0; 刷题的网站一般也是支持的
}
可以使用变量来指定数组大小
并不是说数组的大小是可变的 数组大小一旦确定便无法改变
变长数组不能初始化(只有运行时才知道n是多少)