笔记目录
前言
郝斌 ; C语言中文网 ; C语言 ; 笔记
一、选择_If
1.求分数等级
//求分数等级
# include <stdio.h>
int main(void)
{
float score;
printf("请输入您的考试成绩 : ");
scanf("%f",&score);
if (score > 100 || score < 0)
printf("这不可能\n");
else if (score >= 90 && score <= 100) //不能写成 90 <= score <= 100 ; 先执行90 <= score ? 0:1 ; 0,1 <= 100恒成立
printf("A\n");
else if (score >= 60 && score <90)
printf("B\n");
else
printf("C\n");
return 0;
}
2.互换两个数字
//互换两个数字
# include <stdio.h>
int main (void)
{
int i = 3;
int j = 4;
int tmp;
tmp = i;
i = j;
j = tmp;
printf("i = %d , j = %d\n", i, j);
return 0;
}
3.对任意三个数字进行排序
//对任意三个数字排序_小冒泡
# include <stdio.h>
int main(void)
{
int a,b,c;
int t;
printf("请输入三个整数(中间以空格分隔):");
scanf("%d %d %d", &a, &b, &c);
//编写代码:a是最大值,b是中间值,c是最小值
if (a < b)
{
t = a;
a = b;
b = t;
}
if (a < c)
{
t = a;
a = c;
c = t;
}
if (b < c)
{
t = b;
b = c;
c = t;
}
printf("%d %d %d\n", a, b, c);
return 0;
}
4.看懂/掌握一个程序
- 算法程序 : 思考15分钟后直接看答案
- 重点 : 看懂程序(流程 ; 每个语句功能 ; 试数(三_7, 四_4))
- 修改程序,明白修改后不同输出结果含义
- 照着答案敲,调试错误
- 不看答案敲
- 无法理解 : 直接背会
5.If常见问题
- if … else if … else 即使都成立,也只执行第一个成立的
- 可以不写else语句,逻辑无误(无匹配则不执行)
- 空语句
if (3 > 2);
<=>
if (3 > 2)
; // 这是个空语句 - else 不能加判断语句 // 写表达式必须有if
Eg 1 :
else (表达式4) //语法错误
D;
Eg 2 :
else (表达式4);
D;
<=>
else
(表达式4);
D;
二、选择_Switch
三、循环_for
- 定义 : 某些代码会被重复执行
- 分类 : for ; while ; do…while
- 范围问题 : 加括号()
- 执行顺序: 1243; 3标志着循环结束
for(1; 2; 3)
4;
1. 1+2+…+100
//1+2+...+100
# include <stdio.h>
int main(void)
{
int i;
int sum = 0;
for(i = 1; i <= 100; ++i)
{
sum += i;
}
printf("sum = %d\n", sum);
return 0;
}
2. 1~10的奇数之和
//1~10的奇数之和
# include <stdio.h>
int main(void)
{
int i;
int sum = 0;
for (i = 1; i < 10; i += 2)
{
sum += i;
}
printf("1~10奇数之和为 : %d\n", sum);
return 0;
}
//25
3.For与If的嵌套使用_被3整除的数字之和
- 100以内能被三整除的数:S = n * (a1 + an) / 2
//求1~100之间所有能被3整除的数字之和
# include <stdio.h>
int main(void)
{
int i,sum = 0;//i是垃圾值
//printf("%d %d", i, sum);
for (i = 3; i <= 100; ++i)
{
if(i%3 == 0)
{
sum += i;
}
}
printf("sum = %d\n", sum);
return 0;
}
- 1~100之间的奇数之和
- 1~100之间的奇数的个数
- 1~100之间的奇数的平均值
- 1~100之间的奇数之和 与 偶数之和 //输出两个值
4.For与If的嵌套使用_斐波拉契序列
/*
斐波拉契序列 :
1 2 3 5 8 13 21 34 …
*/
# include <stdio.h>
int main (void)
{
int n, i;
int f1, f2, f3;
f1 = 1;
f2 = 2;
printf("请输入您需要查询的项 : ");
scanf("%d", &n);
if (n == 1)
{
f3 = 1;
}
else if (n == 2)
{
f3 = 2;
}
else
{
for(i = 3; i <= n; ++i)
{
f3 = f1 + f2;
//后一项赋给前一项
f1 = f2;
f2 = f3;
}
}
printf("斐波拉契序列, 第%d项是%d\n", n, f3);
return 0;
}
/*
请输入您需要查询的项 : 7
斐波拉契序列, 第7项是21
*/
5.强制类型转换
- 高精度与低精度运算(±*/等) -> 高精度 // float后跟6个0
- 强制类型转换 : (数据类型)(表达式)
- 程序中更新的变量不能定义为浮点型
6. 1/1 + 1/2 + … + 1/100
# include <stdio.h>
int main (void)
{
int i;
float sum = 0;
for (i = 1; i <= 100 ; ++i) // 令 i = 0 结果为sum = 1.#INF00
{
sum += 1 / (float)(i); //简化 : sum += 1.0/i
}
printf("sum = %f\n", sum);
return 0;
}
7.试数举例_1
具体过程:
1 -> i = 1 1 <= 100 成立
 sum = 0 + 1/1.0 = 1.0 ++i i = 2
