文章目录
- 谭浩强C语言笔记
-
- 1.C语言基础知识
- 2.选择结构
- 3.循环结构
- 4.数组
- 5.函数
- 6.指针
- 7.自定义数据类型
- 8.文件
谭浩强C语言笔记
1.C语言基础知识
1.常量和变量
1.1入门程序
#include <stdio.h>
int main() {
// 定义一个整型变量 a
int a;
// 为变量 a 赋值为 100
a = 100;
return 0;
}
1.2 常量
在程序运行过程中,其值不能被改变的量叫做常量。常用的常量有以下几类:
1.2.1 整型常量
整型常量就是数学里面的定义的整数,例如:0,-1,999……
1.2.2 实型(浮点型)常量
实型常量就是数学里面定义的小数,例如:0.0,3.14,-1.8,999.0……
实型常量在 C 语言里面有两种表现形式:
- 正常的十进制小数形式:3.14……
- 指数形式:3.14e5(表示 3.14 * 10的5次方),-123.456E6(表示 -123.456 * 10的6次方),-346.87e-25(表示 -346.87 * 10-25)……
对于指数形式来说,e(E)前后必须要有数字,e(E)后面必须是整数,e(E)前面可以是整数也可以是浮点数。
1.2.3 字符常量
- 普通字符
使用单引号括起来的一个字符,如:'a','B','*','#','1'
……不能写成:‘ab’,‘12’……
计算机在存储字符的时候,并不是存储字符本身,而是存储字符对应的 ASCII 码。
例如存储字符 ‘#’ 的时候,并不是存储其本身,而是存储 35(二进制形式)。需要的时候再通过 ASCII 映射出对应的字符。特殊的字符序号:‘A’ - 65, ‘a’ - 97
注意:单引号(‘’)不属于字符的一部分,这只是一个标志。标志着这是一个字符。
完整 ASCII 码表:https://baike.baidu.com/item/ASCII/309296
- 转义字符
除了普通字符外,C 语言中还有一些特殊的字符常量,这些字符常量以“\”开头。
这些常量都会有一些特殊的作用,例如之前遇到的 “\n” 表示换行,类似的字符还有很多。
转义字符 | 字符值 |
---|---|
’ | 一个单引号 |
" | 一个双引号 |
\ | 一个反斜杠 |
\t | 水平制表符 |
\n | 换行符 |
? | 一个问号 |
\a | 警告 |
\b | 退格 |
\f | 换页 |
\r | 回车 |
\v | 垂直制表符 |
\o [o…] 其中 o 指代一个八进制数字 | 该八进制数对应的 ASCII 字符。例如,\123 表示字符 ‘S’ |
\x h[h…] 其中 h 指代一个十六进制数字 | 该十六进制数对应的 ASCII 字符。例如,\x53 表示字符 ‘S’ |
1.2.4 字符串常量
由双引号括起来的若干字符称为字符串常量。例如:"Hello World!","123","A"
……
千万不要错写成 'Hello World!'
,这种写法是错误的,单引号里面只能包含一个字符(转义字符除外)用来表示字符常量。
1.2.5 符号常量
在 C 语言中,我们会使用 #define
指令来定义一个符号常量,如下面:
#define PI 3.14`,`#define NAME "Jack"
注意了,定义符号常量的时候,结尾是没有分号的。编译时,会将所有的符号常量替换成对应的值。
1.3 变量
变量是一个有名字的、具有特定属性的存储单元。它是用来存放数据的,被存放的数据叫做变量的值。在程序运行期间,变量的值是可以改变的。
变量必须先定义,后使用。定义的时候必须指明变量的名字和类型,例如代码 int n = 10;
(等价于int n; n = 10;
)就是定义了一个整型变量 n。其中 n 是变量的名字,int 表示这个变量是整型的,后面使用赋值符号(=)来给变量赋初试值 10。因此,我们可以使用“值为 10 的变量 n”来描述这个变量。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aZwspQiq-1665324647760)(E:\Blog\source\images\1656666146861-84c1cff3-eb86-4cf8-8897-2ca851017566.png)]
看内存图:
矩形框就表示一个存储单元,这个存储单元在内存中的地址是1002。
存储单元里面存着整数 10,n 指向这个存储单元(其实有映射表)。
每次使用 n 的时候,默认取 n 指向的单元里的值。
1.4 常变量
我们在定义变量的时候,在前面加上关键字 const
就会使这个变量变为常变量。如代码
const int n = 10;
就是定义了一个值为 10 的整型常变量。
可以看出,常变量和变量类似有名字、有类型还可以存值。但常变量归根到底还是常量,因此常变量一旦定义,其值就不可以改变了。
正是由于常变量一旦定义就不能改变其值的特性,导致我们在定义常变量的时候必须给予其初值。否则这个常变量就没有任何意义。
和符号常量相比,常变量使用起来更加方便,因此我们推荐使用常变量。
简要阐述一下常变量和符号常量之间的异同:
相同点:两者都给常量命名;二者都是用来定义常量的
不同点:
- 符号常量:#define 来定义;不关注常量的类型;该常量不分配内存
- 常变量:类似于变量定义;关注常量类型;分配内存
2.标识符和关键字
2.1 标识符
标识符主要用来标识变量和函数。一个合法的标识符由数字、英文字母(a-z,A-Z)、下划线(_)构成,其中数字不能开头且标识符不能和关键字相同。
C 语言的标识符是区分大小写的,例如 name
、Name
、NAME
都是不同的标识符。
2.2 关键字
auto | break | case |
---|---|---|
char | const | continue |
default | do | double |
else | enum | extern |
float | for | goto |
if | int | long |
register | return | short |
signed | sizeof | static |
struct | switch | typedef |
unsigned | union | void |
volatile | while | |
inline | restrict | _Bool |
_Complex | _Imaginary |
2.3 小习题
判断下列标识符的合法性,将结果填入后面的框内(✓或×):
name | 对 | n0_0n | 对 |
---|---|---|---|
_age0 | 对 | M.D.John | 错 |
i | 对 | 51job | 错 |
int | 错 | v_v | 对 |
int_ | 对 | inline | 错 |
INT | 对 | Program$ | 错 |
3. 基本数据类型
内存单位:比特位(bit),字节(B),千字节(KB),兆字节(MB)
换算:1 B = 8 位;1 KB = 1024 B;1 MB = 1024 KB
可以使用 sizeof 运算符来查看自己编译器下某类型的所占据的字节数,如 sizeof(int)
。
3.1 整型
类型 | 关键字 | 字节数 | 取值范围 |
---|---|---|---|
整型 | int | 4 | -231 ~ (231 - 1) |
无符号整型 | unsigned int | 4 | 0 ~ (232 - 1) |
短整型 | short | 2 | -215 ~ (215 - 1) |
无符号短整型 | unsigned short | 2 | 0 ~ (216 - 1) |
长整型 | long | 4 | -231 ~ (231 - 1) |
无符号长整型 | unsigned long | 4 | 0 ~ (232 - 1) |
长长整型 | long long | 8 | -263 ~ (263 - 1) |
无符号长长整型 | unsigned long long | 8 | 0 ~ (264 - 1) |
3.2 字符型
我们之前提到过,字符型变量里面存储的是该字符的 ASCII 码,而 ASCII 码本质上是一个整数,所以字符型变量本质上还是一个整型。经过观察可以发现,ASCII 里面只有 127 个字符,我们使用 1 个字节(8 位)就可以表示出所有的字符。所以使用int
来表示字符是很浪费内存的,因此特地新开一个类型**char**
,这是 character 的简写。
// 下面两句话是等价的,都表示字符 A,存储的时候都存储 65(二进制)。
char c = 65;
char c = 'A';
// 问:既然存储的时候把 A 存储成 65,那么输出的时候怎么变回 A?
// %d 是十进制整数的输出占位符;%c 是字符输出占位符。
printf("%d, %c", c1, c1);
参考 ASCII 表,思考:如何将一个大写字母变为对应的小写字母?
答:大写字母的ASCII码值比小写字母的ASCII值小32,所以只需要在char 类型下 +32 就可以了。
给定 0-9 之间的一个整数,将其转成对应的字符,即 0-‘0’, 9-‘9’
#include <stdio.h>
int main() {
int a;
char b;
scanf("%d",&a);
b=a+'0';
printf("转换后的字符为:%c\n",b);
return 0;
}
3.3 浮点型
浮点型也就是实型数据。3.14 * 100,0.314 * 101,31.4 * 10-1 都表示同一个数据。可以看出,我们可以通过操作指数来使得小数点在数字之间浮动,故名浮点数。
类型 | 关键字 | 字节数 |
---|---|---|
单精度浮点型 | float | 4 |
双精度浮点型 | double | 8 |
3.4 常量的类型及转化
对于整数(例如 99)来讲默认类型是 int,对于小数(例如 3.14)来讲默认类型是 double。
所以代码int n = 99;
没什么问题。
但是代码float f = 3.14;
会报警告,你可以在数字结尾加一个f(或 F)表示这个数字是单精度浮点型,如:float f = 3.14f;
。
4.运算符
4.1 算术运算符
运算符 | 含义 | 举例 |
---|---|---|
+ | 正号运算符(默认可省略) | +5, 5 |
- | 负号运算符,用来表示负数 | -5 |
+ | 加法运算符,求两个数的和 | 1 + 2 |
- | 减法运算符,求两个数的差 | 3 - 2 |
* | 乘法运算符,求两个数的积 | 2 * 3 |
/ | 除法运算符,求两个数的商 若操作数都是整型,则表示整除 若操作数里有浮点型,则表示除法 | 整除的结果会向 0 取整: 5 / 2 = 2, 6 / 2 = 3, -5 / 2 = -2 浮点数除法就是正常小数 |
% | 模运算(取余运算)符。a % b 表示获取 a 除以 b 的余数。 | 只有整数之前可以取余,浮点数不行。 5 % 2 = 1,6 % 2 = 0 |
4.2 自增(++),自减(–)
自增(++)、自减(–)运算符的作用是使变量的值加1 或 减 1。例如:
++i,–i (在使用 i 之前,先将 i 的值加 1 或减 1)
i++,i-- (在使用 i 之后,再将 i 的值加 1 或减 1)
++ 和 – 可以作用在所有数字上,不一定非是整数,浮点数也可以。
表面上看i++和++i都表示将 i 的值加 1,但两者之间存在着加 1 顺序的区别。例如:
int i = 1, j;
// ++ 在后就后加 1
// 等价于:j = i; i = i + 1;
j = i++;
// ++ 在前就先加 1
// 等价于:i = i + 1; j = i;
j = ++i;
int i = 1, j = 1;
// 下面等价于 (i++)+j
i+++j;
4.3 混合运算
4.3.1 优先级
在混合运算过程中,一个表达式里会有多个不同的运算符,那么在运算的时候依据它们的优先级来计算。例如:
1 + 2 * 5是一个包含了加法和乘法的表达式,很显然***运算符优先于+**运算符,因此计算结果是 11。
n = 1 + 2表达式包含了赋值运算符=和加法运算符+,显然加法运算符优先级高,因此 n 的值为 3 而不是 1。
4.3.2 结合方向
结合方向就是遇到同级运算符时,应该先算左边还是右边。例如:
左结合案例:1 + 3 - 2
加法和减法是同级运算符,但是由于加减是左结合的,因此先加后减。
右结合案例:n = i = 1
两个赋值运算是同级的,又由于赋值运算是右结合的,因此先执行 i = 1,再执行 n = i
记住这两个案例:1. 算术运算符都是左结合; 2. 赋值运算符是右结合。
4.3.3 自动类型转换
各数值类型大小关系:char < int < float < double
若某运算前后两个数据的类型不一致,则按照“小变大”的原则同步双方的类型。
但是注意:不要以上帝视角去转换类型,而是走一步看一步。例如:5 / 2 / 2.0
一眼看穿,自动类型转换都是将小类型往大类型转。
4.3.4 强制类型转换
有些时候,自动转换类型并不能满足我们的要求,需要手动转换变量的类型,这时就用到强制类型转换了。强转时只需要在要转的变量或表达式前加上(要转的类型)。例如:
1.(int) a
表示将量 a 强转成 int 型。
2.(double) (a + b)
表示将 a + b 的结果强转成 double 型。
3.(double) a + b
表示将 a 强转成 double 型再将其与 b 想加。
强制类型转换,可以小转大,也可以大转小,取决于你的心意。
小转大,数据会完全包容,没什么问题。但大转小存在数据精度丢失的风险,例如n = (int) 3.14,我们将double 类型数据 3.14 强转成 int 型,那么小数部分会丢失,也就是会向 0 取整。
4.3.5 C 语言优先级表
https://www.yuque.com/docs/share/ea772be5-f17c-4091-bf6f-4b38a31fdcd8?#
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-udREvBFb-1665324647761)(E:\Blog\source\images\1656827642693-e0dd3997-a2ce-4bee-8e45-5958dc6e4867.png)]
4.3.6 小习题
1.口算下面的运行结果并与编程运行结果比较:
表达式 | 结果类型 | 结果值 |
---|---|---|
(double) 2 * 5 / 4 + 1 | double | 3.5 |
5 / 2 + 1.2 * 2 - 1 | double | 3.4 |
(double)(7 / 2 + 1) | double | 4.0 |
5 / 2 + 7 / 2 (5 + 7) / 2 | int | 2 |
70 % ‘A’ * 10 % 2 / 2 | int | 0 |
2.对于任意的四位整数 n,如何取到 n 的个位数、十位数、百位数、千位数?
4.4.位运算
运算符 | 含义 | 运算符 | 含义 |
---|---|---|---|
& | 按位与 | ~ | 按位取反 |
| | 按位或 | << | 左移 |
^ | 按位异或 | >> | 右移 |
注:参加位运算的对象只能是整型或字符型的数据,不能为实型数据。
例题 2的n次方计算
#include <stdio.h>
int main()
{
int a,n;
a=1;
scanf("%d",&n);
a=a<<n;
printf("%d",a);
return 0;
}
5. 语句
5.1 语句分类
5.1.1 控制语句
控制语句是用于完成一定的控制功能,C 语言中有 9 种控制语句,它们分别是:
- if ()…else… (条件语句)
- for ()… (循环语句)
- while()… (循环语句)
- do…while() (循环语句)
- continue (结束本次循环语句)
- break (终止 switch 或循环语句)
- switch (多分支选择语句)
- return (函数返回语句)
- goto (转向语句。极其不推荐使用!!)
5.1.2 函数调用语句
例如:printf("Hello World!\n");
就是一个函数调用语句。
5.1.3 表达式语句
一个表达式后面加上;
就变成了表达式语句。例如n = 10
是一个表达式,而n = 10;
就是一个表达式语句。相似的,i++
是一个表达式,而i++;
就是一个语句。
5.1.4 空语句
空语句就是一个单独的;
。空语句什么都不会做,但它就是一个语句。
5.1.5 复合语句
将若干条普通语句使用{}
括起来就变成了一条复合语句。例如下面就是一条复合语句:
{
int n = 10;
n++;
printf("%d", n);
}
5.2 赋值
5.2.1 案例
给定三角形三边长 a、b、c,求该三角形的面积。
已知海伦公式求三角形面积为:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6TcisfBv-1665324647762)(E:\Blog\source\images\76f5b6258a519c9f741d61fd85e001a3.svg+xml)],其中 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-md846SGa-1665324647762)(E:\Blog\source\images\bf9b283fa6a817d4465843a9355c4bb9.svg+xml)]
#include <stdio.h>
#include <math.h>
int main() {
double a, b, c, p, S;
a = 3.67;
b = 5.43;
c = 6.21;
p = (a + b + c) / 2;
S = sqrt(p * (p - a) * (p - b) * (p - c));
printf("三角形面积为:%f\n", S);
}
5.2.2 赋值运算符
赋值运算符的作用是将一个数据赋给一个变量。例如n = 10
的作用是将 10 这个常量赋给变量 n。
n = 1 + 2
作用是将 1 + 2 这个表达式的值赋给变量 n。
5.2.3 赋值运算符的变种
表达式 | 等价写法 |
---|---|
a += b | a = a + b |
a -= b | a = a - b |
a *= b | a = a * b |
a /= b | a = a / b |
a %= b | a = a % b |
5.2.4 赋值表达式
前面的语句分类里面我们知道,表达式语句由“表达式
+;
”构成。所以赋值语句也是赋值表达式加“;”组成,那何为赋值表达式呢?答:由赋值运算符将变量与表达式连接起来的式子称之为赋值表达式。
我们知道所有的表达式都是有值的,赋值表达式作为表达式的一员也是有值的,赋值表达式的值就是被赋值变量的值。例如赋值表达式n = 10
的值是 10。注意区分表达式的值与被赋值变量的值之间的不同,虽然两者值是相同的。
赋值表达式左侧应该是一个变量,右侧可以是变量、常量、表达式。当右侧还是一个赋值表达式的时候是什么情况呢?例如a = b = 5
,这完全等价于 a = (b = 5)
。逐步分析,这个表达式会先执行b = 5
,然后将其值赋给 a。
分析以下赋值表达式的含义:
表达式 | a, b, c 的值 | 表达式的值 |
---|---|---|
a = b = c = 5 | a = , b = , c = | 返回 a 的值, |
a = (b = 3) * (c = 4) | a = , b = , c = | 返回 a 的值, |
已知:a=3, b=4, c=5a += (b *= 2) / (c -= 3) | a = , b = , c = | 返回 a 的值, |
5.2.5 赋值时强转
对某变量赋值但值与变量的类型不匹配时,会发生赋值时强转。例如int n = 3.14;
可以看出,n 是 int 型,但赋值时却使用 3.14(double 型数据)为其赋值。此时会进行强转,相当于int n = (int) 3.14;
强转的规则上节讲过,会丢失精度。
5.2.6 定义变量时赋予初值
// 定义整型变量 a 时赋予初值 1
int a = 1;
// 定义整型变量 a、b、c 并为 b 赋予初值 2
int a, b = 2, c;
// 定义整型变量 a、b、c 并将初值都设为 1
int a = 1, b = 1, c = 1;
// 这是错误的,不符合语法的
int a = b = c = 1;
6. 输入和输出
输入和输出主要使用printf
和scanf
函数来操作,这两个函数都在stdio.h
头文件里声明,因此使用这两个函数的时候,一定记住要在文件开头导入这个头文件#include <stdio.h>
。
6.1 输出函数 printf
printf 函数的一般格式:printf(格式字符串, 输出列表)
其中,输出列表不是必须的。当格式字符串里没有占位符的时候,就可以省略输出列表;否则有多少占位符,输出列表里就得有多少元素。什么是占位符?
6.1.1 占位符案例
// 占位符都以 % 开头,下面的 %d 就是一个整型占位符。
// 输出时,会使用后面的 999 替换掉这个 %d,因此被称为占位符。
printf("一刀 %d", 999);
// 下面的例子有两个占位符,一个是整型 %d 占位符,一个是双精度浮点型 %lf 占位符
// 后面的数据按照顺序和前面的占位符对应起来,注意数据要和占位符类型对应起来。
printf("老铁%d,圆周率是:%lf", 666, 3.14159);
6.1.2 所有占位符
6.2 输入函数 scanf
scanf 函数的一般形式:scanf(格式字符串, 地址列表)
格式字符串和 printf 里面的是一样的,但是地址列表和输出列表就有极大不同了。地址列表里面可以是变量的地址,也可以是数组的首地址。scanf 函数也是在格式化字符串里使用占位符的方式来确定你输入的是什么类型的数据,占位符格式和上述差不多。
6.2.1 常用占位符
占位符 | 含义 |
---|---|
%c | 字符占位符 |
%d | 十进制整数占位符 |
%f | 单精度浮点型占位符 |
%lf | 双精度浮点型占位符 |
%s | 字符串占位符 |
6.2.2 输入函数小案例
-
整型、浮点型数据输入
int a, b; double d; // 要求输入两个整数,使用 a 和 b 来接收。 // 注意,这边 a 和 b 前面都有一个 &,这是取地址运算符。 // 输入的时候,格式要和格式字符串完全对应,所以我应当这样输入“a=10, b=99” scanf("a=%d, b=%d", &a, &b); // 输入样本:10, 3.14 scanf("%d, %lf", &a, &d); // 这是一种特殊情形,两个占位符放在一起 // 如果我们还是按照格式输入,那会有歧义,所以这种特殊情况,我们需要在两个数字间添加一个空格 scanf("%d%d", &a, &b); scanf("%d%lf", &a, &d);
2.字符型数据输入
char ch, ch2;
// 直接输入一个字符即可
scanf("%c", &ch);
// 按照格式,输入:ch=A
scanf("ch=%c", &ch);
// 按照格式输入:A B
scanf("%c %c", &ch, &ch2);
// 这个和上面不太一样,因为空格本身就是一个字符,不能擅自在两个字符之间加空格
// 又由于字符之间连着输入是不会有歧义的,所以直接输入而不加空格:AB
scanf("%c%c", &ch, &ch2);
6.3 字符输入输出函数
6.3.1 字符输出函数 putchar
一般形式:putchar(ch)
,其中 ch 是一个字符。可以是普通字符,也可以是转义字符。
// 输出 A 字符
// 等价于:printf("%c", 'A');
putchar('A');
// 输出一个换行符
putchar('\n');
6.3.2 字符输入函数 getchar
// 输入一个字符并存到 ch 里面
char ch = getchar();
6.4 小习题
6.4.2 输入 1 个小写字母,输出其大写字母形式。
#include <stdio.h>
int main() {
char c1,c2;
c1=getchar(); // 从键盘读入一个字母,赋值给字符变量c1
c2=c1-32; //求对应小写字母的ASCII码,放在字符变量c2中
putchar(c2); //输出c2的值
putchar('\n'); //输出换行
return 0;
}
#include <stdio.h>
int main() {
char c1,c2;
c1=getchar(); // 从键盘读入一个字母,赋值给字符变量c1
c2=c1-32; //求对应小写字母的ASCII码,放在字符变量c2中
printf("%c的大写字母为:%c\n",c1,c2); //输出c1 c2的值
return 0;
}
6.4.2 输入 1 个数字,输出对应字母形式。对应规则:0-A,1-B,……
#include <stdio.h>
int main() {
int n;
char c;
scanf("%d",&n);
c=n+65;
printf("%d-%c\n",n,c);
return 0;
}
6.4.3 键盘输入一个数 x,分别输出:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Wq81LGhU-1665324647764)(E:\Blog\source\images\ce28e65aec62bfb9ab16663f90e35407.svg+xml)]
关于 C 语言中各数学函数的使用参考:《附录》。对数函数的换底公式:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oQJM6wXb-1665324647764)(E:\Blog\source\images\06f247245f5a5440875ae7854699b6ee.svg+xml)]
#include <stdio.h>
#include<math.h>
int main() {
double x,a,b,c,d,e;
scanf("%lf",&x);
a=exp(x);
b=log(x);
c= (log10(x)/log10(x));
d= pow(x,x);
e= sqrt(x+1);
printf("a=%lf\n b=%lf\n c=%lf\n d=%lf\n e=%lf\n ",a,b,c,d,e);
return 0;
}
6.4.4 使用 getchar 函数读入一个字符存到 ch 里面,思考:
1.ch 这个变量可以定义为 int 还是 char?
2.如果要用字符形态输出 ch,有什么方法?ASCII 码形态呢?
3.char ch;与int ch;有何不同?
2.选择结构
2.2 if 语句
2.2.1 if 语句的一般形式
if (条件 1) 语句1;
else if (条件 2) 语句2;
...
else if (条件 n-1) 语句 n-1;
else 语句 n;
其中所有 else if 分支和 else 分支都可以省略。
2.2.2 案例体验
- 输入一个数 x,输出 f(x)。其中 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ox1jwphN-1665324647764)(E:\Blog\source\images\a7e6560a0698dc8c053697de6a5687b5.svg+xml)]
#include <stdio.h>
int main() {
int x;
scanf("%d",&x);
if(x<=0)
x=x*x;
else if(x>0)
x=x*x*x;
printf("x=%d\n",x);
return 0;
}
2.输入一个 1-100之间的整数,返回这个分数对应的等级。分数与等级的对应关系如下:
-
- 1-59:D
- 60-79:C
- 80-94:B
- 95-100:A
#include <stdio.h>
int main() {
int x;
scanf("%d",&x);
if(x>=1&&x<59)
printf("D\n");
else if(x>=60&&x<79)
printf("C\n");
else if(x>=80&&x<94)
printf("B\n");
else if(x>=95&&x<100)
printf("A\n");
return 0;
}
3.输入两个整数 a 和 b,若 a > b 则交换 a 与 b 的值,最后输出 a 和 b。
#include <stdio.h>
int main() {
int a,b,c;
scanf("%d%d",&a,&b);
if(a>b)
{
c=a; //大括号很重要 如果不加大括号,就没发判断 a<b的状态了
a=b;
b=c;
}
printf("a=%d b=%d\n",a,b);
return 0;
}
2.2.3 if 结构的嵌套
在 if
、else if
、else
语句里,可以继续嵌套 if 结构语句。
看一个例子:输入三个数a、b、c,输出其中的最大值。
/* 算法思想:通过两个数相比较,得出大的那个数然后再和第三个数进行比较 若大于第三个数则是最大值 若小于第三个数 则第三个数为最大值*/
#include <stdio.h>
int main() {
int a,b,c,max;
scanf("%d %d %d",&a,&b,&c);
if(a>b)
{
if(a>c)
max=a;
else
max=c;
}
else
{
if(b>c)
max=b;
else
max=c;
}
printf("max=%d\n",max);
return 0;
}
2.2.4 条件运算符
条件运算符的一般形式:表达式 1 ? 表达式 2 : 表达式 3 (三目运算)
运行流程:计算表达式 1 的值,若为真(非0),则返回表达式 2 的值,否则返回表达式 3 的值。
-
输入两个数 a、b,返回两者中较大的那一个数
#include <stdio.h> int main() { int a,b,max; scanf("%d %d",&a,&b); max=(a>b)?a:b; //注意括号一定要加 printf("最大的数为:%d\n",max); return 0; }
2.返回 a, b, c 里面最大值
#include <stdio.h>
int main() {
int a,b,c,max;
scanf("%d %d %d",&a,&b,&c);
max=(a>b)?a:b;
max = max>c?b:c;
printf("最大的数为:%d\n",max);
return 0;
}
3.输入一个字符,若它是大写字母就将其转换成对应的小写字母,否则不转换
#include <stdio.h>
int main() {
char ch,Mch;
scanf("%c",&ch);
(ch>='A'&&ch<='Z')?ch+=32:ch;
printf("转换后的字母为:%c\n",ch);
return 0;
}
2.3 多分支 switch
if 一般用于两个分支的选择结构,若是有多分支操作,你需要使用if、else if、else
的组合,这样的组合效率很低,原因后面说。此时 switch 应运而生,switch 一般形式:
switch(整型表达式) {
case 常量 1: 语句 1;
case 常量 2: 语句 2;
……
case 常量 n: 语句 n;
default: 语句 n + 1;
}
switch 语句中的表达值必须是一个整数,case 后面必须跟着不重复的常量。执行流程:设表达式的值为 n,从所有常量里找到与 n 值相等的那个 case,执行后面的语句;若找不到相等的值,就执行 default 后面的语句,若 default 语句被省略了,就啥都不执行。
注意点:假设,表达式的值等于常量 2 的值,那么程序不仅仅只执行语句 2,后面的所有语句都会执行,若是不想全部执行,那就需要在恰当的位置使用 break。
来个例子感受感受:
已知 A 对应 85-100分,B 对应 70-84 分,C 对应 60-69 分,D 对应 < 60分。要求输入分数的等级,输出对应分数范围。
#include <stdio.h>
int main() {
char grade;
scanf("%c",&grade);
switch(grade)
{
case 'A': printf("85~100\n");break;
case 'B': printf("70~84\n");break;
case 'C': printf("60~69\n");break;
case 'D': printf("小于60\n");break;
default : printf("输入数据错误!\n");
}
return 0;
}
2.4.1 设 a = 3, b = 4, c = 5,求下列逻辑表达式的值
a + b > c && b == c
0a || b + c && b - c
1!(a > b) && !c || 1
0!(x=a) && (y=b) && 0
0 (遇到逻辑运算符需要先在逻辑运算两边的表达式先加上括号)!(a + b) + c - 1 && b + c / 2
1
2.4.2 表达式类型的题
- 已知
i = 1, j = 2, k = 3
,则执行完代码int m = i-- && j++ || k--;
之后,各变量的值分别为i = , j = , k = , m =
。 - 已知
i = j = k = 1
,则执行完代码int m = ++i || ++j && ++k;
之后,各变量的值分别为i = , j = , k = , m =
- 已知
int m = 1, n = 2;
则表达式++m == n
的值为: - 已知
x = 43, y = 0, c = 'a'
则表达式x >= y && c <= 'b' && !y
的值为:
2.4.3 判断一个数是否是完全平方数
2.4.4 给一个百分制数,输出该分数对应的等级
条件:90 分及以上为 A,80~89 为 B,70~79 为 C,60~69为 D,其余为 E
/* 使用 if 分支写 */
#include <stdio.h>
int main() {
int score;
char grade;
scanf("%d", &score);
if (score <= 59) grade = 'E';
else if (score <= 69) grade = 'D';
else if (score <= 79) grade = 'C';
else if (score <= 89) grade = 'B';
else grade = 'A';
putchar(grade);
return 0;
}
/*使用switch写*/
2.4.5 输入一个年份和月份 year、month,判断该年是不是闰年,该月有多少天
2.4.6 输入三条边长,判断这三条边能构成:等腰三角形、等边三角形、直角三角形、不是三角形
2.4.7 水仙花数
对于一个三位数 n,设 a, b, c 是其百位、十位、个位数,若 a3 + b3 + c3 = n 则称 n 为水仙花数。
键盘输入一个三位正整数,判断 n 是否是水仙花数。
3.循环结构
3.1while 循环
3.1.1 引言
循环结构是很常用的一个结构。有很多案例,例如:键盘输入 50 个数字代表一个班级学生的成绩。我们可以使用scanf
语句来获取键盘输入,但现在要输入 50 个数字,难道要使用 50 次 scanf
?那遇到 500 次、5000 次呢?
理智分析我们可以发现,对于录入分数这个操作,我们都是使用scanf
操作。既然操作都是一样的,我们就没必要反复写一样的代码了。
while 循环的一般形式:
// 只有条件为“真”才会执行循环体内容
while (条件) {
循环体语句;
}
3.1.2 小习题
使用循环求解 1 + 2 + 3 + ……+ 1000
#include <stdio.h>
int main() {
int sum=0,i=1;
while(i<=1000){
sum+=i;
i++;
}
printf("sum=%d\n",sum);
return 0;
}
3.2 do…while 循环
3.2.1 引言
do…while 循环是先做再看条件的循环,是《第 2 节算法》里面的的直到型循环的一类。其一般形式为:
/*
代码自上而下先执行循环体内容,然后再去判断条件是否满足。
满足条件,继续执行循环体……直到某一次条件不满足,退出循环。
*/
do {
循环体;
} while(条件);
3.2.2 梅开二度
使用 do…while 循环实现 1000 内数字的求和
#include <stdio.h>
int main() {
int sum=0,i=1;
do{
sum+=i;
i++;
}while(i<=1000);
printf("sum=%d\n",sum);
return 0;
}
3.2.3 对比 while 和 do…while
相同点:两者都是循环语句
不同点:while 语句的循环体部分可能一次都不执行;do…while 循环体部分最少执行一次。
案例:《谭》P115
3.3 for 循环
3.3.1 引言
for 循环的一般形式是:
for (初始化表达式; 循环条件; 变量修改表达式) {
循环体语句;
}
for (; ; ) {
循环体语句;
}
3.3.2 小案例
- 使用 for 循环求 1000 以内数字的和
#include <stdio.h>
int main() {
int sum=0,i=1;
for(i=1;i<100;i++){
sum+=i;
}
printf("sum=%d\n",sum);
return 0;
}
2.从键盘读取字符并输出这个字符直到遇到换行符
//可以使用while和for来写
char ch;
while((ch = getchar()) != '\n') putchar(ch);
for(; (ch= getchar()) != '\n'); putchar(ch)
3.输入一个数 n,输出其满足角谷猜想的角谷路径。
所谓角谷猜想是指,对任意正整数执行若干次[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5QKgCq3h-1665324647765)(E:\Blog\source\images\d20f3c7aace6efc568d7144830d7e6b0.svg+xml)]总会得到结果 1。
4.键盘输入一行字符(以换行结尾),统计字符串中数字、字母、空格出现的次数
3.3 for 循环
3.3.1 引言
for 循环的一般形式是:
for (初始化表达式; 循环条件; 变量修改表达式) {
循环体语句;
}
for (; ; ) {
循环体语句;
}
3.3.2 小案例
- 使用 for 循环求 1000 以内数字的和
#include <stdio.h>
int main() {
int sum=0,i=1;
for(i=1;i<100;i++){
sum+=i;
}
printf("sum=%d\n",sum);
return 0;
}
2.从键盘读取字符并输出这个字符直到遇到换行符
//可以使用while和for来写
char ch;
while((ch = getchar()) != '\n') putchar(ch);
for(; (ch= getchar()) != '\n'); putchar(ch)
3.输入一个数 n,输出其满足角谷猜想的角谷路径。
所谓角谷猜想是指,对任意正整数执行若干次[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rJir2Zuo-1665324647766)(E:\Blog\source\images\d20f3c7aace6efc568d7144830d7e6b0.svg+xml)]总会得到结果 1。
4.键盘输入一行字符(以换行结尾),统计字符串中数字、字母、空格出现的次数
3.4 重循环(循环的嵌套)
重循环也叫循环嵌套,即在一个循环体语句里面包含另一个循环语句。
3种循环(while循环、do…while循环和for循环)可以互相嵌套。
案例:输出如下矩阵
1 2 3 4 5
2 4 6 8 10
3 6 9 12 15
4 8 12 16 20
#include<stdio.h>
int main(){
int i,j,n=0;
for(i=1;i<=4;i++)
for(j=1;j<=5;j++,n++) //n用来累计输出数据的个数
{
if(n%5==0) //控制在输出5个数据后换行
printf("\n");
printf("%d\t",i*j);
}
printf("\n");
return 0;
}
3.5 循环控制
3.5.1 break
在循环或者 switch 语句中,使用 break 语句可以跳出循环或 switch 语句。这主要用于提前结束循环或者作为循环出口使用。
案例:在全校 1000 个学生中进行募捐,当 1000 个同学都捐完或捐款总额达到 10000元 的时候停止募捐。
#include <stdio.h>
#define SUM 100000 //指定符号常量SUM代表100000
int main()
{
float amount,total;
int i;
for(i=1,total=0;i<=1000;i++)
{
printf("请您输入捐款的金额:");
scanf("f%",&amount);
total=total+amount;
if(total>=SUM)
break;
}
printf("本次捐款人数为:%d\n",i);
return 0;
}
3.5.2 continue
continue 作用于循环中,跳过后面未被执行的循环体语句。
案例:输出 100 ~ 200 之间所有不能被 3 整除的数
#include <stdio.h>
int main()
{
int i;
for(i=100;i<=200;i++)
{
if(i%3 == 0)
continue;
printf("num=%d\t",i);
}
return 0;
}
3.5.3 break 和 continue 区别
观察如下两种循环结构,分析执行流程
while (表达式1) {
语句1;
if (表达式2) break;
语句2;
}
- 若“表达式1”值为真,进入循环体
- 执行“语句1”
- 若“表达式2”值为真,执行 break 退出循环
- 否则走正常流程
while (表达式1) {
语句1;
if (表达式2) continue;
语句2;
}
- 若“表达式1”值为真,进入循环体
- 执行“语句1”
- 若“表达式2”值为真,执行 continue 结束本次循环,直接到达“表达式1”处
- 否则走正常流程
3.6习题
3.6.1 按照下面的格式输出乘法表
1 * 1 = 1
1 * 2 = 2 2 * 2 = 4
...
1 * 9 = 9 2 * 9 = 18 ... 9 * 9 = 81
3.6.2 输入 10 个数,输出其中的最大值
#include<stdio.h>
int main(){
int n,max=0;
for(int i;i<5;i++)
{
scanf("%d",&n);
if(n>max)
max=n;
}
printf("%d",max);
return 0;
}
3.6.3 求 π 的近似值
已知:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LHWGTkYq-1665324647766)(E:\Blog\source\images\1113836e8d5eb0a6c3a79226d7332138.svg+xml)]当公式中某一项绝对值小于 10-6为止。
3.6.4 输入正整数 n,判断其是否是素数
3.6.5 输出斐波那契数列前20项
已知,满足条件[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-va5x89qM-1665324647767)(E:\Blog\source\images\2b6b32b05b12c1a6f07f8a1c7e9a07ce.svg+xml)]的数列叫做斐波那契数列。
3.6.6 输入一个正整数 n,输出其反序数
例如 123 的反序数是 321,100 的反序数是 1。
3.6.7 密文
输入一行字符(以换行结尾),对于串中的英文字母(包含大写和小写字母)做后移 4 位操作,得到一个新串并输出。
后移 4 位操作是指A -> E, b -> f, W -> A, z -> d
3.6.8 按照如下规律输出图案