📘 C语言学习笔记
1. 计算机与编程语言 🖥️
一.
- 程序是用特殊的编程语言表达了如何解决问题的
- 不是用编程语言来和计算机交谈,而是描述要求它如何做事情的过程或方法
二. 算法
- 我们要让计算机做计算,就需要像这样找出计算的步骤,然后用编程语言写出来
- 计算机做的所有的事情都叫做计算
- 计算的步骤就是算法
2. 计算机的思维方式 🧠
Shutterstock探索
一. 程序的执行
- 解释:借助一个程序,那个程序能试图理解你的程序,然后按照你的要求执行
- 编译:借助一个程序,就像一个翻译,把你的程序翻译成计算机真正能懂的语言--机器语言--写的程序,然后这个机器语言写的传给你就能直接执行了
3. 为什么是C语言 ❓
一. 其他语言
- 现代的变成语言在语法上的差异很小
- 几乎都是C-like语言
- 语言的能力/适用领域主要是由库和传统所决定的
4. C语言的简史 📜
一.
- C语言是从B语言发展而来的,B语言是从BCPL发展而来的,BCPL是从FORTRAN发展而来的
- BCPL和B都支持指针间接方式,所以C也支持了
- C语言还收到了PL/I的影响,还和PDP-II的机器圆有很大的关系
- 1973年3月,第三版的Unix上出现了C语言的编译器
- 1973年11月,第四版的Unix(System Four)发布了,这个版本是完全用C语言重新编写的
二. C的发展与版本
- 经典C
- 又被叫做"K&R the C"
三. C的发展与版本-标准
- 1989年ANSI发布了一个标准--ANSI C
- 1990你那ISO接受了ANSI的标准--C89
- C的标准在1995年和1999年两次更新--C95和C99
5. 编程软件 🛠️
一. C语言是一种工业语言
- 操作系统:开发效率 >> 学习过程
- 嵌入式系统:开发效率 >> 开发乐趣
- 驱动程序:日常应用很少直接用C语言编写
- 底层驱动:学习C的过程主要是练习写代码
- 图形引擎、图像处理、声音效果:而非真是软件
二. 编译-→运行
- C需要被编译才能运行,所以你需要:
- 编辑器
- 编译器
- 或者,IDE(集成开发环境)
三. 推荐的编程软件
- Dev C++
- 免费
- 安装简单
- 不用建工程
6. 第一个C程序 🐣
一. 代码示例
C
二. 程序的主干
C
- 本课程中所有的程序都需要这一段,直到学到函数之前,我们的代码都只是在这个框架中间
三. 输出
pirntf("Hello World!\n");""里面的内容叫做“字符串”,printf会把其中的内容原封不动地输出\n表示需要在输出的结果后面换一行
四. 程序中的错误
- 编译的时候发现的错误所在的地方会以红色的底标示出来
- 具体的错误原因列在下方的窗口里(是英文的)
- C的编译器给出的错误提示往往不那么好“猜”
五. 不要用中文
7. 做点计算 ➕
一.
printf("%d\n",23+43);%d说明后面有一个整数要输出在这个位置上printf("23+43=%d\n",23+43);
二. 四则运算
| 四则运算 | C符号 | 意义 |
|---|---|---|
| + | + | 加 |
| - | - | 减 |
| × | × | 乘 |
| ÷ | / | 除 |
| % | 取余 | |
| () | () | 括号 |
%表示取两个数相除以后的余数
8. 变量定义 📦
一. 如何输入
- 输入也在终端窗口中
- 输入是以行为单位进行的,行的结束标志就是你按下了回车键。在你按下回车之前,你的程序不会读到任何东西
二. 变量
int price =0;- 这一行定义了一个变量,变量的名字是price,类型是int,初始值是0。
- 变量是一个保存数据的地方,当我们需要在程序里保存数据时,比如上面的例子中要记录用户输入的价格,就需要一个变量来保存它。用一个变量保存了数据,它才能参加到后面的计算中,比如计算找零
三. 变量定义
- 变量定义的一般形式就是:
类型名称 变量名称; int price;
四. 变量的名字
- 变量需要一个名字,变量的名字是一种“标识符”,意思是它是用来识别不同的名字
- 标识符有标识符的构造规则。基本的原则是:标识符只能由字母、数字和下划线组成,数字不可以在第一个位置上,C语言的关键字(有的地方叫它们保留字),不可以用做标识符
五. C语言的关键字
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,union,unsigned,void,while。不需要背诵
9. 变量赋值和初始化 📥
一.
int price=0;- 这一行,定义了一个变量,变量的名字是price,类型是int,初始值是0.
price=0是一个式子,这里的“=”是一个赋值运算符,表示将“=”右边的值赋给左边的变量
二. 赋值
- 和数学不同,
a=b在数学中表示关系,即a和b的值一样;而在程序设计中,a=b表示要求计算机做一个动作:将b的值赋个a。关系是静态的,而动作是动态的。在数学中,a=b和b=a是等价的,而在程序设计中,两者的意思完全相反。
三. 初始化
- 虽然C语言并没有强制要求所有的变量都在定义的地方做初始化,但是所有的变量在第一次被使用(出现在赋值运算符的右边)之前被应该赋值一次。如果没有被赋初值,那么它的内存中有啥就表示啥
四. 变量初始化
类型名称 变量名称 =初始值int price =0;- 组合变量定义的时候,也可以在这个定义中单独给变量赋初值
五. 表达式
- “=”是赋值运算符,有运算符的式子就叫做表达式
六. 变量类型
int price=0;- 这一行,定义了一个变量。变量的名字是price,类型是int,初始值是0
- C是一种有类型的语言,所有的变量在使用之前必须定义或声明,所有的变量必须具有确定的数据类型。数据类型表示在变量中可以存放什么样的数据,变量中只能存放指定类型的数据,程序运行过程中也不能改变变量的类型
七. 第二个变量
int change =100-price;- 定义了第二个变量change
- 并且做了计算
- C99版本可以在任意地方定义变量,ANSI C只能在代码开头的地方定义变量
八. 读整数
scanf("%d",&price);- 要求scanf这个函数读入下一个整数,读到的结果赋值给变量price
- 小心price前面的
&
10. 常量与变量 💎
一. 常量
int change = 100 -price;- 固定不变的数,是常数。直接写在程序里,我们称作直接量
- 更好的方式,是定义一个常量
const int AMOUNT=100;
二. const
- const是一个修饰符,加在int的前面,用来给这个变量加上一个const(不变的)的属性。这个const的属性表示这个变量的值一旦初始化,就不能修改了
int change=AMOUNT-price;- 如果你试图对常量做修改,把它放在赋值运算符的左边,就会被编译器发现,指出为一个错误
三. try
- 让用户输入变量AMOUNT的值,而不是使用固定的初始值
- 这个变量在哪里定义合适呢
11. 关于scanf ⌨️
一.
C
- 结果为a,0(如果没有按照双引号内的格式输入,scanf会出错)(scanf的引号里面是用户一定要输入的东西)
12. 浮点数 🌊
一. 计算身高的程序
C
printf("请分别输入身高的英尺和英寸,""如输入\5"5 7\"表示5英尺7英寸:");
int foot;
int inch;
scanf("%d %d",&foot, &inch);
printf("身高是%f米。\n",((foot+inch/12)*0.3048));
- 错误原因:因为两个整数的运算的结果只能是整数
- 10和10.0在C中是完全不同的数
- 10.0是浮点数
二.
- 带小数点的数值。浮点这个词的本意就是指小数点是浮动的,是计算机内部表达非整数(包含分数和无理数)的一种方式
三.
- 当浮点数和整数放到一起运算时,C会将整数转换成浮点数,然后进行浮点数的运算
四. double
- inch是定义为int类型的变量,如果把int换成double,我们就把它改为double类型的浮点数变量了
- 除了double,还有float(表示单精度浮点数)
五. 数据类型
- 整数:
int,printf("%d"),scanf("%d") - 带小数点的数:
double,printf("%f"),scanf("%lf")
13. 表达式 🧮
一. 表达式
- 一个表达式是一系列运算符和算子的组合,用来计算一个值
二. 运算符
- 运算符是指进行运算的值,这个值可能是常数,也可能是变量,还可能是一个方法的返回值
三. 计算时间差
C
int hour1, minute1;
int hour2, minute2;
scanf("%d %d",&hour1,&minute1);
scanf("%d %d",&hour2,&minute2);
int t1=hour1 * 60 +minute1;
int t2=hour2 * 60 + minute2;
int t=t2-t1;
printf("时间差是%d小时%d分",t/60,t%60);
14. 运算符的优先级 🔝
一. 求平均值
- 写一个程序,输入两个整数,输出他们的平均值
C
二. 赋值运算符
- 赋值也是运算,也有结果
a=6的结果是a被赋予的值,也就是6a=b=6-→a=(b=6)
三. 嵌入式赋值
四. 结合关系
- 一般自左向右
- 单目
+-和赋值=自右向左
15. 交换两个变量 🔄
一. 程序是按步执行的
- 程序表达的是顺序执行的动作,而不是关系
a=b,b=a是依次执行的,结果使得a和b都得到b原来的值
二. 交换
C
16. 复合赋值 🔗
一.
- 5个算术运算符.+ - * / %,可以和赋值运算符“=”结合起来,形成复合赋值运算符:“+=”、“-=”、“*=”、“/=”、和“%=”
total+=5;->total=total+5;- 注意两个运算符中间不要有空格
total*=sum+12;->total=total*(sum+12);
二. 递增递减运算符
- “++”和“--”是两个很特殊的运算符,他们是单目运算符,这个算子还必须是变量。这两个运算符分别叫做递增和递减运算符,他们的作用就是给这个变量+1或者-1
count++;,count+=1;,count=count+1;
三. 前缀后缀
- ++和--可以放在变量的前面,叫做前缀形式,也可以放在变量的后面,叫做后缀形式
a++的值是a加1以前的值,而++a的值是加了1以后的值,无论哪个,a自己的值都加了1
总结:
| 表达式 | 运算 | 表达式的值 |
|---|---|---|
count++ | 给count加1 | count原来的值 |
++count | 给count加1 | count+1以后的值 |
count-- | 给count减1 | count原来的值 |
--count | 给count减1 | count-1以后的值 |
四. ++ --
- 这两个运算符有其历史来源
- 可以单独使用,但是不要组合进表达式
17. 做判断 ⚖️
一. 如果
C
二. 条件
- 计算两个值之间的关系,所以叫做关系运算
| 运算符 | 意义 |
|---|---|
| == | 相等 |
| != | 不等于 |
| > | 大于 |
| >= | 大于或等于 |
| < | 小于 |
| <= | 小于或等于 |
三. 关系运算的结果
- 当两个值的关系复合关系运算符的预期时,关系运算的结果为整数1,否则为整数0(只有这两种值)
printf("%d\n",5==3);
四. 优先级
- 所有的关系运算符的优先级比算术运算的低,但是比赋值运算高
7>=3+4- 判断是否相等的==和!=的优先级和其他的低,而连续的关系运算是从左到右进行的
18. 找零计算器 💰
一.
- 找零计算器需要用户做两个操作:输入购买的金额,输入支付的票面,而找零计算器则根据用户的输入做出相应的动作:计算并打印找零,或告知用户月不足以购买
- 从计算机程序的角度看,这就是意味着程序需要读用户的两个输入,然后进行一些计算和判断,最后输出结果
二. 找零计算器
C
//初始化
int price =0;
int bill=0;
//输入金额和票面
printf("请输入金额");
scanf("%d",&price);
print("请输入票面");
scanf("%d",&bill);
//计算找零
printf("应该找您:%d\n",bill-price);
三. 注释
- 以两个斜杠
//开头的语句分成了三个部分:1.初始化 2.读入金额和票面 3.计算并打印找零 - 注释插入在程序代码中,用来向读者提供解释信息。他们对于程序的功能没有任何影响,但是往往能使得程序更容易被人类读者理解
/**/注释:延续数行的注释,要用多行注释的格式来写。多行注释由一堆字符序列/*开始,而已*/结束- 也可以用于一行内的注释
int ak=47/*36*/,y=9;
四. 判断票面够不够
C
五. 不够怎么办?
else
19. if语句再探 🔍
一.
- 一个基本的if语句由一个关键字if开头,跟上在括号里的一个表示条件的逻辑表达式,然后是一对大括号“{}”之间的若干条语句。如果表示条件的逻辑表达式的结果不是零,那么就执行后面跟着的这对大括号中的语句,否则就跳过这些语句不执行,而继续下面的其他语句
C
- if语句这一行结束的时候并没有表示语句结束的“;”,而后的赋值语句写在if的下一行,并且缩进了,在这一行结束的时候有一个表示语句结束的“;”。这表明这套赋值语句是if语句的一部分,if语句拥有和控制这条赋值语句,决定它是否要被执行
20. 嵌套的if-else 🖇️
一. else的匹配
- else总是和最近的那个if匹配
二. 缩进
- 缩进格式不能暗示else的匹配
C
三. 嵌套的if
C
四. tips
- 在if或else后面总是用{}
21. 级联的if-else 🪜
一. 分段函数
二. if - else if
C
- 单一出口,尽量不要把代码写死
22. 多路分支switch-case语句 🛣️
一. switch - case
C
- 注意:控制表达式只能是整数型的结果
- 常量可以是常数,也可以是常数计算的表达式
二. break
- switch语句可以看做是一种基于计算的跳转,计算控制表达式的值后,程序会跳转到相匹配的case(分支标号)出。分支标号知识说明switch内部位置的路标,在执行完分支中的最后一条语句后,如果后面没有break,就会顺序执行到下面的case里去,直到遇到一个break,或者switch结束位置(case不会阻止语句的执行)
三. 成绩转换
- 可以想到用十位数来进行switch-case的流程控制
四. try
- f(x)=-1;x<0
- 0;x=0
- 2x;x>0
- 这个分段函数能否用switch-case?
23. 循环 🔄
一. 数数几位数
- 程序要读入一个4位以下(含4位)的正整数,然后输出这个整数的位数。
- 人VS计算机
二. 程序实现
C
int x;
int n=1;
scanf("%d",%x);
if(x>999){
n=4;
}
else if(x>99){
n=3;
}
else if(x>9){
n=2;
}
else{
n=1;
}
printf("%d",n);
- 因为题目明确了4位数及以下的正整数,所以可以简化一些判断
三. 换个方式想
- 352->3很快。1234251235151512341234是几位?数数!
- 人怎么数?从左往右数,一次划掉一个数字。计算机怎么划掉那个数字?
四. 三位数逆序的题
- 不断地划,直到没数可以划... 在这个过程中计数
五. 试试代码
C
24. while循环 🔁
一.
- 如果我们把while翻译作“当”,那么一个while循环的意思就是:当条件满足时,不断地重复循环体内的语句
- 循环执行之前判断是否继续循环,所以有可能循环一次也没有被执行
- 条件成立是循环继续的条件
二. 看程序运行结果
- 人脑模拟计算机的运行,在纸上列出所有的变量,随着程序的进展不断重新计算变量的值。当程序运行结束时,留在表格最下面的就是程序的最终结果
三. 验证
- 测试程序常使用边界数据,如有效范围两端的数据、特殊的倍数等
- 个位数; 10; 0; 负数。
- 在程序适当的地方插入printf来输出变量的内容
25. do-while循环 ↪️
一. 数位数的算法
- 用户输入x;
- 初始化n为0;
- x=x/10,去掉个位
- n++;
- 如果x>0,回到3;
- 否则n就是结果
二. do-while循环
- 在进入循环的时候不做检查,而是在执行完一轮循环体的代码之后,再来检查循环的条件是否满足,如果满足则继续下一轮循环,不满足则结束循环
C
三. 两种循环
- do-whlie循环和while循环很像,区别是在循环体执行结束的时候才来判断条件。也就是说,无论如何,循环都会执行至少一遍,然后再来判断条件。与while循环相同的是,条件满足时执行循环,条件不满足时结束循环
26. 猜数游戏 🎲
一. 思路
- 让计算机来想一个数,然后让用户来猜,用户每输入一个数,就告诉它是大了还是小了,直到用户猜中为止,最后还要告诉用户它采了多少次
- 因为需要不断重复让用户猜,所以需要用到循环
- 核心重点是循环的条件
二. 步骤
- 计算机随机想一个数,记在变量number里
- 一个负责计次数count初始化为0
- 让用户输入一个数字a;
- count递增(加一)
- 判断a和count的大小关系,如果a大,就输出“大”,如果a小就输出“小”
- 如果a和number是不相等的(无论大还是小),程序转回到第3步
- 否则,程序输出“猜中”和次数,然后结束
三. 随机数
- 每次召唤rand()就得到一个随机的整数
C
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
int main(){
srand(time(0));
int a=rand();
printf("%d\n",a);
return 0;
}
四. %100
- x%n的结果是[0,n-1]的一个整数
五. 完整代码示例
C
srand(time(0));
int number =rand()%100+1;
int count =0;
int a = 0;
printf("我已经想好了一个1到100之间的数。");
do{
printd("请猜这个1到100之间的数:");
scanf("%d",&a);
count ++;
if (a > number){
printf("你猜的数大了");
}
else if (a < number){
printf("你猜的数小了");
}
}while (a!=number);
printf("太好了,你用了%d次就猜到了答案。\n",count);
27. 算平均数 📏
一.
- 让用户输入一系列的正整数,最后输入-1表示输入结束,然后程序计算出这些数字的平均数,输出输入的数字的个数和平均数
- 变量->算法->流程图->程序
二. 变量
- 一个记录读到的整数的变量
- 平均数要怎么算?只需要每读到一个数,就把它加到一个累加的变量里,到全部数据读完,再拿它去除读到的数的个数就可以了
- 一个变量记录累加的结果,一个变量记录读到的数的个数
三. 算法与示例
C
#include<stdio.h>
int main(){
int number;
int sum=0;
int count=0;
scanf("%d",&number);
while(number!=-1){
sum+=number;
count++;
scanf("%d",&number);
}
printf("%f\n",1.0*sum/count);
return 0;
}
28. 整数求逆 ↩️
一. 整数的分解
- 对一个整数做%10的操作,就得到它的个位数
- 对一个整数做/10的操作,就去掉了它的个位数
- 然后再对2的结果做%10,就得到原来数的十位数了
二. 数的逆序
C
#include<stdio.h>
int main(){
int x;
// scanf("%d",&x);
x=700;
int digit;
int ret=0;
while(x>0){
digit=x%10;
// printf("%d",digit);
ret=ret*10+digit;
printf("x=%d,digit=%d,ret=%d\n",x,digit,ret);
x/=10;
}
printf("%d",ret);
return 0;
}
29. for 循环 🔢
一. 阶乘
n!=1x2x3x...xn
C
int n;
scanf("%d",&n);
int fact=1;
int i =1;
for (i=1;i<=n;i++){
fact*=i;
}
printf("%d!=%d\n",n,fact);
二. for循环
- for循环像一个计数循环:设定一个计数器,初始化它,然后在计数器到某值之前,重复执行循环体,而每执行一轮循环,计数器值以一定步骤b变化,比如加1或者减1
C
三. for = 对于
for(count=10;count>0;count--)就读成:“对于一开始的count=10,当count>0时,重复做循环体,每一轮循环在经过循环体内的语句后,使得count--”
四. 小套路
- 做求和的程序时,记录结果的变量应该初始化为0,而做求积的变量时,记录结果的变量应该初始化为1
- 循环控制变量i只在循环里被使用了,循环外面它没有任何用处。因此,我们可以把变量i的定义写到for语句里面去
五. try
- 除了可以从1乘到n来计算n!,还可以从n乘到1来计算吧?试试把循环换个方向来计算n。这时候,还需要循环控制变量i吗?
C
int n;
scanf("%d",&n);
int fact=1;
int i=1;
for (i=n;n>1;n--){
fact*=n;
}
printf("%d!==%d\n",i,fact);
30. 循环的计算和选择 ⚙️
一. 循环次数
for(i=0;i<n;i++)则循环的次数是n,而循环结束以后,i的值是n
二. for循环
for(初始动作;条件;每轮的动作){}- for中的每一个表达式都是可以省略的
for(;条件;)==while(条件)
三. tips for loops
- 如果有固定次数,用for
- 如果必须执行一次,用do_while
- 其他情况用while
31. 循环控制:break和continue 🛑
一. 素数
- 只能被1和自己整除的数,不包括1
C
#include<stdio.h>
int main(){
int x;
scanf("%d",&x);
int i;
int isPrime=1; //x是素数
for (i=2;i<x;i++){
if(x%i==0){
isPrime=0;
break;
}
}
if (isPrime==1){
printf("是素数\n");
}
else{
printf("不是素数\n");
}
return 0;
}
二. break vs continue
- break:跳出循环
- continue: 跳过循环这一轮剩下的语句进入下一轮
32. 循环嵌套 🪆
一. 100以内的素数
- 如何写程序输出100以内的素数?
二. 嵌套的循环
- 循环里面还是循环
三. 凑硬币
- 如何用1角、2角和5角的硬币凑出10元以下的金额呢?
- break和continue只能对它所在的那层循环做
- 跳出所有循环可以使用接力break
C
int x;
int one,two,five;
int exit=0;
scanf("%d",&x);
for (one=1;one <x*10;one++){
for (two=1;two<x*10/2;two++){
for (five=1;five<x*10/5;five++){
if (one+two*2+five*5==x*10){
printf("可以用%d个1角加%d个2角加%d个5角得到%d元\n",one,two,five,x);
exit=1;
break;
}
}
if(exit==1)break;
}
if(exit==1)break;
}
四. goto
- 最好在最内层跳到外层时才用,不然最好不要用(破坏代码的结构性)
33. 前n项求和 ➕
一.
C
int n;
int i;
double sum=0.0;
scanf("%d",&n);
for (i=1;i<=n;i++){
sum+=1.0/i;
}
printf("f(%d)=%f\n",n,sum);
二. 加减交替
sign=-sign;
34. 正序分解整数 🔢
一.
- 输入一个非负整数,正序输出它的每一位数字。输入:13425,输出:1 3 4 2 5
二. 格式化
- 怎么解决最后一个数据后面有带空格呢?使用if判断
三.
- 1.先逆序再正序
- 2.使用求余和整除的方法
- 3.改进的代码 (处理末尾为0的数字)
35. 求最大公约数 ➗
一.
- 输入两个数a和b,输出他们的最大公约数
二. 枚举
- 设t为2;如果u和v都能被t整除,则记下这个t;t加1后重复,直到t等于u或v
三. 辗转相除法
- 如果b等于0,计算结束,a就是最大公约数;
- 否则,计算a除以b的余数,让a等于b,而b等于那个余数;
- 回到第一步
C
46. 编程练习解析 📝
一. 求复合给定条件的整数集
- 给定不超过6的正整数A,考虑从A开始的连续4个数字,请输出所有由他们组成的无重复数字的3位数
二. 水仙花数(20)
- 水仙花数是指一个N位正整数(N>=3),它的每个位上的数字的N次幂之和等于它本身。
三. 打印九九口诀表
- 输出下三角N*N部分口诀表
四. 统计素数并求和
- 统计给定整数M和N区间内素数的个数并对他们求和
五. 猜数字游戏
- 自动对其与随机产生的被猜数进行比较,并提示大了还是小了,根据猜测次数输出不同提示
六. 求序列前N项和
- 计算序列2/1+3/2+5/3+8/5+...的前N项之和
七. 约分最简分式
- 要求用户输入一个分数,然后将其约分为最简分式
八. 念数字
- 输入一个整数,输出每个数字对应的拼音
九. 求a的连续和
- 求数列之和S=a+aa+aaa+...+aaa...a(n个a)
47. 数据类型 🗂️
一. C是有类型的语言
- C语言的变量,必须:在使用之前定义,并且确定类型
二. 类型安全
- 早期语言强调类型,面向底层的语言强调类型
- C语言需要类型,但是对类型的安全检查并不足够
三. C语言的类型
- 整数:
char、short、int、long、long long - 浮点数:
float、double、long double - 逻辑:
bool - 指针
- 自定义类型
四. 类型有何不同
- 类型名称、输入输出格式、表达范围、占据大小、内存表达形式
五. sizeof
- 是一个运算符,给出某个类型或边浪在内存中所占据的字节数
sizeof(int)- 是静态运算符,它的结果在编译时刻就决定了
48. 整数类型 📏
一.
- short是2个字节
- long是8个字节
- long long也是8个字节
二.
- char: 1字节(8比特(bit))
- short: 2字节
- int: 取决于编译器(CPU),通常的意义是“1个字”
49. 整数的内部表达 🤖
一.
- 计算机内部一切都是二进制
二. 如何表示负数
- 十进制用'-'来表示负数,在做计算的时候
三. 二进制负数
- 补码: 考虑-1,我们希望-1+1->0。
- 11111111被当作纯二进制看待时,是255,被当作补码看待时是-1
- 补码的意义就是拿补码和原码可以加出一个溢出的“零”
50. 整数的范围 📉
一. 数的范围
- 对于一个字节(8位),可以表达的是: 00000000-11111111
二.
char: 1字节:-128~-127short: 2字节:-32768~32767
三. unsigned
- 如果一个自变量常熟想要表达自己是unsigned,可以在后面加u或U
- unsigned的初衷并非扩展数能表达的范围,而是为了做纯二进制运算,主要是为了移位
四. 整数越界
- 整数是以纯二进制方式进行计算的
11111111+1->100000000->0
50. 整数的格式化输出 🖨️
一. 整数的输入输出
- 只有两种形式:int或long long
%d: int,%u: unsigned,%ld: long long,%lu: unsigned long long
二. 8进制和16进制
- 一个以0开始的数字字面量是8进制,
%o - 一个以0x开始的数字字面量是16进制,
%x
51. 浮点类型 ☁️
一.
| 类型 | 字长 | 范围 | 有效数字 |
|---|---|---|---|
| float | 32 | 7 | |
| double | 64 | 15 |
二. 浮点的输入输出
| 类型 | scanf | printf |
|---|---|---|
| float | %f | %f,%e |
| double | %lf | %f,%e |
52. 浮点的范围与精度 🎯
一. 超过范围的浮点数
inf: 无穷nan: 不存在的浮点数
四. 选择浮点类型
- 如果没有特殊需要,只使用double
53. 字符类型 🅰️
一. 字符类型
- char是一种整数,也是一种特殊的类型:字符
printf和scanf里用%c来输入输出字符
二. 字符的输入输出
- '1'的ASCII编码是49
四. 字符计算
- 一个字符加一个数字得到ASCII码表中那个数之后的字符
- 两个字符的减,得到他们在表中的距离
五. 大写字母和小写字母
a+'A'-'a'可以把一个大写字母变成小写字母
54. 逃逸字符 🏃
一. 逃逸字符
- 用来表达无法印出来的控制字符或特殊字符,它由一个反斜杠
\开头
| 字符 | 意义 | 字符 | 意义 |
|---|---|---|---|
\b | 回退一格 | \" | 双引号 |
\t | 到下一个制表位 | \' | 单引号 |
\n | 换行 | \\ | 反斜杠本身 |
\r | 回车 |
55. 类型转换 🔄
一. 自动类型转换
- 当运算符的两边出现不一致的类型时,会自动转换成较大的类型
char->short->int->long->long longint->float->double
二. 强制类型转换
(类型)值比如(int)10.2- 强制类型转换的优先级高于四则运算
56. 逻辑类型 ✅
一. bool
#include<stdbool.h>之后就可以使用bool和true、false
57. 逻辑运算 🧠
一.
| 运算符 | 描述 | 示例 | 结果 |
|---|---|---|---|
! | 逻辑非 | !a | 如果a是true结果就是false |
&& | 逻辑与 | a&&b | 如果a和b都是true,结果就是true |
| | | 逻辑或 |
四. 短路
- 逻辑运算是自左向右进行的,如果左边的结果已经能够决定结果了,就不会做右边的计算
58. 条件运算和逗号运算 ❓
一. 条件运算符
count=(count>20)?count-10:count+10
四. 逗号运算
- 逗号用来连接两个表达式,并以其右边的表达式的值作为它的结果。
i=3+4,5+6->i=(3+4,5+6)
59. 初见函数 📦
Shutterstock探索
一. 素数求和
C
二. 求和
- “代码复制”是程序质量不良的表现
60. 函数的定义和使用 🔧
一. 什么是函数?
- 函数是一块代码,接收零个或多个参数,做一件事情,并返回零个或一个值
- 函数头:
**返回类型** 函数名(参数表)
二. 调用函数
函数名(参数值)- ()起到了表示函数调用的重要作用
61. 从函数中返回 🔙
一. 从函数中返回值
return停止函数的执行,并送回一个值
二. 没有返回值的函数
void 函数名(参数表)
62. 函数原型 🏗️
三. 函数原型
- 函数头,以分号“;”结尾,就构成了函数的原型
- 函数原型的目的是告诉编译器这个函数长什么样
63. 参数传递 📨
三. 传过去的是什么?
- C语言在调用函数时,永远只能传值给函数
四. 传值
- 每个函数有自己的变量空间,参数也位于这个独立的空间中,和其他函数没有关系
64. 本地变量 🏠
一. 本地变量
- 函数的每次运行,就产生了一个独立的变量空间,在这个空间中的变量,是函数的这次运行所独有的,称作本地变量
二. 变量的生存期和作用域
- 生存期:什么时候这个变量开始出现了,到什么时候它消亡了
- 作用域:在(代码的)什么范围内可以访问这个变量
65. 函数庶事 📝
一. 没有参数时
void f(void);
三. 函数里的函数?
- C语言不允许函数嵌套定义
66. 初试数组 📚
三. 数组
int number[100];- 1.定义数组 2.对数组中的元素赋值 3.使用数组中的元素 4.遍历数组
67. 定义数组 📏
一. 定义数组
<类型> 变量名称[元素数量];- 元素数量必须是整数
二. 数组
- 是一种容器(放东西的东西),特点是:其中所有的元素具有相同的数据类型;一旦创建,不能改变大小;数组中的元素在内存中是连续依次排列的
四. 数组的单元
- 使用数组时放在[]中的数字叫做下标或索引,下标从0开始计数
五. 有效的下标范围
- 编译器和运行环境都不会检查数组下标是否越界
- 一旦程序运行,越界的数组访问可能造成问题,导致程序崩溃 segmentation fault
68. 数组的例子:统计个数 📊
- 写一个程序,输入数量不确定的[0,9]范围内的整数,统计每一种数字出现的次数
69. 数组运算 🧮
二. 数组的集成初始化
int a[]={2,4,5234,12,4};
三. 集成初始化时的定位
int a[10]={[0]=2,[2]=3,6,};
四. 数组的大小
sizeof(a)/sizeof(a[0])
五. 数组的赋值
- 数组变量本身不能被赋值,要把一个数组的所有元素交给另一个数组,必须采用遍历
70. 数组例子-素数 🔢
一.
- 从2到x-1测试是否可以整除
二. 构造素数表
- 欲构造n以内的素数表
71. 二维数组 ⬛
一. 二维数组
int a[3][5];
二. 二维数组的遍历
C
三. 二维数组的初始化
- 列数是必须给出的,行数可以由编译器来数
四. tic-tac-toe游戏
72. 取地址运算 📍
一. 运算符&
- 获得变量的地址,它的操作数必须是变量
int i; printf("%p",&i);
73. 指针 👆
二. 指针
- 就是保存地址的变量
int* p =&i;
四. 访问那个地址上的变量*
*是一个单目运算符,用来访问指针的值所表示的地址上的变量int k=*p;
74. 指针的使用 🛠️
一. 指针应用场景一
- 交换两个变量的值
二. 指针应用场景二
- 函数返回多个值,某些值就只能通过指针返回
- 函数返回运算的状态,结果通过指针返回
四. 指针最常见的错误
- 定义了指针变量,还没指向任何变量,就开始使用指针
75. 指针与数组 🔗
一. 传入函数的数组成了什么?
- 函数参数表中的数组实际上是指针
sizeof(a)==sizeof(int*)
三. 数组变量是特殊的指针
- 数组变量本身表达地址
int a[10];int*p=a;//无需用&取地址a==&a[0]
76. 指针与const 🔒
二. 指针是const
- 表示一旦得到了某个变量地址,不能再指向其他变量
int*const q=&i;
三. 所指的是const
- 表示不能通过这个指针去修改那个变量(并不能使得那个变量称为const)
const int*p=&i;
77. 指针运算 ➕
一. 1+1=2?
- 给一个指针+1表示要让指针指向下一个变量
- 如果指针不是指向一片连续分配的空间,如数组,则这种运算没有意义
二. 指针计算
- 给指针加、减一个整数(+,+=,-,-=)
- 两个指针相减(表示之间有几个东西(/sizeof))
五. 0地址
- NULL是一个预定义的符号,表示0地址
78. 动态内存分配 🧠
二. malloc
#include<stdlib.h>void*malloc(size_t size)- 向malloc申请的空间的大小是以字节为单位的
四. free()
- 把申请得来的空间还给“系统”
- 只能还申请来的空间的首地址
79. 字符串 🧵
二. 字符串
- 以0(整数0)结尾的遗传字符
- 0标志字符串的结束,但它不是字符串的一部分
80. 字符串变量 🔡
一. 字符串常量
char*s="Hello,world!";- s是一个指针,初始化为指向一个字符串常量
- 如果需要修改字符串,应该用数组;
char s[]="Hello,world!";
81. 字符串的输入和输出 ⌨️
一. 字符串赋值?
- 并没有产生新的字符串,只是让指针s指向了t所指的字符串
三. 安全的输入
scanf("%7s",string);- 在%和s之间的数字表示最多允许读入的字符的数量,这个数字应该比数组的大小小一
82. 字符串数组 📚
一. 字符串数组
char **a;
83. 单字符输入输出 🔤
一. putchar
int putchar(int c);
二. getchar
int getchar(void);
84. 字符串函数 🛠️
一. string.h
- strlen, strcmp, strcpy, strcat, strchr, strstr
二. strlen
size_t strlen(const char*s);返回s的字符串长度(不包括结尾的0)
三. strcmp
- 比较两个字符串
四. strcpy
char * strcpy(char *restrict dst,const char *restrict src);
85. 枚举 🔢
三. 枚举
- 枚举是一种用户定义的数据类型
enum 枚举类型名字{名字0,...,名字n}
86. 复杂数据类型 🏗️
一. 用户自己建立数据类型
- 结构体:是一种构造数据类型
- 关键字:
struct
二. 定义结构体类型变量
- 先声明结构体类型,再定义结构体变量
- 声明结构体类型的同时定义结构体变量
三. 结构体变量的引用和初始化
- 结构体变量名.成员名
五. 指向结构体类型数据的指针
- 存放结构体首地址
p->成员名
87. 文件 📁
一. 文件的基本概念和文件指针
- 文本文件:占存储空间多,需要转换时间,但方便字符处理
- 文件指针:
FILE *fp;
二. 文件的打开和关闭
fp=fopen("a1",“r”);fclose(文件指针);
三. 文本文件读写
fgetc(),fputc()fgets(),fputs()fprintf(),fscanf()
四. 二进制文件读写
fread(buffer,size,count,fp);fwrite(buffer,size,count,fp);