导图社区 c语言
关于朱鸣华、刘旭麒、杨辉等编著的C语言程序设计教程,我对文章中的内容做了一个梳理
编辑于2023-11-02 09:33:35c语言程序设计
其它
子主题
子主题
子主题
子主题
概述
背景
特点
开发步骤
1,编辑源程序
文件方式存在,扩展名.c
2,编译源程序
1源程序转换为二进制形式的1目标程序,扩展名为.obj
全部内容检查:拼写,语法等
显示错误
error
warning
3,连接目标文件
得到一个或多个目标文件
所有目标文件+系统的库文件+系统提供的其它信息=可执行的二进制文件,扩展名为.exe
4,运行程序
5,结果分析
组成与结构
多个源程序
编译预处理
全局变量说明
函数
主函数
函数
函数头
函数体
说明部分
注释
执行语句
关键字
表达式
变量
常量
运算符
函数头
类型说明符
说明函数返回值的类型
函数名
用来标识一个函数
参数(形参表)
用来接受调用函数者传递给函数的数据
参数传递方式
值传递
不是同一个内存块
地址传递
是同一个内存块
数组作为函数参数
一维数组
float average(float a[])
二维数组
int exchange(int a[][3])
调用者的实参采用数组名
实参数组与形参数组类型一致,行数不一致、列数必须一致
编译预处理
宏定义
#define 宏名 替换文本
任何位置,引用之前
替换文本
常量、表达式、格式串。若有运算符加括号
纯文本替换
分类
无参
有参
参数任意类型
文件包含
作用
使一个源程序文件包含另一个源程序文件全部包含进来
形式
#include <文件名> 或”文件名“
只能包含一个文件名
”“先当前目录再系统路径
条件编译
形式
if格式
#if 表达式 程序段1; 【#else 程序段2;】 #endif
ifdef格式
#ifdef 宏名 程序段1; 【#else 程序段2;】 #endif
函数
使用方法
先定义后使用
声明
类型说明符 函数名(参数表)
函数调用
嵌套
递归
分类
种类
主函数
必须有且有且只有一个
程序的入口、从main开始结束与main
主函数的特定形式和命名是标准的,这是因为编译器会在启动程序时查找特定的函数名作为入口点
int main() { // 主函数的代码 return 0; }
用户自定义函数
系统提供的库函数
printf/scanf
范围
内部函数
static int sum(int a,int b)
不同文件中有同名函数互不干扰
外部函数
extern char compare(char s,char b)
不允许使用goto函数转到另一个函数
常量
两大属性
数据类型
本身隐含决定的
常量名
符号常量,采用大写
一般采用宏定义
#define PI 3.14159
含义清楚,一改全改
变量
三大属性
数据类型
决定该块内存的大小
数据类型
基本类型
整型
维度
基本、短、长
基本
int
标准形式
短整型
short
长整型
long
L
有无符号(有无负数)
无
unsigned
表达形式
十进制
八进制
0
十六进制
ox
字节数及其取值范围
字符型
表示一个字符值(ASCII--二进制形式存储),占一个字节,当作整型处理
维度
字符常量
转义字符
\0\a\b\t\n\r\f\v\''\'\\\ddd\xhh
字符变量
char a = 'b';
字符串常量
"XXX"
内存空间连续
多一个\0
浮点型
维度
单、双、长双
单
float
6-7
双
double
15-16
标准形式
长双
long double
变量、常量
表示形式
十进制小数
指数形式
实数(整数)+e/E+整数
一般作为双精度处理,单精度后加f
指针类型
枚举类型
空类型
构造类型
数组类型
一维数组
定义
int a[8]
float b[N]
int c['a']
引用
一次一个元素
下标为
数值常量
符号常量
字符常量
变量
算术表达式
函数返回值
注意:不进行下标越界检测,下标从0开始
初始化
定义初始化
全部
int a[2]={1,2};
int a[]={1,2}
可以不指定数组长度
局部
int a[2]={1};
其余默认为0
单一赋值
二维数组
定义初始化
全部
int a[2][2]={1,2,3,4};
int a[2][2]={{1,2},{3,4}};
int a[][2]={1,2,3,4}
可以不指定数组行长度,但是列必须要
局部
int a[][2]={{1},{2,3},{4}}
其余默认为0
按行优先存储
单一赋值
字符数组
字符串定义和引用与数组类似
输入与输出
输出
char c[]="hello"; printf("%s",c);
c是内存地址不加&
输入
需要考虑长度+1=定义空间大小
因为字符串多一个\0
scanf是以空格作为字符串结束标志
gets是以回车作为字符串结束标志
gets[c]
输入带空格的话一般采用初始化,或者gets函数
字符串处理函数:#include<string.h>
输出字符串
puts[c]
输入字符串gets
gets[c]
字符串连接函数
strcat[c,c1]===c+c1
c1替代c的\0
字符串赋值
strcopy(c,字符串)
字符串比较
strcmp(字符串1,字符串2)
等于为0
大于为正
小于为负
if(strcmp(字符串1,字符串2)==0)
字符串长度
strlen[c]
字符串小写
strlwr[c]
大转小
字符串大写
strupr[c]
小转大
结构体类型
应用场景
关系密切但数据类型不同的数据
组成
不同类型的数据组成
对应的每一种数据叫做该结构体的成员
结构体成员可以嵌套另一个结构体
引用时注意逐级访问
定义
struct 结构体类型名 { 数据类型 成员1; 数据类型 成员2; 。。。。 };
当成一个整体,也就是一个数据类型来处理
此时不分配存储单元
结构体变量的定义 struct student { long num; char name[20]; };
1,struct student stu1,stu2;
跟平时定义变量一样,只不过多一个struct关键字
2, struct student { long num; char name[20]; }stu1,stu2;
3, struct { long num; char name[20]; }stu1,stu2;
该结构体没有名字
引用··
方式
结构体变量名.成员名
stu1.num=1001
"."是成员运算符,运算符中优先级最高
可以引用结构体成员地址和结构体变量的地址
结构体成员变量与普通变量一样进行各种运算
初始化
数组的扩充等同于数组的初始化
定义结构体变量时的初始化
struct student { long num; char name[20]; }stu1={200,"nihao"};
结构体数组
含义
数组中的每一个元素都是结构体类型的变量
定义
与结构体变量的定义方法相同
引用
初始化
结构体指针
含义
指向结构体变量的指针,用一个指针变量来存放结构体变量的起始地址
形式
struct student stu1,*p = &stu1;
等价形似
stu1.num
(*p).num
p->num
为了防止(*p).num---->*p.num
结构体数组指针
形式
struct student sta[3],*p ;
for(p =sta ;p<sta+3; p++ )
p=&sta[1].num,这样的表达是错误的
更正:p=sta;或者p=&sta[0/1/2]
与函数之间的关系
参数
值传递
结构体变量
实参和形参都是结构体变量名
实参的值不能被修改,因为分配在不同的内存空间
地址传递
结构体指针变量
结构体数组
共用体类型
对比
结构体变量是各种类型数据成员的集合,各成员占用不同的内存空间
共同体变量是从同一起始地址开始存放各个成员的值,空间共享,在某一时刻只有一个成员起作用
定义
共用体类型形式
union data { int m; float x; char c; };
共用体变量
union data { int m; float x; char c; }; union data a,b;
union data { int m; float x; char c; } a,b;
union { int m; float x; char c; } a,b;
分配内存大小为成员中占最大字节,这里是float
引用
union data a,*p=&a;
1,a.m
普通共用体变量
2,p->m
共同体指针变量
可以整体引用,这里不同于结构体
union data a,b;
a=b;
初始化
在共用体变量定义的同时只能用第一个成员的类型值进行初始化
union data a={8}
这是非法的
union { int i; char ch; float f; } a={1,'t',2.6}; a=1; m=a;
最后一个才有效
a.i=2; a.f=90.5; a.ch='b';
a.ch
注意事项
不能使用共同体变量作为函数参数,做函数返回值也不行,可以使用指向共用体变量的指针
共同体变量可以出现在结构体类型定义中,也可以定义共用体
枚举类型
场景
变量的取值只有几种可能,如星期几,枚举可以将其一一列举出来
定义
类型
enum flag{true,false};
枚举值从0开始,依次递增
true为0,false为1
true>false
0>1
true=3``
枚举值本身是常量,不允许赋值
typedef
针对类型名取别名
typedef int ZS; ZS a=12;
tydedef struct {int a;int b;}DATA; DATA d;
注意
只可以声明类型名,不能定义变量
只能针对现在存在的类型,不饿能构造新的类型
可以自定义一个属于自己的数据类型,用#include包含就好了
变量名
符号地址
具体的内存地址
命名规则与标识符完全相同
标识符
命名的有效序列
规则
不能使用关键字
区分大小写
字母/下划线+数字
见名知意
变量值
本质
一块内存
使用方法
先定义,在赋值,后使用
定义
指定数据类型和变量名
分类
作用域
局部变量
它的函数和复合语句
全局变量
定义点到源文件结束
extern:定义点之前用
就近原则
局部和全局冲突
存在的时间
静态存储变量
动态存储变量
存储空间
程序区
可执行程序的机器指令
静态存储区
程序运行期间需要占用固定存储单元的变量
全局变量
动态存储区
程序运行期间需要占用动态分配存储单元的变量
局部变量、形参变量
存储方法
自动型
局部变量
函数内定义的变量默认自动型
静态型
static 类型说明符 变量名
默认值数值类型为0,字符变量为空字符
编译过程中赋初值,只赋一次初值
寄存器型
register int a
缩短存取时间
只有局部自动变量和形参可作为寄存器变量
全局变量和局部静态变量不行
不能长时间占有cpu
int char 可以,long/double/float不行,太长了
外部型
全局变量,默认初值为0
静态全局变量,自己用
extern
只能用来说明变量
不能用来初始化变量
运算符
两大属性
优先级+结合方向
分类
算数运算符
+、-、*、/、%、++、--
%
两边都是整数
正负符号与被除数符号一致
关系运算符
==、<、>、!=、<=、>=
逻辑运算符
!、&&、||
位运算符
<<、>>、~、|、^、&
^(异或)
相同为0,不同为1
<<
乘
>>
除
赋值运算符
X=
X=算数+位
逗号运算符
,X,Y,Z;
从左到右,结果为右
三目运算符
逻辑判断?:Y:N;
指针运算符
*、&
强制运算符
(int)
其它
函数调用()
类型转换
隐式转化
1,转为标准
2,由低向高
强制转换
将要转的内容用括号框起来
是一个中间值
优先级高于取余运算符
表达式
用运算符将操作对象连接起来,符合c语言语法的式子
值
数值和地址
关键字
auto
声明自动变量
break
用于跳出循环或 switch 语句
case/char/const/continue
switch 语句中的一个分支
声明字符类型的变量。
声明常量。
跳过循环的当前迭代。
default/do/double
switch 语句的默认分支。
do-while 循环的一部分。
声明双精度浮点类型的变量。
else/enum/extern
if 语句的可选部分。
声明枚举类型。
声明一个变量或函数是在其他文件或程序中定义的。
float/for
声明单精度浮点类型的变量。
for 循环。
goto
跳转到程序中的另一个位置。
if/int/inline
条件语句。
声明整数类型的变量。
建议编译器内联函数,但不是强制的。
long
声明长整数类型的变量。
register/return/restrict
建议编译器将变量存储在寄存器中,以加快访问速度。
从函数返回值。
指针是访问数据对象的唯一和初始方式。
short/signed/sizeof/static/struct/switch
声明短整数类型的变量。
声明有符号类型的变量。
返回数据类型或变量的大小。
声明静态变量。
声明结构体类型。
选择语句。
typedef
为数据类型定义一个新的名称。
union/unsigned
union 用于定义一个联合体,联合体允许在相同的内存位置存储不同的数据类型。联合体的大小取决于其成员中占用内存最大的数据类型。
unsigned 用于声明无符号整数类型,即非负整数。无符号整数只能表示非负数。
void/volatile
void 用于声明没有返回值的函数,或用于指定指针没有特定的数据类型。在函数声明中,void 表示函数不返回任何值。
volatile 用于告诉编译器不要对声明为 volatile 的变量进行优化,因为它们的值可能会在未知的时刻被外部因素更改。
while
while 用于创建一个循环,只要指定的条件为真(非零),就会重复执行循环体中的语句。
abcdefgrstuvwli
说明部分
注释
行注释
//
段注释
/* XXXX */
指针
最有特色的数据类型
作用
实现调用函数与被调用函数共享变量或数据结构,实现双向数据通信
可以实现内存空间的动态存储分配
可以提高程序的编译效率和执行速度
基本概念
对比
变量名与内存中的一个地址对应的
int a = 3;
这是直接按照变量的地址存取变量值的方式称为直接存取方式
变量的内存地址称为该变量的指针(指向这个变量),我们用一个变量来存储这个指针,称这个变量升级了,为指针类型的变量,简称指针变量,也称指针
基本操作
定义方法
类型说明符 *标识符
int *a;
表达式的值是指针类型的,即使内存地址,这个表达式为指针表达式
数组名代表数组的地址,是地址常量
指针变量也是变量,也有自己的地址
运算
赋值运算
指针变量=指针表达式
左右数据类型一致
取地址运算
&标识符
标识符不能是register,可以是数组
估计访问不了cpu
返回标识符的地址
取内容运算
*指针表达式
*为指针运算符或间接访问运算符
指针表达式与整数相加减
p+(-) n
n为整型表达式
等于=p的值+(-)p所指的类型长度*n
连续区间上进行此操作才有意义
自增、自减
p++/p--
等于=p(+)-1
同类指针相减运算
m-n
等于数据元素之间的个数
关系运算
指针表达式 关系运算符 指针表达式
强制类型转换运算
(类型说明符*) 指针表达式
float *i=ox1000;int *p; p = (int*) i+1;
等于p=0x1000+1*4=0x1004
注意空指针异常
就是没有给指针赋初值,里面是任意的一个地址
指针与数组的关系
一维数组
联系
统一的计算地址方法访问内存
都能够处理内存中连续存放的一系列数据
区别
指针是变量可以变,数组名是地址常量(形参除外)不可变
数组中有每个元素的定义,指针是连续改变指针
数组在内存中始终占据固定的大小空间,指针变量仅仅需要一个存放地址值的存储空间
等价形式
int a[5],*p=a,i;
p[i]=*(p+i)=*(a+i)=a[i]
&p[i]=p+i=a+i=&a[i]
字符串指针与字符串相似
注意点
char *p = "C language";
"C language"这个字符串存储与只读存储区中
char s[11] = "C language";
正确
char s[11]; s[]= "C language";
错误
二维数组
数组名代表该数组的首地址,是地址常量,二维及其更高都适用
二维数组的看法
1,先看成一维数组,把后面的列去掉
2,对于一维数组的每一个元素里面又装着列的个数的元素
如:int r,d[3][3]
1,d[0] d[1] d[2]
2,d[0]=d[0][0],d[0][1],d[0][2] d[1]=d[1][0],d[1][1],d[1][2] d[2]=d[2][0],d[2][1],d[2][2]
所以d是一个地址常量,d[0]/d[1]/d[2]也是,所以,d[0]++、d++表达错误
d[0]+1= d[0][1]
r=d[0]
二维数组元素及其地址
定义:int d[3][4]
数组元素d[i][j]表示方法
d[i][j]
*(d[i]+j)
*(*(d+i)+j)
数组元素d[i][j]地址表示方法
&d[i][j]
(d[i]+j)
(*(d+i)+j)
指针数组
定义:这个数组里面全是指针变量
定义:int *a[5]
int *p[3],d[3][3];
如何表示d[i][j]
用p和d的形式,与二维数组等价且p可替换d
指针与字符串数组
指向数组的指针变量
形式
int (*p)[2];
定义p是一个指针变量,它所指对象是一个具有2个元素的int型数组
int d[3][2]
d表示指向由两个整型变量构成的一维数组的指针
int *q
合法型
q=d,不合法
1VS2
p=d,合法
2VS2
指针与函数的关系
指针作为函数的参数
区分
*a++
指针动,值不动
(*a)++
指针不动,值动
char *a = "hello"; printf("s",a);
这里的a是一个指针变量,他的值装的是字符串的地址,printf的作用就是沿着a的里面的地址在将地址里面的值打印出来,而不是打印地址值
指针作为函数的参数,在调用是传递是地址
被调用函数不能改变参数指针变量的值,但是可以改变实参指针变量所指变量的值
一级指针
传地址的方法
1,形参和实参都用数组名
2,形参和实参都用指针变量
3,形参用数组名,实参用指针变量
4,形参用指针变量,实参用数组名
指针数组,形参实参
返回类型指针的函数
函数的返回值是一个指针
函数的指针和指向函数的指针变量
形式
定义
int (*y)(max)
函数
int max(int a)
调用
int r; r= (*y)(int a)
等价与调用这个函数
高级操作
二级指针
定义
变量里存地址,地址对应的变量里面存值叫一级指针
要是地址变量里的存的还是地址,叫二级指针
形式
int **a;
可以改变指针变量的指向,但没有改变指针变量的变量的值
内存
通用指针void*
内存管理函数
calloc
void *calloc(unsigned n,unsigned size)
int *p; p = (int *) calloc(20,sizeof(int))
malloc
void *malloc(unsigned size)
free
void free(void *p)
main函数的参数
int main(int argc,char*argv[])
int main(int argc,char**argv)
argc:命令行中参数的个数
c:count
argv:存放命令行中的各个参数
系统将以空格为分界字符串存放其首地址
v:value
文件
概念
存储在计算机外部存储介质上数据的集合
程序文件
可执行文件
原始数据文件或一组输出结果
操作系统是以文件为单位对数据进行管理,并把每一个与主机相恋的输入或输出都看作是一个文件
文件可以通过应用创建
C语言程序中的数据可以从文件中读入,或者输入到文件中
依赖于标准输入输出函数
分类
准则
通过扩展名进行分类
文件存储的编码形式
ASCII文件
就是.txt文件
字符文件,字符流
文件就是一个个字符组成,1个字符占一个字节
C语言源程序和数据文件都是ASCII文件
二进制
内存数据如何表示原样输出到磁盘
二进制流
编译连接后的目标文件和可执行文件是二进制文件
内存举例
111
ASCII
00000001+00000001+00000001
3个字节
二进制
00000000+01101111
两个字节
C语言中
文件看作数据流,并将数据按顺序存储
对文件的存取是以(字符)字节为单位的
输入输出
有无文件缓冲区
非缓冲文件系统
缓冲文件系统
背景
系统对磁盘和内存中数据的存取访问速度不一致,为了提高数据存取速度
C语言采用缓冲文件系统
针对的是文本文件和二进制文件
系统自动在内存区为每一个正在使用的文件开辟一个缓冲区
缓冲区大小由c语言确定,一般为512字节
文件类型指针
缓冲系统中存放正在使用文件的信息,用结构体类型名为FILE,包含stdio.h
定义
FILE *fp;
通过文件指针变量可以找到与它相关的文件
打开与关闭
打开
FILE *fp; fp=fopen(文件名,使用文件方式); fp=fopen(”data1“,r); if( (fp=fopen(”data1“,r))==NULL ) { exit(0); }
方向
单向(只读只写追加)
分类
存在
是
r
a
否
w
先建立
双向(可读写)
多个+号
分类
存在
是
r+
a+
否
w+
先建立
文件类型
默认文本文件,加b为二进制文件
b
binary
读写的视角是以计算机中 的程序来说
读到计算机里面来
写到磁盘去
失败返回NULL
关闭
fclose(fp);
成功返回0,失败返回EOF
读写
读
数量
字节
块
格式化
fscanf(fp,"%d%f",&i,&s)
8 1.3
a=12,b=1.2
fprintf(fp,"%d,%f",a,b)
12 1.2
位置
顺序
随机