2 -> i = 2 2 <= 100 成立
 sum = 1.0 + 1/2.0 = 1.5 ++i i = 3
3 -> i = 3 3 <= 100 成立
 sum = 1.5 + 1/3.0 ++i i = 4
8.浮点数存储
- float 和 double 都不能保证精确的存储一个小数 (编码问题) // 近似值
- 现实意义 : 如何判断x的值是否为0
//极限的定义 : 计算机中最小△为0.000001
if (|x - 0.000001| < 0.000001)
{
printf("是");
}
else
{
printf("否");
}
- 为什么程序中更新的变量不能定义为浮点型?
答 : 可能溢出一点导致循环遗漏
9.多层For循环嵌套使用
for (1; 2; 3)
for(4; 5; 6)
A;
B;
执行顺序 :
1 -> 2(成立) -> 4 -> 5(成立) -> A -> 6 -> 5(成立) -> A -> 6 -> 5(不成立) -> 3
-> 2(成立) -> 4 -> 5(成立) -> A -> 6 -> 5(成立) -> A -> 6 ->5(不成立) -> 3
-> 2(不成立) -> B
四、循环_While
1.格式
格式 :
while (表达式)
{
语句;
}
2.While 与 For循环比较
for (1; 2; 3)
{
A;
}
等价于 :
1;
while (2)
{
A;
3;
}
3.举例_while求回文数
//试数要把自己代入计算机视角, 一步一步详细试, 千万不能跳步(体力活)
// while 求回文数
# include <stdio.h>
int main(void)
{
int val, m;
int sum = 0; // 翻转后
printf("请输入您需要判断的数字 : ");
scanf("%d", &val);
m = val;
while (m)
{
sum = sum*10 + m%10; // 取 m 最低位作为 sum 最高位
m /= 10; // 整数除去掉最低位
}
if (sum == val)
printf("Y\n");
else
printf("N\n");
return 0;
}
4.试数举例_2
具体过程:
1 -> m = 123 成立
sum = 0*10 + 123%10 = 3
m = m/10 = 12
2 -> m = 12 成立
sum = 3*10 + 12%10 = 32
m = 12/10 = 1
3 -> m = 1 成立
sum = 32*10 + 1%10 = 321
m = 1/10 = 0
4 -> m = 0 不成立
最终sum = 321
5.什么时候使用While, 什么时候使用For
- while 和 for可以相互转换
- for的逻辑性更强, 更不易出错, 推荐用for
五、循环_Do…While
1.格式
格式 :
do
{
语句;
} while (表达式); // 分号不能省
2.Do…While 与 While & For循环比较
1. do...while 一定执行一次 ; while与for可能完全不执行
2. do...while 主要用于人机交互
3.Do…While_一元二次方程
六、数组
-
为什么需要数组:
*为了解决大量同类型数据的存储和使用
*为了模拟现实世界 -
怎样定义一维数组
*为n个变量连续分配存储空间
*所有变量数据类型必须相同
*所有变量所占字节大小必须相等 -
一维数组的操作
*初始化:
1.完全初始化
2.不完全初始化
3.不初始化 // 所有元素都是垃圾值
4.清零 // 每个元素都是0 :int a[5] = {0};
错误: int a[5]; a[5] = {1, 2, 3, 4, 5}; // 本身也不存在a[5]元素
// 错误:定义数组时才能整体赋值,其他情况下是给一个元素进行整体赋值
*赋值:
想把数组a中元素全部复制给b数组
错误写法 : b = a ; // 数组名是数组第一个元素地址
正确写法 :
for (i = 0; i < 5; ++i)
{
b[i] = a [i] ;
}
1.一维数组的创建与使用
# include <stdio.h>
int main(void)
{
int a[5] = {1, 2, 3, 4, 5}; // a为数组名, 5表示数组 元素(变量) 个数, 并且五个元素分别用a[0] ~ a[4]表示
int i;
for (i = 0; i < 5; ++i)
{
printf("%d\n", a[i]);
}
// printf("%d\n", a[100]); //944791496
return 0;
}
2.一维数组的操作
1.倒置
//数组倒置
# include <stdio.h>
int main(void)
{
int a[9] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
int i, j;
int t;
i = 0;
j = 8;
while(i < j)
{
t = a[i];
a[i] = a[j];
a[j] = t;
i++;
j--;
}
for(i = 0; i < 9; i++)
{
printf("a[%d]的值为 : %d\n", i, a[i]);
}
return 0;
}
/*
a[0]的值为 : 9
a[1]的值为 : 8
a[2]的值为 : 7
a[3]的值为 : 6
a[4]的值为 : 5
a[5]的值为 : 4
a[6]的值为 : 3
a[7]的值为 : 2
a[8]的值为 : 1
*/
2.赋值
3.排序
4.求 最大/最小 值
5.查找
6.插入
7.删除
3.二维数组
int a[3][4];
总共是12个元素, 可以当做3行4列看待
名字依次是 :
a[0][0] a[0][1] a[0][2] a[0][3]
a[1][3]
a[2][3]
//实际上内存中是竖直
初始化_1 :
int a[3][4] = {1, 2, ... , 12};
初始化_2 :
int a[3][4] = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
1.二维数组的使用
//二维数组的使用
# include <stdio.h>
int main(void)
{
int a[3][4] = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
int i, j;
//输出数组内容
for (i = 0; i < 3; ++i)
{
for(j = 0; j < 4; ++j)
{
printf("a[%d][%d]的值为 : %d\n", i, j, a[i][j]);
}
}
return 0;
}
/*
a[0][0]的值为 : 1
a[0][1]的值为 : 2
a[0][2]的值为 : 3
a[0][3]的值为 : 4
a[1][0]的值为 : 5
a[1][1]的值为 : 6
a[1][2]的值为 : 7
a[1][3]的值为 : 8
a[2][0]的值为 : 9
a[2][1]的值为 : 10
a[2][2]的值为 : 11
a[2][3]的值为 : 12
*/
2.对二维数组排序
3.求每一行的最大值
4.判断矩阵是否对称
5.矩阵相乘
4.多维数组
不存在多维数组 ;
因为内存是线性一维的 :
n维数组可以当做每个元素是n-1维数组的一维数组
例子 :
int a[3][4];
该数组是含有3个元素的一维数组
只不过每个元素都可以再分成四个小元素
int a[3][4][5];
该数组是含有3个元素的一维数组
只不过每个元素都是4行5列的二维数组
七、函数
1.函数的概念
(1) 什么叫函数 // 类似于黑匣子
1. 逻辑上 : 能够完成特定功能的, 独立的, 代码单元
2. 物理上 : 1>能够接收数据 // 也能不接收
2>能够对接收的数据进行处理
3>能够将数据处理结果返回 // 也可不返回
(2) 为什么需要函数
1. 避免重复性操作
2. 有利于程序的模块化 // 分而治之
2.定义函数
函数的返回值 函数的名字(函数的形参列表)
{
函数的执行体;
}
1. 函数定义 的本质 : 详细描述函数之所以能够实现某个特定功能的具体实现方法
2. return 表达式的含义 :
return 返回类型, 以函数定义的, 函数返回值的返回值类型为准;
表达式为空, 则只终止函数不返回值
3.Return 和 Break的区别
1. return 终止函数
2. break 终止循环
4.函数的声明
1. 告诉编译器, 即将出现的若干个字母是一个函数
2. 告诉编译器, 即将出现的若干个字母, 所代表的函数的, 形参 和 返回值 的具体情况
3. 函数声明是一个语句, 末尾必须加分号 // void f(void);
4. 对库函数的声明通过 : # include <库函数所在的文件名.h>
5.形参与实参
1. 个数相同
2. 位置一一对应
3. 数据可惜必须相互兼容
6.Max()函数
//第一个函数
# include <stdio.h>
void max(int i, int j)
{
if (i > j)
printf("%d\n",i);
else
printf("%d\n",j);
} // 函数执行完毕时释放形参空间, 入栈后出栈
int main(void)
{
int a, b, c, d, e, f;
a = 1, b = 2, c = 3, d = 9, e = -5, f = 100;
max(a, b); // 运行到此去找max()函数,
max(c, d);
max(e, f);
return 0;
}
/*
2
9
100
*/
7.判断一个数是否是素数
8.递归
数据结构_栈
函数自己调用自己
函数A 调用 函数A`, 函数A` 调用 函数A``
// 栈_先进后出
函数A压栈, 函数A`压栈, 函数A``压栈 ; 函数A``出栈, 函数A`出栈, 函数A出栈
9.函数的分类
1. 有参函数 & 无参函数
2. 有返回值函数 & 无返回值函数
3. 库函数 &用户自定义函数
4. 值传递函数 & 地址传递函数
5. 普通函数 & 主函数(main)
注 :
- 一个程序必须有且只有一个主函数
- 主函数可调用普通函数
- 普通函数不能调用主函数
- 普通函数可以相互调用
- 主函数是程序的入口, 也是程序的出口
八、指针(C语言的灵魂)
单独开一篇
九、结构体
单独开一篇
补充1 : 运算符
1.算数运算符:
- +
- -
- *
- \ (整数除)
- %
2.关系运算符:
- >
- >=
- <
- <=
- !=
- ==
3.逻辑运算符:
**注:**C语言对真假处理 : 非零是真 ; 零是假
- !
- && (并且)
- || (或)
4.赋值运算符:
- =
- +=
- -=
- *=
- =
5.自增和自减
- 前自增 : ++i
- 后自增 : i++
前自增与后自增的异同:
相同 : 都使i的值+1
不同 : i++ 整体值是 i+1 之前的值
++i 整体值是 i+1 之后的值
为什么出现自增 : 1.代码更精炼 2.自增速度更快 : 寄存器内处理
注 :
- 编程时屏蔽掉前自增与后自增的差别
- 自增表达式最好单独成一个语句
# include <stdio.h>
int main(void)
{
int i,j,k,m;
i = j = 3;
k = i++;
m = ++j;
printf("i = %d, j = %d, k = %d, m = %d\n", i, j, k, m);
return 0;
}
//i = 4, j = 4, k = 3, m = 4
# include <stdio.h>
int main(void)
{
int i = 1;
int m = i++ + ++i + i + i++; //不可移植
printf("%d, %d, %d, %d\n", m, i++, ++i, i);
return 0;
}
//8, 5, 5, 4
6.三目运算符
A ? B : C
等价于 :
if (A)
B;
else
C;
7.逗号表达式
# include <stdio.h>
int main(void)
{
int i;
int j = 2;
i = (j++, ++j, j+2, j-3); //逗号表达式, 从左到右依次执行, 最后输出最右边
printf("%d\n", i);
return 0;
}
// 1
8.位运算符
1.按位与 _ &
eg :
-9 & 5可以转换成如下的运算:
1111 1111 -- 1111 1111 -- 1111 1111 -- 1111 0111 (-9 在内存中的存储)
& 0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 0101 ( 5 在内存中的存储)
-----------------------------------------------------------------------------------
0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 0101 ( 5 在内存中的存储)
// -9 & 5的结果是 5。
/*
int类型 为 4 字节(byte)
每个字节占 8 比特(bit)
1 & 0 == 0;
*/
2.按位或 _ |
1 & 0 == 1;
按位或运算可以用来将某些位 置 1 ,或者 保留 某些位。
eg :
要把 n 的高 16 位置 1,保留低 16 位,可以进行n | 0XFFFF0000运算
(0XFFFF0000 在内存中的存储形式为 1111 1111 -- 1111 1111 -- 0000 0000 -- 0000 0000)
// 校验 :
# include <stdio.h>
int main(void)
{
int n = 0X2D;
printf("%d, %d, %X\n", 9 | 5, -9 | 5, n | 0XFFFF0000);
return 0;
}
// 13, -9, FFFF002D
3.按位异或 _ ^
// 不同为1, 相同为0
按位与运算通常用来对某些位 清 0 ,或者 保留 某些位。
例如要把 n 的高 16 位清 0 ,保留低 16 位,可以进行n & 0XFFFF运算
(0XFFFF 在内存中的存储形式为 0000 0000 -- 0000 0000 -- 1111 1111 -- 1111 1111)
4.取反 _ ~
取反运算符~为单目运算符,右结合性,作用是对参与运算的二进制位取反
5.左移 _ <<
左移运算符<<用来把操作数的各个二进制位全部左移若干位,高位丢弃,低位补0。
如果数据较小,被丢弃的高位不包含 1,那么左移 n 位相当于乘以 2 的 n 次方。
6.右移 _ >>
右移运算符>>用来把操作数的各个二进制位全部右移若干位,低位丢弃,高位补 0 或 1。
如果数据的最高位是 0,那么就补 0;如果最高位是 1,那么就补 1。
如果被丢弃的低位不包含 1,那么右移 n 位相当于除以 2 的 n 次方(但被移除的位中经常会包含 1)。
补充2 : 变量的作用域 和 存储方式
1.按作用域分 :
(1) 全局变量
1. 全局变量
在所有函数外部定义的变量叫全局变量
全局变量使用范围 : 从定义位置 开始 到整个程序结束
2. 局部变量
局部变量使用范围 : 只能在本函数内部使用
注 : 一个函数内部如果定义 局部变量 与 全局变量 名相同, 局部变量会屏蔽全局变量
(2)按变量的存储方式
1. 静态变量
2. 自动变量
3. 寄存器变量
总结
23/05/13 - 未完结