目录
一 初识C语言
1 main 主函数
2 注释
3 C 程序执行的过程:
4 C 程序的结构
5 进制的转换
1.内存容量
2.二进制与十进制的转换
1>将二进制数转换成十进制
2>将十进制转换成二进制数
3.二进制与八进制的转换
1>将八进制数转换成二进制:
2>将二进制数转换成八进制:
4.二进制与十六进制的转换
1>将十六进制数转换成二进制:
2>将二进制数转换成十六进制:
6 原码、反码、补码
二 数据类型、变量、常量
1 数据类型
1.基本类型
1>字符型:特殊的整型,占据 1 个字节(1byte---8bit)
2>整型:整数类型
3>实型:小数,浮点型,没有无符号的浮点型数据
2.构造类型
2 变量
注意:
3 常量
1.整型常量
2.十进制常量、八进制常量、十六进制常量的表示
3.转义字符常量:
4.常变量:用 const 修饰的标识符
三 运算符与表达式
1 运算符与表达式
1.优先级与结合性
2 算术运算符和算术运算表达式
1. + - * / %
2.自增++ 自减--
1> ++后缀:先读后写
2> ++前缀:先写后读
3 关系运算符和关系运算表达式:> < == >= <= !=
4 逻辑运算符和逻辑运算表达式
1.&&逻辑与运算符:
2.||逻辑或运算符:
3.!逻辑非运算符:
5 赋值运算符和赋值运算表达式:
6 逗号运算符和逗号运算表达式:,
7 sizeof 求字节运算符
8 强制类型转换运算符:(类型名)(表达式)
9 不同类型的数据混合运算
四 输入与输出函数、选择结构
1 数据的输出和输入
2 输出函数
1.printf 函数的调用形式:
2.printf 函数的使用方法:
1>使用方法 1:输出单个数据--不换行
2>使用方法 2:有数据需要原样输出的
3>使用方法 3:同时输出多个数据
3.输出数据所占宽度说明
1>整型数据的输出宽度
2>浮点型数据的输出宽度说明
4.输出的数据左对齐
3 输入函数
4 算法的基本结构
4.1 顺序结构:
复合语句:
4.2 选择结构(分支结构)
1.if 语句
2.if...else 语句
3.if...else if 语句
4.if 语句嵌套
5.switch 多路分支语句
6.条件运算符和条件运算表达式: (?:)
五 循环结构
1 循环结构语句
1.while 语句
2.do...while 语句
3.for 语句
2 中断语句
1.break 语句
2.continue 语句
3.goto 语句(了解)
六 函数
1 函数的定义
2 函数的调用
3 函数的声明
4 函数的设计原则
七 递归调用、作用域和存储类别
1 函数的递归调用
1>递归的概念
2>递归思想应该关注的几点:
2 作用域
1.作用域:一个代码空间
1>在同一个作用域内,不能出现相同的标识符,同一个作用域内,不能重复定义变量名。
2>一个标识符不能同时属于两个作用域,使用就近原则
3>局部变量:就是在函数作用域或者是语句块作用域中定义的变量 全局变量:就是在文件作用域中定义的变量(实际开发中尽量不要使用全局变量)
4>全局变量和函数都属于文件作用域内的标识符,文件作用域内的标识符是可以通过 extern 扩展作用域的
3 存储类别
4 栈变量:auto 声明的变量
5 全局区变量:用 static 声明的变量
1>并非所有的变量都可以声明为 static,形式参数不能声明为 static,只能声明 为 auto.
2>变量声明为 static 时,不赋初值时默认为 0.
3>全局标识符如果用 static 修饰,并不是表示在全局区而是表示该标识符只能在本文件内被扩展使用。
八 指针与变量
1 指针的预备知识
2 指针的基本概念和指针常量
1.什么是指针:
2.怎么获取变量的地址:
3.C 语言中地址绑定一块内存
4.指针(地址)常量的写法
3 指针的类型
4 指针变量的定义
5 指针变量的基本用法
一 初识C语言
1 main 主函数
1.只能有一个主函数,必须要有一个主函数, C 程序从主函数开始运行。
2.int main(void),int:返回值类型, main :函数名, void :参数
3.return 0,返回值是 0 。
2 注释
1.单行注释 //
2.多行注释 /* */
注意:不能在多行注释中嵌套多行注释
注释一个函数时通常用多行注释,注释某个语句用单行注释
3 C 程序执行的过程:
编辑---写代码的过程,生成 .c 文件
编译---检查语法错误的过程,生成 .obj 文件
连接---多个 .obj 文件合并成一个 .exe 文件的过程
运行---运行 .exe 文件的过程
4 C 程序的结构
项目---> 文件 ---> 函数 ---> 语句 ---> 单词
项目:后缀是 .sln
文件:源文件后缀是 .c
函数:可以有多个函数,但一定要有主函数
语句:以分号 ; 结尾
单词:不是单纯的英文单词,而是 标识符 ,标识符又分成: 关键字、预定义标识符、自定
义标识符 。 C 语言的标识符命名规范: 由字母、数字、下划线构成且第一个字符不能是数
字,且不能是系统占用的单词 。
5 进制的转换
在计算机内存储和运算数据时,通常要涉及到的数据单位有以下 3 种:
位(bit) :计算机中的数据都是以二进制来表示的,二进制的代码只有“ 0 ” “ 1 ”两 个数码,采用多个数码(0 和 1 的组合)来表示一个数,其中的每一个数码称为一位,位 是计算机中最小的数据单位。
字节(Byte) :在对二进制数据进行存储时,以 8 位二进制代码为一个单元存放在一 起,称为一个字节,即 1 Byte =8 bit 。字节是计算机中信息组织和存储的基本单位,也是计 算机体系结构的基本单位。在计算机中,通常用 B(字节)、KB(千字节)、MB(兆字节) 或 GB(吉字节) 为单位来表示存储器(如内存、硬盘、 U 盘等)的存储容量或文件的大小。
字长: 人们将计算机一次能够并行处理的二进制代码的位数,称为字长 。字长是衡量 计算机性能的一个重要指标, 字长越长 ,数据所包含的 位数越多 ,计算机的数据处理 速度越快 。计算机的字长通常是字节的整倍数,如 8 位、 16 位、 32 位、 64 位和 128 位等。
1.内存容量
1TB--->1024GB
1GB--->1024MB
1MB--->1024KB
1KB--->1024B byte(字节)
1byte--->8bit(位)
数制是指用一组固定的符号和统一的规则来表示数值的方法。如下图所示为计算机中常用的几种进位计数制的表示。
2.二进制与十进制的转换
1>将二进制数转换成十进制
10110 转换成十进制数: 先将二进制数 10110 按位权展开,再对其乘积相加,转换过程
如下所示。
2>将十进制转换成二进制数
除以 2 逆向取余法:
22(10)=10110(2)
3.二进制与八进制的转换
1>将八进制数转换成二进制:
每 1 个八进制位转换成 3 个二进制位,左边不足三个的则补 0。
5 6 7 ---> 101 110 111
2 3 4 ---> 010 011 100
2>将二进制数转换成八进制:
从右向左,每 3 个二进制位为一组,每一组转换成 1 个八进制数。
011 010 111 100 110 ---> 3 2 7 4 6
011 010 111 101 110--->32756
011 101 110 101 011--->35653
4.二进制与十六进制的转换
1>将十六进制数转换成二进制:
每 1 个十六进制位转换成 4 个二进制位,左边不足 4 个的则 补 0 。
0----0000
1----0001
2----0010
3----0011
4----0100
5----0101
6----0110
7----0111
8----1000
9----1001
A----1010 10
B----1011 11
C----1100 12
D----1101 13
E----1110 14
F----1111 15
1 2 8 9 A D F ---> 0001 0010 1000 1001 1010 1101 1111
2>将二进制数转换成十六进制:
从右向左,每 4 个 2 进制位为一组,每一组转换成 1 个十六进制数。
1110 1101 1111 1001 1110 ---> E D F 9 E
6 原码、反码、补码
数据在计算机里面都是以补码的形式存储。
正数 的原码、反码、补码都是一样的!
负数 的反码 是在原码的基础上“ 符号位不变,数值位取反 ”
负数 的补码 是在反码的基础上“ 符号位不变,数值位加 1 ”
原码 反码 补码
37:0010 0101--->0010 0101--->0010 0101
-37:1010 0101--->1101 1010--->1101 1011
数据类型、变量、常量
1 数据类型
C 语言的数据类型分为:基本类型和构造类型两种。
1.基本类型
1>字符型:特殊的整型,占据 1 个字节(1byte---8bit)
有符号字符型 signed char/char:有符号位
取值范围:1000 0000( -128 ) ----0111 1111( 127 )
无符号字符型 unsigned char:没有符号位,都是数值位
取值范围:0000 0000( 0 )---1111 1111( 255 )
2>整型:整数类型
有符号的整型 signed int/int , 占据 4byte
1000 0000 0000 0000 0000 0000 0000 0000( -2147483648 )---
0111 1111 1111 1111 1111 1111 1111 1111( 2147483647 )
无符号的整型 unsigned int , 占据 4byte
0000 0000 0000 0000 0000 0000 0000 0000( 0 )---
1111 1111 1111 1111 1111 1111 1111 1111 ( 4294967295 )
短整型 short int:占据 2byte
1000 0000 0000 0000( -32768 )---0111 1111 1111 1111( 32767 )
无符号短整型 unsigned short int: 占据 2byte
0000 0000 0000 0000( 0 )---1111 1111 1111 1111( 65535 )
长整型 long long int: 占据 8byte
( -9223372036854775808--9223372036854775807 )
无符号长整型 unsigned long long int: 占据 8byte
0--18446744073709551615)
3>实型:小数,浮点型,没有无符号的浮点型数据
float : 单精度浮点型,占据 4byte
double : 双精度浮点型,占据 8byte
long double : 长双精度浮点型,占据 8byte 或者 16byte
2.构造类型
数组
指针
结构体
共用体
枚举类型
2 变量
变量的概念:值可以发生改变的量
定义语法:类型名 变量名, 变量名 , 变量名 ;
类型名 变量名 = 初值 , 变量名 = 初值 ;
char a , b , c ;
int e ;
char a = 0 , b = 0 , c = 0 ;
char a = 0 ;
unsigned char e = 0 ;
int height = 170 ;
int weight = 0 ;
int a = 0 ;//在变量定义时,给变量赋值叫赋初值
a = 0 ;//不是赋初值,这叫赋值
注意:
1.变量名以字母、数字、下划线构成且第一个字符不能是数字,要符合标识符的命名规范,
且不能是系统占用的单词,如关键字 int、预定义标识符 printf 等。
char 8 Tom;// 错误的,数字不能作为第一个字符
MJ;//错误的,有空格
char Tom_MJ;//正确的
char MJ8;//正确的
int a * b;// 错误的, * 不符合标识符命名规范
int ab & c;// 错误的, & 不符合标识符命名规范
int _ab;//正确的
char int ;// 错误, int 是关键字,不能用来作为变量名
//变量名的字母 分大小写 , ab 和 AB 不是同一个变量名
int ab;
int AB;
2.变量要先定义再使用
a = 45;// 错误, a 要先定义再使用
char a ;
3.变量是占据内存的,占据的内存大小由变量的数据类型决定
如:char a;//a 占据 1byte
a = 10;
3 常量
常量:值不能发生改变的量
常量和变量一样,都占用内存空间
1.整型常量
int a = 0;
int a = 100; //100 是整型常量,占用 4byte
unsigned int a = 200U; //200 是一个无符号的整型常量
long int a = 200L; //200 是一个 long int 型常量
long long int a = 200LL; //200 是一个 long long int 型常量,占据 8byte
float f = 3.14f; //3.14 是一个单精度浮点型常量
double d = 3.14; //3.14 是一个双精度浮点型常量
long double ld = 3.14L; //3.14 是一个长双精度浮点型常量
2.十进制常量、八进制常量、十六进制常量的表示
char a = 11; //11 是十进制常量
char b= 0 11; //11 是八进制常量,以数字 0 开头表示的是八进制
char c= 0x 11; //11 是十六进制常量,以 0x 开头表示的是十六进制
3.转义字符常量:
看不到,常用于控制格式,比如换行或回车,'\n' '\r'
\字母 ,如 '\t'
\1-3 位八进制整数 ,如'\101' --- 'A'
\x1-2 位 16 进制数 ,如 '\x41' --- 'A'
转义字符只代表一个字符
4.常变量:用 const 修饰的标识符
const 用于限定 变量内存的使用权限 (修改成只读模式)
const int a = 45;
a = 100;// 错误,不能修改 a 的值
运算符与表达式
1 运算符与表达式
运算符 :+ - * / %
表达式 :由操作数和运算符组成的式子,如 a-b,1+2
C 语言中单一的一个变量或者单一的一个常量是 最简单的表达式
1.优先级与结合性
结合性 :同一优先级时,从左到右或者从右到左的运算顺序。
优先级 :参考下图,从 1 开始逐渐减弱
算术运算符和算术运算表达式
1. + - * / %
+ - * / :只要有一个运算对象是浮点型,则表达式的值为 double 型。
% 求余运算符 : 两个运算对象必须都是 整数 !
20 % 6.5 // 错误 ,不能是小数
2.自增++ 自减--
1> ++后缀:先读后写
int main(void)
{
int a = 0;
a = 20;
a++;//相当于 a = a + 1; 21
printf("%d\n", a++);//先读后写,先把 a 的值(21)读出来,再 a = a + 1;
printf("%d\n", a);//22
}
printf("%d\n", a++);
//相当于
//printf("%d\n", a);
//a = a + 1;
2> ++前缀:先写后读
int main(void)
{
int a = 0;
a = 20;
++a;//相当于 a = a + 1; a = 21
printf("%d\n", ++a);//先写后读,先 a = a + 1;再把 a 的值(22)读出来
printf("%d\n", a);//22
}
printf("%d\n", ++a);
//相当于
//a = a + 1;
//printf("%d\n", a);
3 关系运算符和关系运算表达式:> < == >= <= !=
关系运算表达式的值为 “真”或者“假”用“1”和“0”表示 。
int a = 15;
int b = 10;
a > b //1
a < b //0
a < 15 //0
a > 15 //0
a >= 15 //1
a == 15 //1
a == b //0
a != b //1
4 逻辑运算符和逻辑运算表达式
逻辑运算表达式的值为 “真”或者“假”用“1”和“0”表示。
参与运算的对象只要 不为 0 ,则运算对象 为真 。
1.&&逻辑与运算符:
参与运算的对象 都为真 (不为 0) ,结果才是 真 。
int a = 15;
int b = 10;
a > b && a < b//0
a > b && a != b//1
a && b//1
2.||逻辑或运算符:
参与运算的对象只要有一个为真(不为 0) ,结果就是真,只有 两个都是假的 ,结果才是 假 。
int a = 15;
int b = 10;
a > b || a < b //1 a>b为真,有真则为真
a > b || a != b //1
a < b || a == b //0 两边都为假,则为假
a || b //1 运算对象不为0,为真
3.!逻辑非运算符:
使表达式的值 由真变假,由假变真
int a = 15;
int b = 10;
!(a > b) //0 a>b为真
!(a < b) //1 a<b为假
!a //0
5 赋值运算符和赋值运算表达式:
简单赋值运算符: =
变量 = 表达式 ;
a = 45;
复合的赋值运算符: += -= *= /= %=
int a = 15;
a += 10; //a = a + 10; a = 25;
a -= 10; //a = a - 10; a = 15;
a *= 2; //a = a*2; a = 30;
a /= 2; //a = a/2; a = 15;
a %= 6; //a = a % 6; a = 3;
a++; // 相当于 a += 1;
a / = 10; // 错误 ,不能有 空格
6 逗号运算符和逗号运算表达式:,
表达式 1,表达式 2,表达式 3,...
逗号表达式的最终值是 最后一个 表达式的值,但是所有的表达式 都会运行 。
int main(void)
{
int a = 0;
int b = 0;
int c = 0;
a = 5;
b = 15;
c = 10;
printf("%d\n", (++a, ++b, c++));//10
printf("%d\n",a);//6
printf("%d\n", b);//16
}
7 sizeof 求字节运算符
sizeof(表达式) 结果为表达式的数据类型占据的字节数
int a = 10;
sizeof( int ) //4
sizeof(unsigned int) //4
sizeof(a) //4
sizeof(165) //4
sizeof(a + 10) //4
sizeof(float) //4
sizeof(double) //8
sizeof(long double) //8
8 强制类型转换运算符:(类型名)(表达式)
int main(void)
{
float a = 0;
int b = 0;
int c = 0;
float d = 0;
a = 7.5;
b = 2;
d = 1.5;
c = a * b;//c = 15.000 000 000 000 000;
printf("%d\n", c);//15
c = (int)a * b;//c = 7*2;
printf("%d\n", c);//14
c = (int)(a * b) ;//c = 15;
printf("%d\n", c);//15
c = a*b*d;//c = 22.5; c = 22
printf("%d\n", c);//22
c = (int) a *b*d;
printf("%d\n", c);//21
c = (int)a *b* (int)d ;
printf("%d\n", c);//14
}
9 不同类型的数据混合运算
为了保证运算的精度,计算机会自动转向精度高的数据类型进行转换
char 一定会转换为 int
float 一定会转换为 double
char b = 0;
float c = 0;
char d = 'M';
b = 'A'+ 32; //b = 65+32;
c = 7 / 2.0f; //c = 3.500 000 000 000 000;
四 输入与输出函数、选择结构
1 数据的输出和输入
把数据从计算机内存送到计算机外部设备上的操作称为“输出” 。
例如,把计算机运算结果显示在显示屏或打印机上,或者送到磁盘上保存起来。
从计算机外部设备将数据送入计算机内部的操作称为“输入” 。
说明: C 语言本身并没有提供输入输出语句 ,但是可以通过调用标准库函数中提供的输入 和输出函数来实现输入和输出。 C 语言中提供了丰富的输入和输出库函数。在调用标准库 中的函数时,必须包含标准库的头文件 stdio.h 。
写法:
#include <stdio.h>
2 输出函数
C 语言中,最常用的输出函数时 printf 函数,用来在终端设备上按照指定格式进行输出。
1.printf 函数的调用形式:
printf(格式控制,输出项 1,输出项 2,...);
说明:
格式控制是 字符串 的形式
在 printf 函数调用之后加上” ; ”, 才能构成一条完整的输出语句。
2.printf 函数的使用方法:
1>使用方法 1:输出单个数据--不换行
printf("%格式字符",输出的数据 );
说明:
格式字符 | 输出说明 |
c | 输出一个字符 |
d 或 i | 输出带符号的十进制整型数据,若为长整型用%ld ,短整型 %hd |
o | 以八进制格式输出整型数据,若以%#o,则在实际八进制数前加 了先导 0 |
x 或 X | 以十六进制格式输出整型数据,若以%#x,则在实际十六进制数前 加了先导 0x,格式字符的大小写决定了十六进制数中的大小写 |
f | 以带小数点的数学形式输出浮点型数据(单精度和双精度) |
e 或 E | 以指数形式输出浮点型数据 |
s | 输出一个字符串,直到遇到’\0’结束 |
% | %%,实际输出的是一个% |
注意:
float 类型数据一般有 7 位 有效数字
double 类型数据一般有 15 位 有效数字
2>使用方法 2:有数据需要原样输出的
int a = 100;
printf("a = %d",a); //输出的结果是: a = 100 ,输出结果不换行
3>使用方法 3:同时输出多个数据
int a = 110;
char c = 'a';
//调用一次 printf 函数,就能输出这两个变量的值
printf("%d%c\n",a,c);
printf("a = %d c= %c\n",a,c);
printf("a = %d,c= %c\n",a,c);
3.输出数据所占宽度说明
在做数据输出操作时,有的时候需要规定输出数据的宽度。
1>整型数据的输出宽度
int a = 250;
int b = 20;
要求输出的两行结果右对齐。
分析:
a 的数值有 3 位,b 的数值有 2 位
b 的数据前应该补一位空格 ,此时就要设定输出 b 的数据的宽度,输出的宽度应该为 3
printf("%d",a);
printf(" %3d ",b);
假设:
int a = 1234;printf("%6d\n",a); printf("%4d\n",a); printf("%3d\n",a); printf("%2d\n",a);
总结:
printf(“% m d”,a);
1> 若 m <= 实际数据的宽度,则按 实际情况 输出
2> 若 m > 实际数据的宽度,则在实际数据的 左边用空格补齐
3>printf( “ % 0m d ” ,a); 则实际的结果不够 m 位的在数据的 左边用 0 补齐
2>浮点型数据的输出宽度说明
浮点型:若用 %f 输出,则宽度为: 整数部分的位数+小数点+小数部分的宽度
float a = 3.14159;printf("%7.4f\n",a); printf("%6.6f\n",a); printf("%6.6f\n",a); printf("%0.3f\n",a);
总结 :
若 float a = 1.2345; ,以%f 输出
printf(“% m . n f” ,a);
m ----整个数据的宽度
n----小数位数
1>>实际小数位数>n,截去小数右边多余的小数,截去的第一位要注意 四舍五入
2>>实际小数位数< n,在小数的 最后变补 0
3>> m 省略,%.n , 则整数部分 按照实际输出 ,小数部分按照以上两个规则进行
4>> m < n+1,自动突破,按照实际数据进行输出
5>> m > n+1,整个数据的最左边补空格
4.输出的数据左对齐
由于输出的数据都是 隐含的右对齐 ,如果想要输出的数据实现 左对齐 ,可以在格式控制中 的 % 和宽度之间加一个“ - ”来实现。
double a = 3.141592653;
double b = 3.14;
printf("% - 10.7f,%f\n",a,b);
// 输出结果 :3.1415927 ,3.140000
//3.1415927 后面有一个空格
3 输入函数
数据的输入函数,通常会使用 scanf 函数。
scanf(格式控制,地址列表);
int a = 0;
scanf("%d",&a);
char a = 0;
scanf("%c",&a);//a = 'M';
注意:
1>scanf 函数中的地址列表应当是变量地址,不能是变量名。
scanf("%d",a);//错误,缺少 &
2>如果在格式控制字符串中除了格式字符还包括其他字符,则输入时要在对应的位置输
入相同的字符。
scanf("a=%d,b=%d",&a,&b);
要输入 :a=123,b=456
输入时 a= , b= 也要在对应的位置手动输入
3>在用%c 格式字符时,输入空格也是有效字符。
scanf("%c%c",&a,&b);
如果输入 :M N
则 a 为 'M',b 为空格字符
必须是输入 :MN
b 的值才是 'N'
4>在使用 %d 输入数据时,如输入空格、回车、Tab 键或遇到非法字符(不属于数值的字符),则认为数据输入结束。
scanf("%d%d",&a,&b);
输入时 :123 456
输入 123 后加空格表示 123 输入完成并赋值给 a
4 算法的基本结构
算法的三种基本结构:顺序结构、选择结构(分支结构)和循环结构。
顺序结构:
按语句书写的先后顺序依次执行的结构。
复合语句:
由大括号{}中的 0 个或多个声明和语句列表共同构成。
int main(void)
{
int a = 0;
int b = 0;
a = 5;
b = 4;
{
int a = 6;//变量声明
printf("%d\n",a);//这个 a 的值是 6,和前面的 a 不是同一个
a++;//自增表达式语句
printf("%d\n",a);//函数调用语句
++b;
}
printf("%d\n", a);//这个 a 的值是 5
printf("%d\n",b);
return 0;
}
注意:
1>复合语句不以分号;作为结束符,即 最后的}后面不加分号 。
2>在复合语句中 可以定义变量,但仅在复合语句中有效 ,即作用域是{}括起来的部分。
int main(void){ int b = 0; b = 4; { int a = 6; printf("%d\n",a); a++; printf("%d\n",a); ++b; };//错误,不能加; printf("%d\n", a);//错误,a 没有定义 printf("%d\n",b); return 0; }
选择结构(分支结构)
根据条件判断来选择执行哪一条语句。
选择结构的语句有: if 条件语句 和 switch 多路分支语句 。
1.if 语句
if(条件表达式)
语句 1;
执行过程:如果条件表达式的值为真,则执行语句 1,否则不执行语句 1。
//输入 a 和 b 的值,判断并输出最大值
int main(void)
int main(void)
{
int a = 0;
int b = 0;
int max = 0;
printf("请依次输入 a 和 b 的值:");
scanf("%d%d",&a,&b);
max = a;
if(max < b)
max = b;
printf("max:%d\n",max);
return 0;
}
if 条件语句中的 语句 1 不是只有一条语句的意思,可以是多条语句用 {} 括起来的复
合语句。
int main(void){ int a = 0;
int b = 0;
int max = 0;
printf("请依次输入 a 和 b 的值:");
scanf("%d%d",&a,&b);
max = a;
if(max < b)
{
max = b;
printf("a < b \n");
}
printf("max:%d\n",max);
return 0;
}
2.if...else 语句
if(条件表达式)
语句 1;
else
语句 2;
执行过程:如果条件表达式的值为 真,则执行语句 1 ,否则执行语句 2 。
//输入 a 和 b 的值,判断并输出最大值
int main(void)
{
int a = 0;
int b = 0;
int max = 0;
printf("请依次输入 a 和 b 的值:");
scanf("%d%d",&a,&b);
if(a < b)
max = b;
else
max = a;
printf("max:%d\n",max);
return 0;
}
3.if...else if 语句
if(条件表达式 1)
语句 1;
else if(条件表达式 2)
语句 2;
else if(条件表达式 3)
语句 3;
....
else
语句 n;
执行过程:依次判断条件表达式的值,当某个值为真时,则执行相应的语句,然后跳出
整个 if 语句之外,继续执行后面的程序。如果所有的 表达式都为假,则执行语句 n, 然后
继续执行后面的程序。
//输入成绩分数,并判断该成绩属于哪个等级
int main(void)
{
int score = 0;
printf("请输入成绩:");
scanf("%d",&score);
if (score >= 0 && score <= 100)
{
if(score >= 90)
printf("A+\n");
else if(score >= 80)
printf("A\n");
else if(score >= 70)
printf("B+\n");
else if(score >= 60)
printf("B\n");
else
printf("不合格\n");
}
else
printf("请输入合法的成绩!");
return 0;
}
4.if 语句嵌套
当 if 语句中的执行语句又是 if 语句时,则形成了 if 语句嵌套。
if(条件表达式)
if 语句;
或者
if(条件表达式)
if 语句;
else
if 语句;
1 修改下面的程序使程序:输入 a 和 b 的值,判断最大值是否大于 100,是则输出最大值。
int main(void){ int a = 0;
int b = 0;
printf("请依次输入 a 和 b 的值:");
scanf("%d%d",&a,&b);
if(a < b)
if(b > 100)
printf("max:%d\n",b);
else
if(a > 100)
printf("max:%d\n",a);
return 0;
}
注意:C 语言规定,else 总是与它前面最近的为配对的 if 配对。
//所以修改后应为:int main(void){
int a = 0;
int b = 0;
printf("请依次输入 a 和 b 的值:");
scanf("%d%d",&a,&b);
if(a < b)
{
if(b > 100)
printf("max:%d\n",b);
}
else
{
if(a > 100)
printf("max:%d\n",a);
}
return 0;
}
2 输入 a 、
b
、
c
的值,判断并输出最大值
int main(void){ int a = 0;
int b = 0;
int c = 0;
int max = 0;
printf("请依次输入 a、b、c 的值:");
scanf("%d%d%d", &a, &b,&c);//
if (a > b)
{
if (a > c)
max = a;
else
max = c;
}
else//b > a
{
if (b > c)
max = b;
else
max = c;
}
printf("max:%d\n", max);
return 0;
}
5.switch 多路分支语句
switch(表达式)//1
{
case 常量表达式 1:语句 1(集合);
case 常量表达式 2:语句 2(集合);
...
case 常量表达式 n:语句 n(集合);
default:语句 n+1;
}
执行过程:首先计算表达式的值,与常量表达式 i 进行比较,如果与其中一个常量表达式 i 的值相等,就执行其后的语句 直到遇到 break 语句才结束 switch 语句 ,如果 case 后无 break
语句,则继续执行随后所有的 case 后的语句 。如果没有找到与表达式的值相匹配的常量表达式,则执行 default 后的语句 n+1 。
输入数字 1-7 ,并输出显示对应的星期
int main(void){ int week = 0;
printf("今天星期几:");
scanf("%d", &week);//1---'1'
switch (week)//week 是表达式
{
case 1:printf("今天是星期一\n"); break;
case 2:printf("今天是星期二\n"); break;
case 3:printf("今天是星期三\n"); break;
case 4:printf("今天是星期四\n"); break;
case 5:printf("今天是星期五\n"); break;
case 6:printf("今天是星期六\n"); break;
case 7:printf("今天是星期天\n"); break;
default:printf("输入数据有误!\n");
}
return 0;
}
注意:
1>switch 后面括号中的表达式可以是 整型、字符型和枚举型
。
2> 在 case
后的各常量表达式的值
不能相同
3> 在 case
后,允许有多个语句,可以不用
{}
括起来,而整个
switch
结构一定要有一对
{}
4> 各 case
和
default
语句的先后
顺序可以改变
,不影响程序执行结果。
6.条件运算符和条件运算表达式: (?:)
表达式 1 ? 表达式 2 : 表达式 3
求值过程:如果 表达式 1 的值为 真 ,则以 表达式 2 的值作为条件表达式的值,否则以 表达式 3 的值作为条件表达式的值 .
五 循环结构
//输入 a、b 的值,判断并输出最大值,使用条件表达式。
int main(void){ int a = 0;
int b = 0;
int max = 0;
printf("请依次输入 a 和 b 的值:");
scanf("%d%d",&a,&b);
max = a>b?a:b;
printf("max:%d\n",max);
return 0;
}
循环结构语句
什么时候用到循环结构:处理重复的问题的时候。
循环结构的三大语句: while 语句、do while 语句、for 语句 。
1.while 语句
while(循环条件表达式)
循环体语句;
执行过程:只有循环条件表达式的值为 真就 执行循环体 语句,先判断后执行。
1. 输出 1---n
之间的数
int main(void){ int i = 1;
int n = 0;
printf("请输入 n 的值:");
scanf("%d",&n);//10 15
while(i <= n)
{
printf("%d\n",i);
i++;
}
return 0;
}
2. 计算 m+...+n
的值
int main(void){ int n = 0;
int m = 0;
int sum = 0;
printf("请依次输入 m 和 n 的值:");
scanf("%d%d",&m,&n);//m+...n 10 15
while (m <= n)
{
sum = sum + m;
m++;
}
printf("sum=%d\n", sum);
return 0;
}
2.do...while 语句
do
{
循环体语句;
}while(循环条件表达式);
执行过程: 先执行 循环体语句, 再检查 循环条件表达式的值是否为真,如果为真则继续 执
行循环体语句,否则结束循环。
1计算 m+...+n 的值,使用 do while 语句。
int main(void){ int n = 0;
int m = 0;
int sum = 0;
printf("请依次输入 m 和 n 的值:");
scanf("%d%d",&m,&n);//m+...n 10 15
do
{
sum = sum + m;
m++;
}while (m <= n);
printf("sum=%d\n", sum);
return 0;
}
2输出 1---n 之间的数,使用
do while
语句
int main(void){ int i = 1;
int n = 0;
printf("请输入 n 的值:");
scanf("%d",&n);//10 15
do
{
printf("%d\n",i);
i++;
}while(i <= n);
return 0;
}
while 语句和 do...while 语句的区别
:
while 语句是先判断后执行,do...while 语句是先执行,至少会执行一次。
for 语句
for( 表达式 1 ; 表达式 2 ; 表达式 3 )
循环体语句;
说明:
表达式 1 :设置初始条件, 只执行一次 ,为 0 个或多个变量设置初值。
表达式 2 :是循环条件表达式,用来判定是否继续循环。在每次 执行循环体之前 要先执行
表达式 2,然后再决定是否继续执行循环。
表达式 3 :作为 循环的调整 ,比如是循环体变量增值,它是执行循环体语句之后再执行。
1.while 语句与 for 语句的替换:计算 1+2+3+...+n 的值
使用 while 语句实现
:
int i = 1;while(i <= n){
sum = sum + i;
i++;
}
使用 for 语句实现
:
int i = 1;for(i = 1;i <= n;i++){
sum = sum + i;
}
2. 输出 1---n
之间的数,使用
for
语句。
int main(void){ int i = 1;
int n = 0;
printf("请输入 n 的值:");
scanf("%d",&n);//10 15
/*while(i <= n)
{
printf("%d\n",i);
i++;
}*/
for(i = 1;i <= n;i++)
{
printf("%d\n",i);
}
return 0;
}
3.计算 m+...+n 的值,使用
for
语句。
int main(void){ int n = 0;
int m = 0;
int sum = 0;
printf("请依次输入 m 和 n 的值:");
scanf("%d%d",&m,&n);//m+...n 10 15
/*while (m <= n)
{
sum = sum + m;
m++;
}*/
for(;m <= n;m++)
{
sum = sum + m;
}
printf("sum=%d\n", sum);
return 0;
}
注意:
1>for 语句的 三个表达式不是必须的 。
2>当条件表达式 ( 表达式 2)的值为假(为 0)时 for 循环语句就结束
。
3>可以在循环体内执行 break,continue,goto
语句。
4> 表达式 2 是空 的,表明表达式
2
的值一直是真,即
死循环
。
for(;;)//死循环语句
{
}
相当于
while(1)
{
}
小结:
for(i=m;i <
n;i++)//循环次数
:n-m
次
for(i=m;i <=
n;i++)//循环次数
:n-m+1
次
中断语句
break 语句 :跳出本层循环,执行循环后的语句。
continue 语句 :跳出本次循环,执行下一次循环。
goto 语句 :跳出到指定的标号位。
1.break 语句
1 计算 m+...+n 的值,当累加的值大于
100
时退出循环
int main(void){ int n = 0;
int m = 0;
int sum = 0;
printf("请依次输入 m 和 n 的值:");
scanf("%d%d",&m,&n);//m+...n 10 50
for(;m <= n;m++)
{
sum = sum + m;
if(sum > 100)
break;
}
printf("sum=%d\n", sum);
return 0;
}
2 输出 1---n 之间的数 ,当输出的数大于 100 时结束循环
int main(void){ int i = 1;
int n = 0;
printf("请输入 n 的值:");
scanf("%d",&n);//10 15
for(i = 1;i <= n;i++)
{
printf("%d\n",i);
if(i > 100)
break;
}
return 0;
}
2.continue 语句
只用于结束本次循环 ,即 直接去执行表达式 3 .
int main(void)
{
int i = 1;
int n = 0;
int sum = 0;
printf("请输入 n 的值:");
scanf("%d", &n);//150
for (i = 1; i <= n; i++)
{
sum = sum + i;
printf("sum:%d\n",sum);
if (i > 100)
continue;
printf("i=%d\n", i);
}
return 0;
}
3.goto 语句(了解)
int main(void)
{
int i = 1;
int j = 0;
int k = 0;
for (j = 0; j < 2; j++)//2
{
for (i = 0; i < 15; i++)//15
{
if (i == 10)
goto again;
printf("i=%d\t", i);
}
}
again:printf("穿越啦\n");
return 0;
}
六 函数
1 函数的定义
函数的定义:包括两个部分,分别是“ 函数头 ”和“ 函数体 ”。
返回值类型 函数名(形式参数 1, 形参 2, ...)// 函数头
{
}// 函数体
注意 1 :函数的返回值和参数可以是 任意类型 ,包括空类型!!
void printfStart(void)//打印一行星号
{
printf("************\n");
return;
}
注意 2 :函数名是一种标识符,必须符合标识符的命名规则!通常用动词
注意 3 :函数的参数可以是一个变量
void sel(int n)//n 表示输入的分数
{
if (n > 90)
printf("你的成绩属于优秀!");
else if (n > 80)
printf("你的成绩属于良好!");
else if (n > 70)
printf("你的成绩属于中等!");
else if (n > 60)
printf("你的成绩属于及格!");
else
printf("你的成绩属于不及格!");
}
总结:
1.函数名要 符合标识符命名规则
2.定义时的参数叫 形参,个数没有限制 ,类 型没有限制
3. 返回值的类型没有限制
4.return 表达式:
return 语句后面的表达式是 可以省略 的
如果 return 后有表达式则返回值类型必须和表达式类型 一致
如果 return 后没有表达式则用于中断函数执行
函数不调用是无法得到运行的,函数要想被执行必须调用之
2 函数的调用
语法 : 函数名(实际参数 1,实参 2,。。。。)
注意:
1 > A 函数 调用 B 函数 ,则 A 函数叫主调函数 , B 叫被调用函数
2 > 调用的参数个数、顺序、类型要与定义相同 demo add(1, 2);
3 > 函数调用步骤
step1.实参的值赋值给形参
step2.执行函数体
step3.返回主调函数
3 函数的声明
声明的方式: 只保留函数头 且后面 加分号
总结:
函数的定义:包括 函数头 和 函数体
函数的调用:用于执行定义的函数,通常 先定义后调用
函数的声明:用于 扩展函数名称的作用域 ,使得可以先声明后使用!
4 函数的设计原则
1.一个函数实现一个功能
2.返回值的原则:如果计算有结果需要加返回值
3. 形参 的设计及原则:如果计算的过程需要有数值进行
辅助
, 则需要加参数。
4.如果函数有形式参数则必须进行 参数检查 ,检查参数是否有 异常。
通常用 分支结构 (选择结构)进行参数检查,如果有错误则返 回-1
5.函数体的设计思路
第一步:定义变量
第二步:逻辑关系运用,选择结构还是循环结构还是综合运用。
1.定义一个函数实现:求 n 以内的奇数累加和。
主函数实现:输入 n 的值,调用该函数后, 输出对应的累加和。
int sum(int n);int main(void){
int m = 0;
int result = 0;
printf("请输入一个整数:");
scanf("%d",&m);
result = sum(m);
if(result == 0)
printf("形参异常!\n");
else
printf("%d 以下的奇数的累加和是:%d\n",m,result);
return 0;
}
//函数的功能:求奇数的累加和,1+3+5+...+n
int sum(int n)
{
int i = 0;
int s = 0;
if(n<1)//形参的异常检查
return 0;
//for(i=1;i<=n;i++)
//{
// if(i%2 != 0)//if(i%2 == 1)//if(i%2)
// s = s + i;
//}
for(i=1;i<=n;i+=2)
{
s = s + i;
}
return s;
}
2.定义一个函数实现:计算 10 - 1/2 - 1/3 - ...- 1/n 的值。
主函数实现:输入 n 的值, 调用该函数后,输出对应的结果。
float sum_div(int n);//函数的声明int main(void){
int m = 0;
float s = 0;
printf("请输入一个整数:");
scanf("%d",&m);
s = sum_div(m);
if(s == 0)
printf("形参异常\n");
else
printf("10-1/2-1/3-...-1/%d 的值:%f\n",m,s);
return 0;
}
//函数要实现的功能:计算 10 - 1/2 - 1/3 - ...- 1/n 的值
float sum_div(int n)
{
int i = 0;
float sum = 10;
if(n<2)//判断形参是否异常
return 11;
for(i=2;i<=n;i++)
{
sum -= 1.0/i;
}
return sum;
}
3.定义一个函数实现:
根据 x 求 y 的值。主函数实现:输入 y 的值,调用该函数后,输出对应的结果。
int y_value(int x);//函数的声明int main(void){ int m = 0;
int y = 0;
printf("请输入一个整数:");
scanf("%d",&m);
y = y_value(m);
if(y == -1)
printf("形参异常\n");
else
printf("x:%d,y:%d\n",m,y);
return 0;
}
//函数要实现的功能:求 y 的值
int y_value(int x)
{
int y = 0;
if(x<1)
y = 2*x;//return 2*x;
else if(x>=1 && x<5)
y = 3*x - 2;//return 3*x - 2;
else if(x>=10)
y = 4*x - 3;//return 4*x - 3;
else//形参异常
y = -1;//return -1;
return y;
}
七 递归调用、作用域和存储类别
1 函数的递归调用
1>递归的概念
C 语言中的函数可以递归调用,即:可以 直接或者间接地自己调用自己 。
2>递归思想应该关注的几点:
(1)找到规律
(2)递归调用的条件
(3)结束递归调用的条件
1. 使用递归调用的形式编写函数实现求 :1+2+3+...+n
#include <stdio.h>int sum(int m);//函数的声明int main(void)
{
int n = 0 ,s = 0;
printf("请输入 n 的值:");
scanf("%d",&n);
s = sum(n);//函数的调用
printf("1+2+3+...+%d 的值为%d\n",n,s);
return 0;
}
int sum(int m)
{
if(m<1)//形参异常检查
return -1;
else if(m==1)//当形参为 1 时返回 1,即结束递归调用的条件
return 1;
else
return m+sum(m-1);
}
2 作用域
1.作用域:一个代码空间
作用域解决的是标识符的使用范围,是空间的问题。
分类:
文件作用域:从文件头到文件尾的代码空间。
函数作用域:函数的参数和函数体属于函数作用域,函数的返回值和函数名属于文件作用 域。
注意:
1>在同一个作用域内,不能出现相同的标识符,同一个作用域内,不能重复定义变量名。
int foot(void){ int a = 0;
}
void foot(void)//错误,函数名不能相同
{
char a = 0;
}
int main(void)
{
char a;
char a;//错误,重复定义变量 a
return 0;
}
2>一个标识符不能同时属于两个作用域,使用就近原则
#include <stdio.h>char height = 10;//height 属于文件作用域int main(void)
{
char height = 12;//height 属于函数作用域
printf("%d\n",height);//使用的是函数里面的 height,结果:12
return 0;
}
3>局部变量:就是在函数作用域或者是语句块作用域中定义的变量 全局变量:就是在文件作用域中定义的变量(实际开发中尽量不要使用全局变量)
4>全局变量和函数都属于文件作用域内的标识符,文件作用域内的标识符是可以通过 extern 扩展作用域的
//指出下面程序的错误int main(void){
foo();//error
printf("%d", g_a);//error
return 0;
}
void foo(void){}
int g_a = 0;
//改进如下
extern void foo(void);
extern int g_a;
int main(void)
{
foo();//error
printf("%d", g_a);//error
return 0;
}
void foo(void){}
int g_a = 0;
3 存储类别
1.存储类别解决的是标识符的“ 生命周期 ”或者 变量内存的开辟时间和销毁时间
2.学习 存储类别 时不要去考虑 作用域,两者没有关系 !
void foo(int a)
{
int b = 0;
}//a 内存销毁
int main(void)
{
foo(10);//a 内存开辟
return 0;
}
4 栈变量:auto 声明的变量
变量 内存开辟 时间:栈变量是在 执行到变量定义语句时 开辟内存
变量 内存销毁 时间: 所在作用域结束后 销毁
void foo(int a)
{
int b = 0;//b 开辟内存
{
int i = 0;//i 开辟内存
}//i 内存销毁
i = 10;//错误,i 内存已经销毁
}//b 内存销毁,a 内存销毁
int main(void)
{
foo(10);//a 开辟内存
foo(20);//a 重新开辟内存
return 0;
}
注意: 只有局部变量可以用 auto 修饰,全局变量不行,默认情况下是可以省略。
auto int a = 0;//错误,a 是全局变量不能用 auto 修饰
int main(void)
{
auto int i = 0;
int b = 0;
}
5 全局区变量:用 static 声明的变量
变量 内存开辟 时间: 编译时
变量 内存销毁 时间: 主函数结束时
void foo(int a)
{
static int b = 0;//b 编译时开辟内存,该语句只在编译时执行一次,后面不再执行
{
int i = 0;//i 开辟内存
}//i 内存销毁
b++;
printf("%d\n",b);
}//a 内存销毁
int main(void)
{
foo(1);//a 开辟内存
foo(2);//a 重新开辟内存
return 0;//主函数结束时 b 销毁内存
}
注意:
1>并非所有的变量都可以声明为 static,形式参数不能声明为 static,只能声明 为 auto.
void foo(static int a);//错误,形参 a 不能用 static 声明void foo(auto int a);//正确
2>变量声明为 static 时,不赋初值时默认为 0.
void foo(void){ static int count;//默认是 0
count++;
printf("%d", count);
}
int main(void)
{
foo();
foo();
foo();
return 0;
}
3>全局标识符如果用 static 修饰,并不是表示在全局区而是表示该标识符只能在本文件内被扩展使用。
main.c:extern int g_a;//正确static int g_a;
fun.c
extern int g_a;//错误main.c:extern void foo(void);//正确static void foo(void){};
fun.c
extern void foo(void);//错误
八 指针与变量
1 指针的预备知识
int a = 0;
1.变量是要占据内存的。
2.内存的大小由数据类型决定。
char b = 0;//b 占据 1byte
3.变量名是内存的标识,用来读写内存
b = 10;//写内存
printf("%d\n",b);//读内存
4.内存是有地址的,每个字节都有一个唯一的整数作为编号, 这个整数就是地址。
2 指针的基本概念和指针常量
1.什么是指针:
指针就是地址。
2.怎么获取变量的地址:
取地址符号 &
int a = 10;
printf("%d\n",a);//输出 a 的值
printf("%d\n", &a);//输出 a 的地址
3.C 语言中地址绑定一块内存
int 地址绑定 4byte
double 绑定 8byte
char 绑定 1byte
4.指针(地址)常量的写法
int a = 0;
float f = 3.14f;
double d = 3.14;
char c = 'M';
&a;&f;&d;&c;//指针常量
4 = 100 ; //错误 ,常量 4 不能被修改
&a = &b; //错误 ,&a 是指针常量不能修改
int a;
int b = 10;
a = b;//a = 10;
3 指针的类型
int a = 0;//那么&a 的类型名是 int *
double d = 0;//那么&d 的类型名是 double *
char c = 0;//那么&c 的类型名是 char *
long long int L = 0;//那么&L 的类型名 long long int *
*:指针运算符
int * 绑定 4byte
double * 绑定 4byte
char * 绑定 4byte
4 指针变量的定义
普通变量的定义:类型名 变量名 = 初始值;
int a = 0;
指针变量的定义:类型名 变量名 = 初始值;
int * a;//int *是类型名,a 是指针变量
int * b = 10;//错误,10 是整型常量,不是地址常量
int c = 0;
int * d = &c;//正确
int e = 0,f = 0;
int * g = &e,h = 10,*i = &f;//指针变量 i 前面的*不能少,h 是 int 型变量
5 指针变量的基本用法
int a = 0;
int * b = &a;
*b = 100;//*b 是 a 的小名或别名,a 和*b 都标识同一块内存