初心:在一个人摸索下十分痛苦,不知道哪里开始复习,真题以及视频都没有,我希望在自己摸索完之后,能把宝贵的经验分享给需要的人,也希望各位以后也可以帮助更多的人,接下来让我们一起开始学习C语言和数据结构吧!!!
座右铭:“莫问收获,但问耕耘”
目录
2、break不能直接用于if,除非if属于循环内部的一个子句:
3、在多层switch循环中,break只能终止距离它最近的switch!:
5、函数举例_判断一个数组是否是素数(不用调用函数的例子):
如何看懂一个程序:
如何看懂一个程序,分三步:
1、流程2、每个语句的功能
3、试数
对一些小算法的程序:
尝试自己去编程解决它,大部分人都自己无法解决
如果解决不了,就看答案
关键是把答案看懂,这个要花很多时间精力,也是我们学习的重点
看懂之后尝试自己去修改程序,并且知道修改之后程序的不同输出结果的含义
照着答案敲
调试错误
不看答案,自己独立把答案敲出来如果程序实在无法彻底理解,就把程序背会(极少这些情况)!
数据类型
基本数据类型
#include <stdio.h>
/*
整数
整型----int 占用4个字节
短整型----short int 占用2个字节
长整形----long int 占用8个字节
浮点型【实数】
单精度浮点数----float 小 占用4个字节
双精度浮点数----double 大 占用8个字节
字符
char 占用一个字节
复合类型数据
结构体
枚举
共用体
*/
什么是变量:
变量的本质就是内存中一段存储空间。
#include <stdio.h>
int main() {
int i = 3;//3最终是存放在内存中,程序终止之后3所占的空间会被释放
printf("i=%d\n", i);//%d 是输出整形的 后面会详细讲
return 0;
}
输出结果:
变量为什么必须初始化:
所谓的初始化就是赋值的意思。
1、先来看看未初始化的代码:
已经初始化的代码:
#include <stdio.h>
int main() {
int i = 88;
printf("i=%d\n", i);//输出88
return 0;
}
如何定义变量:
#include <stdio.h>
/*
数据类型 变量名 = 要赋的值;
等价于
数据类型 变量名;
变量名 = 要赋的值;
*/
举例子:
#include <stdio.h>
int main() {
int i = 88;
//等价于 int i; i=88;
printf("i=%d\n", i);//输出88
return 0;
}
什么是进制:
#include <stdio.h>
/*
十进制就是逢十进一
二进制就是逢二进一
十六进制就是逢十六进一
*/
例子:(ps:在算进制转换可以使用位权展开法进行计算-----具体百度)
#include <stdio.h>
int main() {
int i = 88;//10进制
printf("i=%x\n", i);//输出58
}
常量在c语言中如何表示:
#include <stdio.h>
/*
整数:
十进制:传统的写法
十六进制:前面加0x或0X
八进制:前面加0 注意是数字零不是字母o
浮点数:
传统的写法
float x = 3.1;//传统
科学技术法
float x = 3.2e3;//x的值是3200
float x = 123.45e-2;//x的值是1.2345
*/
代码展示:
#include <stdio.h>
int main() {
float x = 123.45e-2;//赋值不加F 默认是double类型 加了F如:123.45e-2F;是float类型
printf("%f\n", x);//输出1.234500
}
字符char:
#include <stdio.h>
/*
总结:字符用单引号,字符串用双引号。
单个字符用单引号括起来
'A'表示字符A
'AB'错误
字符串用双引号括起来
"A"正确,因为"A"代表'A' '\0'的组合 '\0'代表了字符串的结束,但不算字符串长度
*/
常量以什么样的二进制代码存储在计算机中:(了解即可)
#include <stdio.h>
/*
整数是以补码的形式转化为二进制代码存储在计算机中
实数是以IEEE754标准转化为二进制代码存储在计算机中
字符的本质实际也是与整数的存储方式相同
*/
什么是字节:
#include <stdio.h>
/*
字节就是存储数据的单位,并且是硬件所能访问的最小单位
1字节 = 8位
1k = 1024字节
1M = 1024K
1G = 1024M
*/
char使用常见问题解析:
#include <stdio.h>
int main() {
char ch = 'A';//ok 等价于 char ch ; ch = 'A';
//char g = "AB";//错误 因为"AB"是字符串,我们不能把字符串赋值给单个字符
//char b ="A";//错误 凡是字符串都默认加\0 ch变量只能存放一个 所以报错
// 因为"A"代表'A' '\0'的组合 '\0'代表了字符串的结束,但不算字符串长度
//char k ='AB'//错误的 单引号只能扩一个字符
printf("%c\n", ch);//输出A
return 0;
}
什么是ASCII:(具体的表可以在csdn搜索)
#include <stdio.h>
/*
ASCII不是一个值,而是一种规定
ASCII规定了不同的字符是使用哪个整数值去表示
它对规定了
'A' -- 65
'B' -- 66
'a' -- 97
'b' -- 98
'0' -- 48
*/
代码展示:
基本的输出(printf)的用法:
#include <stdio.h>
/*
printf() --将变量的内容输出到显示器上
四种方法:
1、printf("字符串\n");
2、printf("输出控制符", 输出参数);
3、printf("输出控制符1,输出控制符2,输出控制符3", 输出参数1, 输出参数2, 输出参数3);
输出空字符和输出参数的个数必须一一对应。
4、printf("输出控制符 非输出控制符", 输出参数); (ps:很少用)
*/
代码例子:
#include <stdio.h>
int main() {
printf("欢迎一起学习插本c语言\n");//\n表示换行 第一种方法
int i = 10;
int j = 12;
printf("%d\n",i);//d是十进制 //第二种方法 输出10
printf("%d %d\n",i,j ); //第三种方法 输出12
}
常用输出控制符包含如下:
#include <stdio.h>
/*
% d ---- 以十进制整形数据输出
% ld ---- 长整形输出
% c ---- 输出一个字符
% f ---- 输出实数,以小数形式输出,默认情况下保留小数点6位。(float,double都推荐用% f输出)
% lf ---- 输出实数 (对应double) ps:(float,double都推荐用% f输出)
%s ---- 输出字符串
%e ---- 指定以指数形式输出实数
% x(或者% X后者% #X----- 注意大小写) ---- 输出十六进制 (八进制很少用 ,这里不作解析)
*/
来聊聊陌生的%x:
#include <stdio.h>
int main() {
int x = 100;//100是十进制 0100代表8进制 0X100表示16进制
printf("%d\n",x);//100
printf("%x\n", x);//输出16进制的100 // 64
printf("%#X\n", x);//目的是加前缀让别人知道是十六进制 0X64
printf("%#x\n", x);//一般用大写的 小写的不要 0x64
return 0;
}
扩展知识:
#include <stdio.h>
/*
C语言%f和 %lf的区别
%f和%lf分别是float类型和double类型用于格式化输入输出时对应的格式符号。
其中:
float,单精度浮点型,对应%f。
double,双精度浮点型,对应%lf。
在用于输出(printf)时:
float类型可以使用%lf格式
double类型如果使用了%f格式可能会导致输出错误。
在用于输入(scanf)时:
double 类型使用了%f格式,会导致输入值错误。
float类型使用double类型不仅会导致输入错误,还可能引起程序崩溃。
*/
为什么需要输出控制符:
1、01组成的代码可以表示数据也可以表示指令。
2、如果01组成的代码表示的是数据的话,那么同样的01代码组合以不同的输出格式输出就会有不同的输出结果。
用简单的scanf函数输入数据:
1、scanf函数的一般形式:
scanf () 【通过键盘将数据输入到变量中】
格式代码如下:
#include <stdio.h>
/*
scanf("输入控制符", 输入参数);//输入参数=地址列表
*/
2、scanf的第一种用法:
用法一:scanf("输入控制符", 输入参数);
功能:将从键盘输入的字符转化为输入控制符所规定格式的数据,然后存入以输入参数的值为地址的变量中。
代码例子如下:
#include <stdio.h>
int main() {
int j;//定义一个变量j
printf("请您估算下23年专升本C语言程序设计的分数:\n");
scanf("%d", &j);
printf("您估算的分数是:%d", j);
return 0;
}
代码运行结果:
3、scanf的第二种用法:
用法二:scanf("非输出控制符 输入控制符", 输入参数);
功能:将从键盘输入的字符转化为输入控制符所规定格式的数据,然后存入以输入参数的值为地址的变量中。非输出控制符必须原样输入。
代码例子:
#include <stdio.h>
int main() {
int i;
scanf("m%d", &i);//含非输出控制符 m
printf("i=%d\n", i);
return 0;
}
运行结果与分析:
含非输出控制符号m,如果我们想输出我们输入的数字就必须要把m(非输出控制符也要输入上去,才能输入123)
正确的输入方式是:
输入多位数字:
#include <stdio.h>
int main() {
int i,j,k,l;
scanf("%d %d %d %d", &i,&j,&k,&l);//输入数字要用空格隔开,系统才会知道
printf("政治:%d,英语:%d,数学:%d,计算机程序设计:%d\n", i,j,k,l);//科目和都号都是非控制输出符号,会一同输出
return 0;
}
代码运行结果:
4、如何使用scanf编写出高质量的代码:
1、使用scanf之前最好先使用printf提示用户以样的方式来输入。
2、scanf中尽量不要出现非输入控制符,尤其是不要用\n
3、应该编写代码对用户的非法输入做适当的处理【非重点】
while(((ch=gerchar())!='\n')
continue;
运算符基本概念(考试重点):
1、c的运算符号:有以下几类:
算术运算符 :+ - * / %(取余)
关系运算符:> < == >= <= !=
逻辑运算符:!(非)、&&(并且)、||(或)
位运算符: <<(左移) 、>>(右移)、 ~(按位取反)、 | (按位或)、 ^(按位异或)、 &(按位与)
赋值运算符: =(赋值及其扩展赋值运算符)
条件运算符: ?:(三目运算符)
逗号运算符:,
指针运算符:*和&
求字节数运算符:sizeof
强制类型转换运算符:(类型)
成员运算符:.->
下标运算符: [ ]
C语言运算符优先级:
优先级 | 运算符 | 名称含义 | 使用形式 | 结合方向 | 说明 |
1 | [] | 数组下标 | 数组名[常量表达式] | 左到右 | -- |
() | 圆括号 | (表达式)/函数名(形参表) | -- | ||
. | 成员选择(对象) | 对象.成员名 | -- | ||
.> | 成员选择(指针) | 对象指针->成员名 | -- | ||
2 | - | 负号运算符 | -表达式 | 右到左 | 单目运算符 |
~ | 按位取反运算符 | ~表达式 | |||
++ | 自增运算符 | ++变量名/变量名++ | |||
-- | 自减运算符 | --变量名/变量名-- | |||
* | 取值运算符 | *指针变量 | |||
& | 取地址运算符 | &变量名 | |||
! | 逻辑非运算符 | !表达式 | |||
(类型) | 强制类型转换 | (数据类型)表达式 | |||
sizeof | 长度运算符 | sizeof(表达式) | |||
3 | / | 除 | 表达式/表达式 | 左到右 | 双目运算符 |
* | 乘 | 表达式*表达式 | |||
% | 取余 | 整型表达式%整型表达式 | |||
4 | + | 加 | 表达式+表达式 | 左到右 | 双目运算符 |
- | 减 | 表达式-表达式 | |||
5 | << | 左移 | 变量<<表达式 | 左到右 | 双目运算符 |
>> | 右移 | 变量>>表达式 | |||
6 | > | 大于 | 表达式>表达式 | 左到右 | 双目运算符 |
>= | 大于等于 | 表达式>=表达式 | |||
< | 小于 | 表达式<表达式 | |||
<= | 小于等于 | 表达式<=表达式 | |||
7 | == | 等于 | 表达式==表达式 | 左到右 | 双目运算符 |
!= | 不等于 | 表达式!= 表达式 | |||
8 | & | 按位与 | 表达式&表达式 | 左到右 | 双目运算符 |
9 | ^ | 按位异或 | 表达式^表达式 | 左到右 | 双目运算符 |
10 | | | 按位或 | 表达式|表达式 | 左到右 | 双目运算符 |
11 | && | 逻辑与 | 表达式&&表达式 | 左到右 | 双目运算符 |
12 | || | 逻辑或 | 表达式||表达式 | 左到右 | 双目运算符 |
13 | ?: | 条件运算符 | 表达式1? 表达式2: 表达式3 |
右到左 | 三目运算符 |
14 | = | 赋值运算符 | 变量=表达式 | 右到左 | - |
/= | 除后赋值 | 变量/=表达式 | |||
*= | 乘后赋值 | 变量*=表达式 | |||
%= | 取余后赋值 | 变量%=表达式 | |||
+= | 加后赋值 | 变量+=表达式 | |||
-= | 加后赋值 | 变量-=表达式 | |||
<<= | 左移后赋值 | 变量<<=表达式 | |||
>>= | 右移后赋值 | 变量>>=表达式 | |||
&= | 按位与后赋值 | 变量&=表达式 | |||
^= | 按位异或后赋值 | 变量^=表达式 | |||
|= | 按位或后赋值 | 变量|=表达式 | |||
15 | , | 逗号运算符 | 表达式,表达式,… | 左到右 | - |
说明:
同一优先级的运算符,运算次序由结合方向所决定。
简单记就是:! > 算术运算符 > 关系运算符 > && > || > 赋值运算符
除法(/)运算符细节:
除法/的运算结果和运算对象的数据类型有关,两个数都是int,则商是int,若商有小数,则截取小数部分;
例子:16/5==3 18/7==4 5/3==1 3/5==0
被除数和除数只要有一个或两个都是浮点型数据,则商也是浮点型;
例子:16/5.0=3.20000 -13/4==-3
如果负数/负数得正;
例子:-13/-3==4 -12/-6==2
取余(%)运算符的细节:
取余%的运算对象必须是整数,结果是整除后的余数,其余数的符号与被除数相同;
例子: 13%3==1 13%-3=1 -13%3==-1 以上例子13和-13都是被除数
测试取余运算符的代码例子:
//取余运算符:
int main() {
//==是等于 =是赋值
printf("-13取余6==%d,18取余7==%d\n", -13 % 6, 18 % 7);
//本来想把%取余符号当输出控制符输出,结果不行,只能换中文了
}
代码结果:
逻辑运算符的细节:
逻辑运算符:!(非)、&&(并且)、||(或)
C语言对真假的处理
非零是真(重点记住)
零是假
真是用1表示,假是用0表示(和原码补码反码刚好相反)
&&左边的表达式为假,右边的表达式肯定不会执行
||左边的表达式为真,右边的表达式肯定不会执行!真 假
!假 真
真&&真 真
真&&假 假
假&&真 假
假&&假 假
真||假 真
假||真 真
假||假 假
真||真 真
1、!(非)代码例子:
#include <stdio.h>
int main() {
printf("%d", !- 3);//-3非0即真 !真=假 输出0
}
2、&&(并且)代码例子:
#include <stdio.h>
int main() {
int i = 10;
int k = 20;
int m;
m = (3 > 2) && (k < 8);//真&&假 假输出0
printf("m=%d,k=%d\n", m, k);//输出m=0,k=20
}
3、&&(并且)的陷阱例子:
&&左边的表达式为假,右边的表达式肯定不会执行
#include <stdio.h>
int main() {
int i = 10;
int k = 20;
int m;
m = (1 > 2) && (k = 5);//假&&真 ,此时我们需要注意k到底等于多少?
printf("m=%d,k=%d\n",m,k);//输出 m=0,k=20
//m=0因为假输出0 k是20 因为只要左边为假 右边无论执行还是不执行结果都是假
//假设本串代码是m是真的话,k就会变成5
}
什么是表达式:
- 表达式就是利用运算符链接在一起的有意义,有结果的语句;
- 例如: a + b; 就是一个算数表达式, 它的意义是将两个数相加, 两个数相加的结果就是表达式的结果
- 注意: 表达式一定要有结果
自增自减++、- -:
自增[或自减]
分类:
前自增(减) --i ++i
后自增(减) i-- i++
前自增和后自增的异同:
相同:
最终都使i的值加1
不同:
前自增整体表达式的值是i加1之后的值
后自增整体表达式的值是i加1之前的值
为什么会出现自增:
代码更精炼
i自增的速度更快
学习自增要明白的几个问题:
1、我们编程时应该屏蔽掉前自增和后自增的差别
2、自增表达式最好不要作为一个为更大的表达式的一部分使用
或者说
i++和++i单独成一个语句,不要把它作为一个完整符合语句的一部分来使用
如:(考试喜欢这样)
1、printf("%d %d %d",i++,++i,i );//同上(考试会考,工作千万不要使用!!!)
2、int m =i++ + ++i + i + i++;//这样写不规范的代码,而且是不可移植的代码
在不同机器上运行结果不一样 i++不知道后面运行没就执行+ ++i
顺序点:, () ; i++,++i i++在逗号后面就一定会生效
代码例子:
#include <stdio.h>
int main() {
int i;
int j;
int k;
int m;
i = j = 3;//等价于i=3; j=3;
k = i++;//后自增整体表达式的值是i加1之前的值
m = ++j;//前自增整体表达式的值是i加1之后的值
printf("i=%d, j=%d, k=%d, m=%d\n", i, j, k, m);//i=4, j=4, k=3, m=4
return 0;
}
逗号运算符:
符号:英文逗号,
多用于for循环中 for(i = 0, j = n-1; i < j; i++ , j--) //这里有三个表达式 用分号隔开
逗号运算符的优先级在c语言中是最低的
1、逗号表达式:
表达式:使用逗号把多个表达式连接起来的式子,最后一个表达式的值作为整个逗号表达式的值。
执行规则:从前往后依次执行各表达式。
把最后一个表达式的值作为整个逗号表达式的值。
2、未使用表达式的值--------代码分析:
#include <stdio.h>
int main() {
int a = 3, b = 5, t;
t = a, a = b, b = t;
//等价以下三条语句
t = a; //t=3
a = b; //a=5
b = t; //b=3
//执行完该程序段后,a=5,b=3。交换功能!
}
3、使用表达式的值--------代码分析:
#include <stdio.h>
int main() {
int a1, a2, a3, b, c, d;//定义六个整形变量
a1 = (b = 6, c = 7, d = 5);//d的值5,赋给a1,a1=5
a2 = (++b,c--,d+1);//d+1的值6,赋给a2,a2=6 b=7,c=6
a3 = b,c,d;//(a3=b),c,d a3=7
//分析:(a3=b),c,d 形成逗号表达式 该逗号表达式从前往后计算,b赋值给a3后
// 再执行c,d cd已经没有含义了,cd没有参与运算,只是执行了。
//这行有两个运算符一个赋值运算符、一个逗号运算符,
//已知逗号运算符在c语言中是最低的,所以先进行赋值操作
printf("%d,%d,%d\n", a1, a2, a3);//输出5,6,7
}
例题:
#include <stdio.h>
int main() {
int a = 1;
printf("%d\n", ((a += 4, a + 5), a / 2)); //输出2 5/2,整数/整数=整数
}
/*/
a+5不会改变a的值 相反=就会改变a的值
*/
例子:
#include <stdio.h>
int main() {
int i;
int j = 2;
i = (j++, ++j, j + 2, j - 3);
printf("%d\n", i);//1
}
/*/
j++后逗号后面j就会发现变化j变成3(因为逗号是顺序点)
++j在自增后是4
j+2的值,没有改变,因为+2没有赋值给j
j-3=4-3=1
i+2的值是没有改变的 除非写成i+=2
*/
三目运算符:
三目运算符,它需要3个数据或表达式构成条件表达式
格式:
表达式1?表达式2(结果A):表达式3(结果B)
- 示例:
考试及格 ? 及格 : 不及格;
求值规则:
- 如果"表达式1"为真,三目运算符的运算结果为"表达式2"的值(结果A),否则为"表达式3"的值(结果B)
- 注意点
- 条件运算符的运算优先级低于关系运算符和算术运算符,但高于赋值符
- 条件运算符?和:是一个整体,不能分开使用
代码例子:
#include <stdio.h>
int main() {
int a = 10;
int b = 20;
int max = (a > b) ? a : b;
printf("max = %d", max);//20
//思路:10>20吗如果大于则输出a,否则输出b
//显然10不大于20,那么输出b
return 0;
}
流程控制(是我们学习C语言的第一个重点):
1、什么是流程控制:
程序代码执行的顺序。
2、流程控制的分类:
1、顺序结构(按书写顺序从上至下依次执行)
2、选择结构(某些代码可能执行,也可能不执行,有选择的执行某些代码)
3、循环结构(其特点是,在给定条件成立时,反复执行某程序段, 直到条件不成立为止,给定的条件称为"循环条件",反复执行的程序段称为"循环体")
选择结构:
第一种形式if:
分类:
1、if最简单的用法。
2、if的范围问题
3、if----else的用法4、if----else if----else 的用法
5、C语言对真假的处理
6、if举例--求分数的等级
7、if的常见问题解析
1、if最简单的用法:
#include <stdio.h>
if(表达式) {
语句块1;
}
后续语句;
/*
功能:如果表达式为真,执行语句
如果表达式为假,语句不执行*/
if最简单的用法例子解析:
#include <stdio.h>
int main() {
if (3) {//非0即真
printf("AAAA\n");
}
if (0) {//0即假 不能输出
printf("BBBB\n");
}
if (0==0) {//0==0可以输出
printf("CCCC\n");
}
return 0;
}
//输出结果:AAAA CCCC
2、if的范围问题(重点):
总结:
1、
if(表达式)
语句A;
语句B;
解释:if默认只能控制语句A的执行或不执行
if无法控制语句B的执行或不执行
或者讲:语句B一定会执行2、
if(表达式){
语句A;
语句B;
}
此时if可以控制语句A和语句B
由此可见:if默认只能控制一个语句的执行或不执行
如果想控制多个语句的执行或不执行就必须把这些语句用{}括起来
if的范围问题(重点)例子:
不常用的写法(不推荐使用,会给骂死):
#include <stdio.h>
int main() {
if (3> 2)//会输出cccc dddd
printf("cccc\n");//第一个语句
printf("dddd\n");//第二个语句
//因为系统从上往下去执行
return 0;
//}
细节:
#include <stdio.h>
int main() {
if (1 > 2)//会输出 dddd
printf("cccc\n");//第一个语句
printf("dddd\n");//第二个语句
//if默认控制一个语句,if判断条件为假,所以不输出cccc
//因为系统是顺序执行,会输出dddd
return 0;
}
强烈推荐这样写if选择结构:
#include <stdio.h>
int main() {
if (3 > 2) {
printf("cccc\n");//第一个语句
printf("dddd\n");//第二个语句
}
printf("加了{}就可以输出两个语句了\n");
return 0;
}
//输出结果:cccc
dddd
加了{}就可以输出两个语句了
3、if----else的用法:
if--else含义:
if第二种形式
- 如果表达式为真,则执行语句块1,否则执行语句块2
- else不能脱离if单独使用