一.printf和scanf介绍
1.printf
1.1printf的基本用法
作用:将参数⽂本输出到屏幕。它名字⾥⾯的 f 代表 format (格式化),表⽰可以定制输出⽂本的格式。
#include<stdio.h>
int main()
{
printf("hello,\nworld\n");
return 0;
}
printf() 不会在⾏尾⾃动添加换⾏符,运⾏结束后,光标就停留在输出结束的地⽅,不会⾃动换⾏。
可添加\n使光标移到下一行,位于文本中间可使两侧换行;
printf() 是在标准库的头⽂件 stdio.h 定义的。使⽤这个函数之前,必须在源码⽂件头部引⼊这个头⽂件。
1.2占位符
printf() 可以在输出⽂本中指定占位符。
所谓 “占位符”,就是这个位置可以⽤其他值代⼊。
#include<stdio.h>
int main()
{
printf("%d\n", 666);
return 0;
}
%d即为占位符,其替666占位,在运行使将666代入
占位符的第⼀个字符⼀律为百分号 % ,第⼆个字符表⽰占位符的类型, %d 表⽰这⾥代⼊的值必须是⼀个整数。
printf() 的第⼆个参数就是替换占位符的值
输出⽂本⾥⾯可以使⽤多个占位符。
#include<stdio.h>
int main()
{
printf("%s don't love %s\n","your lover","you");
return 0;
}
%s 表⽰代⼊的是⼀个字符串
printf() 参数与占位符是⼀⼀对应关系,如果有 n 个占位符, printf() 的参数就应该有 n + 1 个。
上面”your lover“和”you“以及”%s don’t love %s\n“为参数。其对应两个占位符即两个%s。如果参数个数少于对应的占位符, printf() 可能会输出内存中的任意值。
1.3占位符列举
• %a :⼗六进制浮点数,字⺟输出为⼩写。
• %A :⼗六进制浮点数,字⺟输出为⼤写。
• %c :字符。
• %d :⼗进制整数。// int
• %e :使⽤科学计数法的浮点数,指数部分的 e 为⼩写。
• %E :使⽤科学计数法的浮点数,指数部分的 E 为⼤写。
• %i :整数,基本等同于 %d 。
• %f :⼩数(包含 float 类型和 double 类型)。//float %f double - %lf
• %g :6个有效数字的浮点数。整数部分⼀旦超过6位,就会⾃动转为科学计数法,指数部分的 e
为⼩写。
• %G :等同于 %g ,唯⼀的区别是指数部分的 E 为⼤写。
• %hd :⼗进制 short int 类型。
• %ho :⼋进制 short int 类型。
• %hx :⼗六进制 short int 类型。
• %hu :unsigned short int 类型。
• %ld :⼗进制 long int 类型。
• %lo :⼋进制 long int 类型。
• %lx :⼗六进制 long int 类型。
• %lu :unsigned long int 类型。
• %lld :⼗进制 long long int 类型。
• %llo :⼋进制 long long int 类型。
• %llx :⼗六进制 long long int 类型。
• %llu :unsigned long long int 类型。
• %Le :科学计数法表⽰的 long double 类型浮点数。
• %Lf :long double 类型浮点数。
• %n :已输出的字符串数量。该占位符本⾝不输出,只将值存储在指定变量之中。
• %o :⼋进制整数。
• %p :指针(⽤来打印地址)。
• %s :字符串。
• %u :⽆符号整数(unsigned int)。
• %x :⼗六进制整数。
• %zd : size_t 类型。
• %% :输出⼀个百分号。
注:%f和%lf在打印的时候,小数点后默认是打印6位。
1.4输出格式
1.4.1限制宽度
printf() 允许限定占位符的最⼩宽度。
上⾯⽰例中, %5d 表⽰这个占位符的宽度⾄少为5位。如果不满5位,对应的值的前⾯会添加空格。输出的值默认是右对⻬,即输出内容前⾯会有空格;如果希望改成左对⻬,在输出内容后⾯添加空格,可以在占位符的 % 的后⾯插⼊⼀个 - 号。
对于⼩数,限定符%xlf会限制所有数字的最⼩显⽰宽度。x为整数
1.4.2总是显示正负号
默认情况下, printf() 不对正数显⽰ + 号,只对负数显⽰ - 号。如果想让正数也输出 + 号,可以在占位符的 % 后⾯加⼀个 + 。
1.4.3限定小数位数
输出⼩数时,有时希望限定⼩数的位数。举例来说,希望⼩数点后⾯只保留*位,占位符可以写成 %.*f
这种写法可以与限定宽度占位符,结合使⽤。
最⼩宽度和⼩数位数这两个限定值,都可以⽤ * 代替,通过 printf() 的参数传⼊。
1.4.4输出部分字符串
%s 占位符⽤来输出字符串,默认是全部输出。如果只想输出开头的部分,可以⽤ %.[m]s 指定输出的⻓度,其中 [m] 代表⼀个数字,表⽰所要输出的⻓度。
2.scanf
即给变量输⼊值
#include <stdio.h>
int main()
{
int score = 0;
printf("请输入成绩:");
scanf("%d", &score);//输入操作
//scanf函数中占位符的后边的参数需要的是地址
//& 取地址操作符。&score-取出score的地址
printf("成绩是%d\n", score);
return 0;
}
2.1基本用法
scanf() 函数⽤于读取⽤⼾的键盘输⼊。
程序运⾏到这个语句时,会停下来,等待⽤⼾从键盘输⼊。
⽤⼾输⼊数据、按下回⻋键后, scanf() 就会处理⽤⼾的输⼊,将其存⼊变量。
它的原型定义在头⽂件 stdio.h 。
scanf() 的语法跟 printf() 类似。
scanf(“%d”,&i)
的第⼀个参数 %d ,表⽰⽤⼾输⼊的应该是⼀个整数。 %d 就是⼀个占位符, % 是占位符的标志, d 表⽰整数。第⼆个参数 &i 表⽰,将⽤⼾从键盘输⼊的`#include <stdio.h>
int main()
#include <stdio.h>
int main()
{
int a = 0;
int b = 0;
float c = 0.0;
float d = 0.0;
scanf("%d,%d,%f,%f", &a, &b, &c, &d);
printf("%d,%d,%f,%f",a,b,c,d);
return 0;
}
2.2scanf的返回值
scanf() 的返回值是⼀个整数,表⽰成功读取的变量个数。
如果没有读取任何项,或者匹配失败,则返回 0 。
如果在成功读取任何数据之前,发⽣了读取错误或者遇到读取到⽂件结尾,则返回常量 EOF (-1)。
2.3占位符
scanf() 常⽤的占位符如下,与 printf() 的占位符基本⼀致。
• %c :字符。
• %d :整数。
• %f : float 类型浮点数。
• %lf : double 类型浮点数。
• %Lf :long double 类型浮点数。
• %s :字符串。
• %[]:在⽅括号中指定⼀组匹配的字符(⽐如 %[0-9]),遇到不在集合之中的字符,匹配将会停⽌。
上⾯所有占位符之中,除了 %c 以外,都会⾃动忽略起⾸的空⽩字符。 %c 不忽略空⽩字符,总是返
回当前第⼀个字符,⽆论该字符是否为空格。
如果要强制跳过字符前的空⽩字符,可以写成 scanf(" %c", &ch) ,即 %c 前加上⼀个空格,表⽰跳过零个或多个空⽩字符。
二.分⽀和循环
C语⾔是结构化的程序设计语⾔,这⾥的结构指的是顺序结构、选择结构、循环结构。
C中用if 、 switch 实现分⽀结构,使⽤ for 、 while 、 do while 实现循环结构
1. if语句
1.1语法格式
if(表达式)
… 语句
表达式成⽴(为真),则语句执⾏,表达式不成⽴(为假),则语句不执⾏。在C语⾔中,0为假,⾮0表⽰真,也就是表达式的结果如果是0,则语句不执⾏,表达式的结果如果为非0,则语句执⾏。
判断是否为奇数
int main()
{
int num = 0;
printf("请输入\n");
scanf("%d", &num);
if (num % 2 == 1)
printf("%d 为奇数", num);
return 0;
}
1.2.else
1.2.1if…else… 语句
语法形式:
if(表达式)
语句1
else
语句
int main()
{
int num = 0;
printf("请输入\n");
scanf("%d", &num);
if (num % 2 == 1)
printf("%d 为奇数", num);
else
printf("tban");
return 0;
}
1.3.分⽀中包含多条语句
默认在 if 和 else 语句中默认都只控制⼀条语句。
如果要if语句同时控制2条语句,就要使⽤ {} 将代码括起来,else 后也可以跟上⼤括号。
int main()
{
int age = 0;
printf("请输入年龄:\n");
scanf("%d", &age);
if (age >= 18)
{
printf("你已经成年,可以恋爱!!!\n");
printf("狗屎\n");
}
else
printf("去学习吧");
return 0;
}
1.4.嵌套if
在 if else 语句中, else 可以与另⼀个 if 语句连⽤,构成多重判断。
#include <stdio.h>
int main()
{
int num = 0;
scanf("%d", &num);
if(num == 0)
printf("输⼊的数字是0\n");
else if(num > 0) //这⾥的if 相当于嵌套在else语句中,形成了嵌套结构
printf("输⼊的数字是正数\n");
else
printf("输⼊的数字是负数\n");
return 0;
}
注:如果有多个 if 和 else ,可以记住这样⼀条规则, else 总是跟最接近的 if 匹配
2.逻辑操作符
&& , || , !三种逻辑运算符提供逻辑判断功能,⽤于构建更复杂的表达式。
• ! :逻辑取反运算符(改变单个表达式的真假)。
• && :逻辑与运算符,就是并且的意思(两侧的表达式都为真,则为真,否则为假)。
• || :逻辑或运算符,就是或者的意思(两侧⾄少有⼀个表达式为真,则为真,否则为假)。
3.短路
C语⾔逻辑运算符还有⼀个特点,它总是先对左侧的表达式求值,再对右边的表达式求值。如果左边的表达式满⾜逻辑运算符的条件,就不再对右边的表达式求值。
if(month >= 3 && month <= 5)
表达式中&& 的左操作数是 month >= 3 ,右操作数是 month <= 5 ,当左操作数 month >= 3 的结果是0的时候,即使不判断 month <= 5 ,整个表达式的结果也是0,所以,对于&&操作符来说,左边操作数的结果是0的时候,右边操作数就不再执⾏。
4.switch语句
switch 语句是⼀种特殊形式的 if…else 结构,⽤于判断条件有多个结果的情况。它把多重的 else if 改成更易⽤、可读性更好的形式。
switch (expression) {
case value1: statement
case value2: statement
default: statement
}switch 后的 expression 必须是整型表达式
case 后的值,必须是整形常量表达式
但要在每个case语句结束后写上break
int main()
{
int a = 0;
scanf("%d", &a);
switch (a % 3)
{
case 0:
printf("余数为0\n");
break;
case 1:
printf("1\n");
break;
case 2:
printf("2\n");
break;
}
return 0;
}
只有在 switch 语句中使⽤ break 才能在跳出 switch 语句,如果某⼀个 case 语句的后边没有 break 语句,代码会继续往下执⾏,有可能执⾏其他 case语句中的代码,直到遇到 break 语句或者 switch 语句结束。就⽐如上⾯的代码就执⾏了 case。
在使⽤ switch 语句的时候,switch 后的表达式中的值⽆法匹配代码中的 case 语句的时候可以不做处理,也在 switch 语句中加⼊default ⼦句。
switch (expression) {
case value1: statement
case value2: statement
default: statement
}
switch 后边的 expression 的结果不是 value1 ,也不是 value2 的时候,就会执⾏default ⼦句。
5.while语句
语法格式:
while(表达式)
语句;//如果循环体想包含更多的语句,可以加上⼤括号
int main()
{
int n = 0;
scanf("%d", &n);
while (n) {
printf("%d", n % 10);
n = n / 10;
}
return 0;
}
6.for循环
语法格式
for(表达式1; 表达式2; 表达式3)
语句;//如果循环体想包含更多的语句,可以加上⼤括号
表达式1 ⽤于循环变量的初始化
表达式2 ⽤于循环结束条件的判断
表达式3 ⽤于循环变量的调整
int main()
{
int i = 0;
for (i = 1; i <= 10; i++) {
printf("%d", i);
}
return 0;
}
7.while和for语句的对比
for 和 while 在实现循环的过程中都有初始化、判断、调整这三个部分,但是 for 循环的三个部分⾮常集中,便于代码的维护,⽽如果代码较多的时候 while 循环的三个部分就⽐较分散,所以从形式上 for 循环要更优⼀些。
8.do…while语句
语法格式:
do
语句;
while(表达式);
int main()
{
int i = 0;
do
{
printf("%d", i);
i++;
} while (i <= 10);
return 0;
}
在 do while 语句中循环体是⾄少执⾏⼀次的,这是 do while 循环⽐较特殊的地⽅。
注:while 和 for 这两种循环都是先判断,条件如果满⾜就进⼊循环,执⾏循环语句,如果不满⾜就跳出循环;⽽ do while 循环则是先直接进⼊循环体,执⾏循环语句,然后再执⾏ while 后的判断表达式,表达式为真,就会进⾏下⼀次,表达式为假,则不再继续循环
9.break和continue
在循环执⾏的过程中,如果某些状况发⽣的时候,需要提前终⽌循环。而C语⾔中提供了 break 和 continue 两个关键字来处理。
• break 的作⽤是⽤于永久的终⽌循环,只要 break 被执⾏,直接就会跳出循环,继续往后执⾏。
• continue 的作⽤是跳过本次循环中 continue 后边的代码,在 for 循环和 while 循环中有所差异的。
.
9.1break
int main()
{
int a = 0;
while (a <= 10)
{
if (a == 5)
break;
printf("%d\n", a);
a++;
}
return 0;
}
打印了1,2,3,4后,当a等于5的时候,循环在 break 的地⽅终⽌,不再打印,不再循环。所以在循环中,想在某种条件下终⽌循环,则可以使⽤ break 来完成我们想要的效果。
9.2continue
9.2.1while中的continue
continue 可以帮助我们跳过某⼀次循环 continue 后边的代码,直接
到循环的判断部分,进⾏下⼀次循环的判断,如果循环的调整是在 continue 后边的话,可能会造成死循环。
调换位置后结果也不同。
9.2.2for中的break和continue
和 while 循环中的 break ⼀样, for 循环中的 break 也是⽤于终⽌循环的,不管循环还需要循环多少次,只要执⾏到了 break ,循环就彻底终⽌
在 for 循环中 continue 的作⽤是跳过本次循环中 continue 后的代码,直接去到循环的调整部分。未来当某个条件发⽣的时候,本次循环⽆需再执⾏后续某些操作的时候,就可以使⽤continue 来实现。
9.2.3do…while的break和continue
do.while 语句中的 break 和 continue 的作⽤和 while 循环中⼏乎⼀模⼀样
#include <stdio.h>
int main()
{
int i = 1;
do
{
if(i == 5)
break;
printf("%d ", i);
i = i + 1;
}while(i<=10);
return 0;
}
`
```c
#include <stdio.h>
int main()
{
int i = 1;
do
{
if(i == 5)
continue;
printf("%d ", i);
i = i + 1;
}while(i<=10);
return 0;
}
10.循环的嵌套
找出100~200之间的素数,并打印在屏幕上。
注:素数⼜称质数,只能被1和本⾝整除的数字。
#include<math.h>
int main()
{
int i = 0;
int count = 0;
for (i = 100; i <= 200; i++)
{
int flag = 1;
int n = 0;
for (n = 2; n <= sqrt(i); n++)
{
if (i % n == 0)
{
flag = 0;
break;
}
}
if (flag == 1)
{
count++;
printf("%d ", i);
}
}
printf("\n %d \n", count);
return 0;
}
11.goto语句
goto 语句可以实现在同⼀个函数内跳转到设置好的标号处。
int main()
{
printf("haha\n");
if (1)
goto end;
printf("hehe\n");
end:
printf("eawn");
return 0;
}
goto 语句
缺点:如果使⽤的不当,就会导致在函数内部随意乱跳转,打乱程序的执⾏流程
优点:本来 for 循环想提前退出得使⽤ break ,⼀个 break 只能跳出⼀层 for 循环,如果3层循环嵌套得使⽤3个 break 才能跳出循环,所以在这种情况下我们使⽤ goto 语句就会更加的快捷。
三.实践
猜数字游戏
1.电脑自动生成1-100的随机数。
2.玩家猜数字,猜数字的过程中,根据猜测数据的大小给出大了或者小了的反馈,直到猜对,游戏结束。
1.rand函数
C语⾔提供了⼀个函数叫 rand,这函数是可以⽣成随机数的,函数原型如下所⽰:
int rand (void);
但运行几次后发现,结果是相同的。
原因是:
-
rand函数会返回⼀个伪随机数,这个随机数的范围是0~RAND_MAX之间,这个RAND_MAX的⼤⼩是依赖编译器上实现的,但是⼤部分编译器上是32767。
-
rand函数的使⽤需要包含⼀个头⽂件是:stdlib.h
-
.rand函数⽣成的随机数是伪随机的,伪随机数不是真正的随机数,是通过某种算法⽣成的随机数。真正的随机数的是⽆法预测下⼀个值是多少的。⽽rand函数是对⼀个叫“种⼦”的基准值进⾏运算⽣成的随机数。
2.srand
C语⾔中⼜提供了⼀个函数叫 srand,⽤来初始化随机数的⽣成器的,srand的原型如下:
void srand (unsigned int seed);
所以得让给srand的种子随机,rand的就能生成随机数
3.time
在程序中我们⼀般是使⽤程序运⾏的时间作为种⼦的,因为时间时刻在发⽣变化的。 在C语⾔中有⼀个函数叫 time ,就可以获得这个时间,time函数原型如下:
time_t time (time_t* timer)
time 函数会返回当前的⽇历时间,其实返回的是1970年1⽉1⽇0时0分0秒到现在程序运⾏时间之间的
差值,单位是秒。返回的类型是time_t类型的,time_t 类型本质上其实就是32位或者64位的整型类
型。
time函数的参数 timer 如果是⾮NULL的指针的话,函数也会将这个返回的差值放在timer指向的内存
中带回去。
如果 timer 是NULL,就只返回这个时间的差值。time函数返回的这个时间差也被叫做:时间戳。
time函数的时候需要包含头⽂件:time.h
4.实现
#include<stdlib.h>
#include<stdio.h>
#include<time.h>
`void menu()
{
printf("***********************");
printf("********* 1.play *********");
printf("********* 0.exit ********");
printf("***********************");
}
void game()
{
int r = rand() % 100 + 1;
int guess = 0;
while (1)
{
printf("请猜数字:");
scanf("%d", &guess);
if (guess > r)
{
printf("da\n");
}
else if (guess < r)
{
printf("xioale\n");
}
else
{
printf("duile\n");
break;
}
}
}
int main()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
menu();
printf("请选择:");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏");
break;
default:
printf("选择错误,重新选择");
break;
}
} while (input);
return 0;
}
结果是