一.数据类型,运算符与表达式
1.1数据类型 短整型(short int)
整形 基本整型 (int)
长整型(long int)
字符型(char)
单精度类型(float)
基本整型
浮点型 双精度类型(double)
长双精度型(long double)
枚举类型(enum)
数据类型
数组类型
构造类型 结构类型(struct)
共用体类型(union)
指针类型(*)
空类型(void)
1.2 常量与变量
1.2.1常量和符号常量
1)在程序运行中,其只不能被改变的量称为常量 P38常量类型
注:P38 用define定义的常量不能再被赋值。
2)变量:变量名为门牌号,变量值为家庭成员。
注:标识符只能由字母、数字、下划线组成。并且第一个字符不能为数字。区分大小写。(先定义,后使用;可读性强悍)
P39 ansic 一段了解一下即可。
1.3 整形数据
1.3.1整型常量的表达方法
1)十进制整数:123,--4556.4
1
2)八进制整数:以0开头的,八进制数字0123=十进制0×83+1×82+2×81+3×80=83 3)十六进制整数:以0X开头的,转化方法同八进制。
1.3.2 整型变量
1)了解补码的知识(整数不变,负数按位取反再加1)
注:存贮单元中,最左端的符号位,0正1负。
2)根据数值的范围分为 int,long, short。 P41
Int的范围 —215 ~~(215 —1) = 32768~~—32767
Unsigned无符号, 没有0正1负的书法了,范围扩大一倍。
Signed 有符号,有0正1负的说法。
什么也不加默认为signed。
3)整形变量定义:“强制类型定义” P43使用方法。
4)数据的溢出:(循环)
1.3.3整型常量的类型(了解一下,重点(4)(5)条)
1.4浮点数据
1.4.1 浮点型常量的表达方法
1) 十进制(平常数学中该怎么写就怎么写)
2)指数形式 123e3,123E3 表示123×103
注意:1,E不区分大小写。
2.规范化形式时,小数点的左边应该是一位非零的数字。 这样的可读性高。
1.4.2 浮点型常量
1)存放形式。 4个字节,小数点部分和指数部分分开存放
2)浮点型变量的分类 (P46了解一下即可)
3)浮点型数据的舍入误差(P47 了解)
1.4.3浮点型常量的类型
P47了解,注意其中加f或者F以及遗失数据的情况
1.5 字符型数据
1.5.1 字符常量(课本最后有表格,字符常量其实就是数)
字符常量是用单撇号括起来的一个字符,如 ‘a’,注意‘a’和‘A’不同。 P48(按需记忆,例题必看)
1.5.2 字符变量
字符常量只能放一个字符。★★★
1.5.3 字符数据在内存中的存储形式以及使用方法(p52)
1.5.4 字符串常量
字符串常量是一对双撇号括起来的字符序列。
(注:系统会自行在字符串后面加上?\0?作为字符串结束标志)
1.6 变量赋初值
C语言允许在定义变量的同时变量初始化。 例如int a=3;
可以仅对一部分赋初值, int a,b,c=5; 表示仅对C赋予初值。
不能写成int a=b=c=5;(其余内容自行了解)
2
1.7 各类数值型数据间的混合运算
横向必定转化 short、char
int
纵向按需转化
低 ( 具体细节看课本P54)
Unsigned
Long
高
float Double
1.8算数运算符和算数表达式
(1)算数运算符 (+ --- * / %)
(2) 关系运算符 (>,<,,==,>=,<=,!=)
(3) 逻辑运算符 (!非,&&与,||或)
(4)。。。不常用
(5)赋值运算符 (=及其扩展赋值运算符)
。。。。。。。
后边不常用,按需记忆!
1.8.1 。。。没有的东西
1.8.2 基本算术运算符(P58)
1)优先级与结合性
1. 先乘除后加减
2. 左结合
2)强制类型转化运算符
(类型名)(表达式) 例如: int(x+y) 对x+y 整体转化 Int x+y 只对x 转化
注:x还是x类型不变,int x 又算一个类型,属于中间的计算数字。不改变x 的类型。 (详细见P57)
3)自增、自减运算符
++i,——i (在使用之前,先使i的值加(减)1)
I++,I—— (在使用之后,使I的值加(减1)
注:1)自增自减只能用于变量,不能用在常量和表达式。
2)右结合。 —i++ 把i++看做整体,进行先使用在加加。、
4)有关表达式使用中的问题说明
(仔细阅读。修改方案:避简就繁)
1.9 赋值运算符和赋值表达式
1)作用是将一个数据赋给一个变量
2)类型转换(截取有用的数字,前不足复制最高位,后不足补零)
看一下 p60 4.2 建议看一下书
P61 7
3
3)复合的赋值运算符
a+=3; 等价于 a=a+3;
x*=y+8; 等价于 x=x*(y+8);
4)赋值表达式
一个变量和一个表达式连接起来的式子。
形式:变量 赋值运算符 表达式
(注:最后保留左值,严格按照优先级的算法来)
1.10 逗号运算符和逗号表达式
1.赋值语句的优先级高于逗号运算符的优先级
2.逗号表达式等于最后一个
3.逗号还有间隔的功能
二、 最简单的C程序设计——顺序程序设计
2.1 C语句概述
(1)控制语句
① if(...)....else... (条件语句)
②for( ; ;)... (循环语句)
③while(..)... (循环语句)
④do...while... (循环语句)
⑤continue (结束本次循环语句)
⑥break (中止switch或者循环语句)
⑦switch (多分支循环语句)
⑧goto (转向语句)
⑨return (从函数返回语句)
“(......)”表示括号内是一个判别条件,“。。。”表示内嵌语句。
(2)函数调用语句:由一个函数调用加一个分号构成。例如 printf(“Chinboy”);
(3)表达式语句:一个表达式加一个分号。
(4)空语句。
(5)符合语句。
2.2 赋值语句
可以把赋值表达式放到别的语句中使用
2.3 数据输入输出的概念及在C语言中的实现(细读P72)
2.4 字符数据的输入输出
2.4.1 putchar 函数
作用:向终端输出一个字符,一般形式为putchar(c);
2.4.2 getchar 函数
作用:从终端输入一个字符,没有参数,一般形式为a=getchar();
4
2.5 格式输入与输出
2.5.1 printf函数 216 =32768,28=256
(1)一般格式 printf(格式控制,输出表列);
(2)“格式控制”双引号括起来,包含两种信息:
①“格式说明”,由%和字符组成,作用将输出数据换为指定的格式。 ② 普通字符,按照原来的样式输出的字符。
(3)格式字符
1)d格式符,又来输出十进制整数。
① %d,按照十进制整型数据,实际长度输出。
② %md, 数据所占列数小于m,左端补空格。
(指定宽度)数据所占列数大于m,原样输出。
③ %ld,输出长整形数据。
2)o格式符(把内存单元的二进制数按照八进制数字输出) 注:不在正负号,用%lo合适输出,也可以指定宽度。
3)X格式符,以十六进制输出,不带正负号,可以用%lx, ,也可以指定宽度。
4)u格式符, %u无符号,十进制输出,可以用%lu ,也可以指定宽度。
5) c格式符,用来输出一个字符。
6)s格式符,用来输出衣个字符串。
① %s, For example : printf(“%s”,”china”);
② %ms, 数据所占列数小于m,左端补空格。
数据所占列数大于m,原样输出。
③ %-ms, 数据所占列数小于m,右端补空格。
数据所占列数大于m,原样输出。
④ %m。ns 在地址中要m个位置,取字符串的前n个放在m个位置的偏右点,左端补空格。如果m<n,突破限制。
⑤ %-m。ns 在地址中要m个位置,取字符串的前n个放在m个位置的偏左点,右端补空格。如果m<n,突破限制。
注:不写m自动认为m=n,n不写不行。
7)f格式符 (用来输出实数,包括:单精度双精度。以小数形式输出) ① %f 使整数全部输出,并输出6位小数。
注:并非全部都是有效数字,双精度有效数字一般为16位,单精度一般为7位。 有效的数就是正确能用的,超出范围的数一般都是错的。
② %m。nf m个位置,n个小数。左补空格
③ %-m。nf m个位置,n个小数。右补空格
8) e格式符 以指数形式输出实数
① %e 不指定输出数据所占的宽度和数字部分的小数位数 注:指数部分的E和e占一个位置
② %m。ne 和 %-m。ne 期中负号自古的含义跟前面一样。 N 指拟输出的数据的小数部分,凡未指定N自动使n=6. M同前,存在突破限制,补空格。
5
9) g格式符
用来输出实数,根据他们数值的大小自动选f格式或者e格式, 选择输出占宽度最小的那一种。并且不输出无意义的零,
P87 两个表格重点了解,需要时记忆。
对printf函数补充说明:
(1)除了XEG外,其他格式字符必须用小写字母
(2)可以再printf函数中的格式控制字符串中包含”转义字符”。
(3)上面介绍的9中字符,在%后面作为格式字符,一个格式字符说 明以%开头,以上面9个格式字符为结束。
(4如果想输出%,应该用两个连续的%表示。
2.5.1 scanf函数
1.一般形式
scanf(格式控制,地址表列)
格式控制,含义同printf
地址表列是由若干个地址组成的表列,可以是变量的地址或者字符串首地址 &是地址运算符,用在地址表列中。
“%d%d%d”表示按照十进制整形输入三个数,输入时俩个数据之间以一个空格或多个空格间隔,也可以用enter键、Tab键。
在%d%d格式时,输入数据不能用逗号。
2.格式说明
详细参阅p83表格
补充说明:
(1) 对unsigned型变量所需要的数据,可以用%u、%o、%x、%d格式输入。也就是说系统会自动把输入的不是unsigned的变成unsigned型.
(2) 可以指定输入数据所占的列数,系统按照它截取所需要的数据。这个一定意义上不在用逗号什么的加以区分直接就是系统的事了。
(3) 如果在%后面有一个*附加说明符,表示读入但是不进行赋值,任何变量跳过它的指定的列数
(4) 输入数据时不能规定精度,也就是可以有m但是不能有n
3 使用scanf函数是应该注意的问题
1)“格式控制”后应是变量地址带&
2)“格式控制”除了格式说明还有其他字符,在输入数据时在对应位置应输入与这些字符相同的字符。
例如: scanf(“%d,%d”,&a,&b); 应该输入3,4
3) 由于在两个% d之间有两个空格,那么在两个数据间应该有两个或者更多的空格
4)“%c”格式输入字符时中间不需要空格什么的。前提是%c中间没有东西,要是中间有逗号,输入的格式还是要有逗号的。
5)在输入数据时,遇到以下情况认为该数据结束。
① 空格、回车、Tab键。
② 按指定的宽度结束。
③ 非法输入
6
2.6 顺序结构程序举例
例题参照课本!
三、选择结构程序设计
3.1 关系运算符和关系表达式
所谓“关系运算”实际上是“比较运算”
3.1.1 关系运算符
< 小于;<= 小于等于;> 大于;>=大于等于; 这四个优先级相同(高) == 等于;!= 不等于; 这俩相同(低)
3.1.2 关系表达式
用关系运算符将两个表达式连接起来的式子,称为关系表达式。 在C的逻辑运算中,“1”表示真,“0”表示假。
例: a>b;为真,那么表达式值为“1”;
3.2 逻辑运算符和逻辑表达式
用逻辑运算符将关系表达式或逻辑量连接起来的式子是逻辑表达式。
3.2.1 逻辑运算符及其优先级
(1) && 逻辑 与
(2) || 逻辑 或
(3) ! 逻辑 非
&&和|| 要求两边有用运算量。
! 只要求一边有运算量。
真假关系同上:“1”表示真,“0”表示假。
优先次序:
!(非)
优先级(高)
算数运算符
关系运算符
&&和||
赋值运算符 优先级(低)
3.2.2 逻辑表达式
C语言表示逻辑结果时(系统给的):“1”表示真,“0”表示假。
C语言判断逻辑是(参与逻辑运算时候,人为输入时):非“0”表示真,“0”表示假。
根据数值对应的真假进行判断。
进行运算的时候自左向右根据优先级扫描求解。
C并不是所有的逻辑运算都被执行,只要能判断出是真是假就行,后面的就不在进行运算。
3.3 if语句
3.3.1 if语句的三种形式
7
1)if(表达式) 语句
2)if(表达式) 语句1
else 语句2
3) if(表达式1) 语句1
else if(表达式2) 语句2
else if(表达式3) 语句3
else if(表达式4) 语句4
.........
① 3种形式的if语句中在if后面的都有表达式,一般为逻辑表达式或者关系表达式 表达式为真时,走if后面紧挨着的语句,为假时走后面的else或者直接跳过。 ② 第二第三种形式的if语句中,在每一个else前面有一个分号,整个语句结束处有一分号。else 不能单独使用,必须和if配对使用。
③ if 或者else 后面接一个语句的时候直接写,
接一个复合语句的时候,用花括号括起来,花括号必须成对出现。
3.3.2 if语句的嵌套
在if语句中有包含一个或者多个if语句称为if语句嵌套
If()
If()语句1 内嵌if
else 语句2
else
If()语句3 内嵌if
else 语句4
else 总是与它上面的最后的if来配对
注: if else 个数不等时,可以用花括号进行限定。
3.4 switch 语句
多分支选择,if为俩分支的
一般形式:
switch(表达式)
{
case 常量表达式 : 语句1;
case 常量表达式 : 语句2;
case 常量表达式 : 语句3;
case 常量表达式 : 语句4;
...........
default :
}
说明:1)switch后面的表达式可以是整形,字符型,枚举型。
2)与case后面常量相等时,执行。不相等的时候路过。。
3)没一个case表达式不应该相等,这样的话机子不会报错但是会让使用者出现误差 4)case 仅仅是路标,不进行判断。
5)case 可以无顺序
6) 多个case可以共用一个语句,这里就是和3)有点相悖。仔细理解。!! 8
四、循环控制
4.2 goto语句以及中goto语句构成循环(了解即可)
Goto 语句为无条件转向语句。
一般形式:goto 语句标号;
语句标号是标识符,由字母,数字,下划线组成。数字不能开头。 用途:
1) 与if语句一起构成循环结构。
2)从循环体内部跳到循环体外部。
4.3 用while 语句实现循环
while 语句实现“当型”循环结构,
一般形式: while (表达式) 语句
当表达式为非0时执行while语句中的内嵌语句
特点:先判断表达式,后执行语句。
注:1)后接一个语句时候直接接上。接复合语句时候要用花括号。
2)用计数的循环决定什么时候结束循环。
4.4 用do...while 语句
先循环后判断。
一般形式: do
循环语句
while 表达式
先执行后循环,非0继续执行知道是0为止。
4.5 用for语句
一般形式:for(表达式1;表达式2;表达式3) 语句
它的执行过程如下:
1) 先求解表达式1‘
2) 求解表达式2,若其值为真,则执行for语句中指定的内嵌语句,然后执行下面第三步。若为假,则循环结束,转到第五步。
3) 求解表达式3.
4) 转回上面第2步骤继续执行
5) 循环结束,执行for语句下面的一个语句。
也就是:
for(循环变量赋初值;循环条件;循环变量增值) 语句
说明:
1) 表达式1 可以省略,不过要在for语句之前完成赋初值的工作。
2) 表达式2 省略就是死循环了,不能省略
3) 表达式3 可以省略,不过要在内嵌语句中完成增值的任务。
4) 表达式1和3 可以同时省略。任务在别的地方完成就行
5) 都省略,神经病干的事。
6) 表达式1可以是与循环体无关的表达式也可以是逗号表达式
在逗号表达式内按照自左至右顺序求解,整个逗号表达式的值为其中最右边的表达式的值。
重点理解P120下面的小例子,理解计算机的工作原理。
9
4.6 循环的嵌套
一个循环体内又包含一个完整的循环结构,称为循环的嵌套。
多用点花括号即可。
4.7 几种循环的比较
P122 看一下课本就好了
4.8 break 和 continue 语句
4.8.1 break
一般形式 break ;
Break语句用来从循环体内跳到循环体外,执行循环下面的语句。
4.8.2 continue
一般形式: continue ;
作用是:结束本次循环,即跳过循环体中下面的尚未执行的语句,接着进行下一次是否执行循环的判定。
注:continue语句只结束本次循环,而不是终止整个循环的执行;break语句则是结束整个循环过程,不在判断执行循环的条件是否成立。
五、数组
C语言中无法表示上下标,就用方括号表示下标。例如 a[5];
5.1 一维数组的定义和引用
5.1.1 一维数组的定义
一维数组的定义的方式为:
类型说明符 数组名【常量表达式】;例如 int a[10];
说明:
1)数组名的命名规则和变量名相同,遵循标识符命名规则。
3)常量表达式中可以包括常量和符号常量,不能包含变量即数组长度,还有数组包括的都是确定的或者表达式,不可以是能变动的。
5.1.2 一维数组的引用
数组必须先定义后使用
C语言规定只能逐个引用,而不能一次性引用整个数组。
数组的表达形式为: 数组名【下标】
下标可以是常量或者表达式,不过要能求出确定数字来,不能带不确定的因素在里面。 定义和引用的区别:
定义: 数组名【长度】;
引用: 数组名【位置(下标)】;
一个表示长度,一个表示位置。 从零开始就是为了防止长度和位置弄混。
5.1.3 一维数组的初始化
对数组的初始化有以下方法实现
1)在定义数组时对数组元素赋予初值。
int a[5]={1,2,3,4,5}; 数值依次被括到大括号里面,中间用逗号隔开。
2)可以仅对一部分进行赋值。
int a[5]={1,2,3}; 前三个数字是对应的数字,剩下的系统自动弄成零
3)全部为零的方法①进行全部赋值为零。②仅对第一个数赋零其余的系统让弄成零。 10
4)对全部元素赋值时,由于数字的长度就已经确定了,那么定义的时候就可以不用写长度了。
int a[]={1,2,3,4,5,4}; 这个时候的长度就是6。
P134例题7.3 对冒泡法有所了解
5.2 二维数组的定义和引用
5.2.1 二维数组的定义
一般形式: 类型说明符 数组名[常量表达式(行数)][常量表达式(列数)];
C语言对二维数组,使二维数组可被看做是一个特殊的一维数组,它的元素又是一个以为数组,内存中按行存放,第一维的小标变化最慢,最右边的下标变化最快。
5.2.2 二维数组的引用
表达形式 数组名[下标][下标]
下标内的数字要求同前,下标必须用方括号,不能出现逗号。
数组元素可以出现在表达式中,也可以被赋值。
下标的起始值依旧是“0”。
5.2.3 二维数组的初始化
1)分行给二维数组赋初值。
int a[3][4]={{1,2,3,4},{1,2,3,4},{1,2,3,4}};
2) 所有数据写在一个大括号中。
int a[2][2]={1,1,1,1};
3) 对部分赋值。
........
详细见p137.
5.2.4 p139 建议用冒泡法写一下 例7.5
5.3 字符数组
5.3.1 字符数组的定义
方法和前面类似, char a[10];
由于字符型与整型互相通用,因此也可以定义一个整型数组用它存放字符数据。
5.3.2 字符数组初始化
最容易的是逐个字符赋予数组中个元素。
不进行初始化,各元素值不可预料。
提供的初值多于数组长度的话机子就会报错。
提供的初值少于数组长度的话,没有进行赋值的就全为“\0”。
5.3.3 字符数组的引用
建议看看例题。。
5.3.4 字符数组个字符串结束标志
系统会在储存的字符串后面自动加一个“\0”作为结束的标志。
对字符数组初始化的方法补充一种方法。
char a[]={“i am happy”}; 等价于 char a[]=“i am happy”; 长度不是10,是11. 也就是 char a[]={?i?,? ?,?a?.?m?........}; 的意思
5.3.5 字符数组的输入输出
方法有两种:
1)逐个的输入输出;用%c
11
2)整个字符串一次输入输出;用% s
注意:
1)输出的字符串不会包括“\0”.
2)用%s格式符输出字符串时候,printf函数的输出项是字符数组的数组名而不是元素。printf(“%s”,a); a是一个字符数组的组名。
3)遇到第一个“\0”就会结束输出,不管其他任何因素。
4)用scanf可以对字符串录入,中间不需要什么特殊的字符。系统会自动的一个地方一个字符的。但是在输出的时候看到第一个空格就会停止输出。还有就是不用再写取地址符号&了,因为c语言中数组名代表该起始地址。
“\0”对应的ASCII是0,空格对应的ASCII是32.
5.3.6 字符串处理函数
1)puts函数
一般形式 puts(字符数组);
其作用是将一个字符串(以“\0”结束的字符序列)输出到终端。其中可以包括转义字符。
2) gets函数
一般形式 gets(字符数组);
其作用是从终端输入一个字符串到字符数组,并且得到一个函数值。该函数值是字符数组起始地址。
3) ........
详细见p147.
其中strlen函数比较重要,其余的用到在查资料就行。
5.3.7 字符数组应用举例
1) 计算单词个数的重点部分。
for(i=0;(i=string[i])!=?\0?;i++)
If(c==? ?) word=0;
else if (word==0)
{
word=1;
num++;
}
对单词前面的空格进行操作。
习题7.1 筛选法 重点!!!
习题7.2 选择法 重点!!!
7.6 杨辉三角 重点!!!
六、函数
6.1 概述
一个c程序可由一个主函数和若干个其他函数构成,由函数调用其他函数,其他函数也可以互相调用。同一个函数可以被一个或者多个函数调用任意任意多次。
6.2 函数定义的一般形式
12
6.2.1 定义无参函数的一般形式
类型标识符 函数名()
{
声明部分;
语句部分;
}
6.2.2 有参函数定义的一般形式
类型标识符 函数名(形式参数表列)
{
声明部分;
语句部分;
}
6.2.3 空函数
类型说明符 函数名()
{ }
没有任何实际作用,先占一个位置。
6.3 函数参数和函数的值
6.3.1 形式参数和实际参数(形参和实参)
定义函数时使用的是形式参数;
调用函数时使用的是实际参数;
因为主调函数和被调函数之间有数据传递关系。 P158 例子。
说明:
1)定义形式参数时候不占内存,仅仅被调用过程占内存,调用结束后,内存单元也会被释放。
2)实参可以是常量,变量或者表达式。但要求有确定的值。
3)被定义函数中,必须指定形参的类型。
4)实参与形参的类型应该相同或者赋值兼容。
5)在c语句中,实参向形参进行的数据传递是“单向值传递”,只有实参传向形参,并且实参形参不是一个内存单元。
6.3.2 函数的返回值
1)函数的返回值是通过函数中的return语句获得的,return语句将调用函数的一个返回值带回主调函数中去。
一个函数中可以有一个以上的return语句。执行到哪一个return语句哪一个起作用, return后面的可以加括号,也可以不加。 并且return后面可以加表达式。
2) 函数的返回值应该是一个确定的类型,应当在定义函数的时候确定一个类型, 在c语言中,凡不加类型说明的函数自动按整形处理,(不同的编译程序有些差别)
3) 定义函数时,指定的函数类型一般应该和return语句中的表达式类型一致。如果不一致则以函数类型为准,return的向函数类型转化。
4)不带返回值,同void定义函数,函数中不的出现return语句。
6.4 函数的调用
6.4.1 函数调用的一般形式
13
函数名(实参列表)
如果无参数,实参数列可以没有,但是括号不能省略。实参较多时,以逗号隔开。
实参形式个数应该等于形参,顺序对位,一一对应。
P162 例8.4 了解
6.4.2 函数调用方式
按照出现的位置来分,可以有以下3种函数调用方式。
1) 函数语句。
把函数调用作为一个语句。
2) 函数表达式
函数出现在一个表达式中,这时候要求函数带回一个确定的值来参与表达式的运算。
3) 函数参数
函数调用作为一而过参数的实参。
例如:m=max(a,max(1,c));
6.4.3 对被调用函数的声明和函数原型
在一个函数中调用另一个函数需要的条件如下
1) 首先被调用的函数必须已经存在。
2) 如果使用库函数,应该把包含需要函数的库函数包含进来
3) 用自己定义的函数,该定义时写的函数在使用该函数的位置的后面,并且应该在主调函数中对被调用函数做声明。 P164 例8.5
注:定义需要把函数的全部功能构造出来,声明就是告诉系统有这么一个函数。 函数原型的一般形式有两种:
1)函数原型 函数名(参数类型1,参数类型2,。。。。。,参数形式n)
2) 函数原型 函数名(参数类型1 参数名1,参数类型2 参数名2,。。参数类型n 参数名n); float add( float a,float b);
说明:
1) 声明时函数原型,可以不包括参数类型和参数个数(不推荐)。
2) 定义在主调函数之前不用声明了,但是定义要在头文件后面 #include后面。
3)如果在头文件之前声明的话,之后就不用声明了。
4) 如果被调函数的函数类型为整型,c语言允许在调用函数前可以不做函数原声明;但是出错率比较大。
6.5 函数的嵌套调用
在定义函数时,一个函数不能包含一个函数,c不能嵌套定义函数,但可以嵌套调用函数,也就是说,在调用函数的过程中有调用另一个函数。
仔细了解 p167 图8.5
在定义函数时可以引用已经被定义的函数。
P168 详细了解。
6.6 函数的递归调用
递归调用。
例如;
在调用一个函数的过程中又出现直接或者间接的调用该函数本身,称为函数的14
int f(int x)
{
Int y,z;
Z=f(y);
Return (z*x);
}
用if语句来结束递归调用的死循环。
6.7 数组作为函数参数
6.7.1 数组元素作为函数参数
由于是实参可以是表达式,而数组元素可以是表达式的组成部分。因此数组元素可以作为函数的实参与用变量一样,是单向传递,也就是值传递的方式。
P178 例题。
6.7.2 数组名作函数参数
可以用数组名做函数参数,形参应用数组名或者指针变量。
个人理解: 输入首地址,也就是把整个数组的元素送了进来。
说明:
1)用数组名作函数参数,应该在主调函数和被调函数分别定义数组。不能只在一方定义。
2)实参数组和形参数组类型应该一样。是float就应该都是float,如果不一致结果就会出错。
3)形参数组定义时候的长度没有什么实际意义,也就是凑形式。而实参向形参传递时,共用同一内存单元。与前面描述的有些诧异。这也就导致了,在新定义的函数中的功能要是包括了改变数组值的同时也会使原来的数组内部的值改变。
4) 形参数组可以不指定大小,但是在定义的时候数组名后要跟一个空的方括号。 P180 例8.12 详细了解。
5) 用数组名做形参是传递的地址,因为共用。那么定义函数中有使形参在内存中数值变化时则,实参也对应变化。
6.7.3 多维数组名作函数参数
与前面类似。
可以用多维数组名作为函数的实参和形参。再被调用函数中对形参数组定义时,可以指定每一维的大小,也可以省略第一维的大小说明。但是不能把第二维以及其他高维的大小说明省略。
二维是由若干个以为数字组成的,按行存放。因此定义二维的时候必定指定列数。形参数组和实参数组类型相同。所以他们时候具有相同长度的一维数组所组成。所以不能只指定第一维
在第二维相同的前提下,第一维可以不相同,编译的时候不进行查阅
P183 例题8.14.
6.8 局部变量和全局变量
6.8.1 局部变量
在一个函数内部定义的变量是内部变量,它只在本函数范围内有效。也就是说只有在本函数内才能使用它们。在此函数以外是不能使用这些变量。
15
说明:
1) 主函数中定义的也只有主函数中有效,主函数也不能使用其他函数中定义的变量。
2)不同函数可以使用相同名字的变量,他们代表不同的对象,互不干扰。
3) 形参也就是局部变量。
4)在一个函数内部,可以在复合语句中定义变量,此变量只在本复合语句中有效,,这种语句叫做 分程序 或 程序块。
6.8.2 全局变量
在函数内部定义为局部变量
函数之外定义的变量称为外部变量,外部变量也就是全局变量。
全局变量可以为本文件中其他函数所共用,他的有效范围从定义变量的位置开始到本源文件结束。
说明:
1)设置全局变量的作用是为了增加函数间数据联系的渠道。P185 下面例题。 (一个函数能有好几个返回值)
2)建议不在必要时候不要使用
① 全局变量在程序的全部执行过程中都占有存储单元,而不仅在需要时候才开辟的。
② 它使函数的通用性降低。
③ 使用全局变量过多,程序清晰性降低。
④ 在一个源文件中,外部变量和局部变量同名,则在局部变量的作用范围内,外部变量被屏蔽。 P187
8.9 变量的存储类别。
8.9.1 动态存储方式和静态存储方式
从变量存在的时间来分,可以分为动态存储方式和静态存储方式。
所谓静态存储,是指在程序运行期间由系统分配固定的存储空间的方式 动态存储是指程序运行期间,根据需要进行动态的分配存储空间的方式。 在动态存储区中存放以下数据
① 函数形参
② 自动变量
③ 函数调用是的现场保护和返回地址等。
以上数据开始时占地方,结束时释放地方。
每一个变量和函数有两个属性:数据类型和数据的存储类别。
具体有四种:自动、静态、寄存器、外部的。
8.9.2 anto变量
局部变量不专门声明static存储,都是动态的。
使用函数时分配不使用时候释放的叫做自动变量。
自动变量用关键字auto作为存储类别的声明,实际上,auto可以省略,auto不写则隐含确定为自动存储类别。属于动态的
程序中大多数的都是动态的。、
8.9.3 用static声明局部变量
有时希望函数中的局部变量的值在函数调用结束后不小时而保留原值。 P189下 函数进行了解。
16
对静态局部变量的说明:
1)在静态存储区内分配单元。
2)对静态局部变量是在编译时赋初值的,并且只赋值一次。
3)定义的时候不赋初值的话,则对静态局部变量来说,编译时自动赋初值0或者空字符。但是对于自动的,不赋初值的话他的值就是一个不确定的数值。
4)虽然静态局部变量在函数调用结束后仍然存在,但其他函数是不能引用的。 需要静态变量的情况如下
1)需要保留函数上一次调用结束时的值。
2)如果初始化后,变量只能被引用而不改变其值。
8.9.4 register 变量
使用频繁的变量放到cpu的寄存器中,节省时间提高效率。
用register作声明 p192 例题8.19 了解应用
说明:
1) 只有局部自动变量和形式参数可以作为寄存器变量。
2) 一个系统的寄存器数量又限。不能任意的定义多个寄存器变量。
3) 局部静态变量不能定义为寄存器变量。
8.9.5 用extern声明外部变量
外部变量是在函数外部定义的全局变量,作用域是从变量的定义处开始,到本程序文件的末尾。
有时用extern来声明外部变量来扩大作用域。
1. 在一个文件内声明外部变量
如果不在文件开始定义,它的有效范围只限于定义处到文件结束。如果想在定义点以前的函数想引用的话,用extern对变量进行 外部变量声明,表示该变量是一个已经定义的外部变量。 P193 例题8.20
2. 在多文件的程序中声明外部变量
一个c程序可以由多个源文件组成。
其中一个文件里面定义全局变量,其余的文件中都要写上声明全局变量的语句。
8.9.6 用static声明外部变量
有时在程序设计中希望某些外部变量只限于被文件引用,不被其他的文件引用。 在别的文件中进行声明 在这个文件中的操作变量前面加上static.
P195 例题进行理解。
8.9.7 关于变量的声明和定义
声明就是闹个声音告诉系统有这个玩意,
定义就要进行细节操作。。
8.9.8 存储类别小结
P197
8.10 内部函数和外部函数
8.10.1 外部函数
一个函数只能被本文件中其他函数调用,它称为内部函数。在定义内部函数时,在函数名和函数类型前面加上static。199页
8.10.2 外部函数
1)在定义的时候,在函数的首部最左端加关键字extern,则表示函数是外部函数可以供其他文件使用。
17
2)在需要调用此函数的文件中,用extern对函数作声明。表示该函数是在其文件中定义的外部函数。
七、预处理命令
C提供的预处理功能主要有以下三种:
1)宏定义。
2)条件包含(连接)
3)条件编译
7.1 宏定义
7.1.1 不带参数的宏定义(常量)
一般形式; #define 标识符 字符串
例: #define PI 3.1415926
作用是在本程序文件中使用指定的PI代替内个数据。
在编译预处理时,将程序中的该命令以后出现的所有的PI都用内个数据代替。 P205 例9.1
说明:
1)宏名一般习惯用大写字母。
2) 宏名代替一个字符串,可以减少程序中重复书写某些字符串的工作量。
3) 宏定义时用宏名代替一个字符串,也就是简单的置换,不坐正确性的检查。
4)宏定义不是c语句,不必在行末添加分号。
5) #define 命令出现在程序中函数的外面,宏名的有效范围为定义之后到本源文件结束。
6) 用#nudef命令终止宏定义的作用域。
7)在进行宏定义时,可以引用已定义的宏名,层层置换。
8)对程序中用双撇号括起来的字符串内的字符,即使与宏名相同,也不进行置换。
9)宏定义是专门用于预处理命令的一个专用名词,它与定义变量的含义不同。只作字符替换,不分配内存空间。
7.1.2 带参数的宏定义(小函数)
带参数的宏定义不是进行简单的字符串替换,还要进行参数替换,其定义的一般形式为。
#define 宏名(参数表) 字符串
字符串中包含在括号中所指定的参数。
详细见p207 例9.3
说明:
1) 对带参数的宏的展开只是将语句中的宏名后面括号内的实参字符串代替 。 #define命令行中的形参详见p208
2) 在宏定义时,在宏名与带参数的括号之间不应加空格。否则分离使后面的成为整体为一常量,即不带参数的宏定义。
参数的宏和函数的区别:
1) 函数调用时,先求出表达式的值然后代入。带参数的宏仅仅进行简单的字符替换。不进行求值。
2)函数调用在程序运行时候处理,分配内存,宏的展开是在编译前进行,展开的时 18
候并不分配内存单元。不进行值的传递,也没有返回值的感念。
3) 对函数中的实参和形参都要定义类型;而宏不存在类型问题。
4) 调用函数只能得到一个返回值,而用宏可以设法得到几个结果。
5)使用宏次数多时,宏展开后源程序变长。
6)宏替换不占运行时间,只占编译时间。
了解210页例9.5 用宏代表输出格式。
9.2 “文件包含”处理
类似#include<stdio.h>的做法
一般形式为
#include <文件名> 或者 #include “文件名”
编译后是已经把所有的文件链接起来形成一个文件。
说明:
1) 一个#include命令只能指定一个被包含文件。
2)文件1用到文件2,文件2用到文件3。那么include时候要使文件3写在文件2之前。
3)一个被包含文件中又可以包含另一个被包含文件,即文件包含是可以嵌套的。
4) 文件名用双撇号时候,系统先在用户当前目录中寻找要包含的文件,要是找不到再按标准凡是查找。尖括号的就直接按照标准方式查找。
5)用了include,如果包含的文件中有全局静态变量。那么他在最大的文件中也有效。不必要extern声明。
9.3 条件编译
有以下几种形式:
1) #ifdef 标识符
程序段1
#else
程序段2
# endif
它的作用是若所指定的标识符已经被#define命令定义过,则在程序编译阶段编译程序段1,否则编译程序段2.
详细见p215。
2)#ifndef 标识符
程序段1
#else
程序段2
# endif
他的作用是若标识符未被定义过就编译程序段1,否则编译程序段2.
3)#if 表达式
程序段1 它的作用是当指定的表达式值为真时,编译程序段1. #else 可以事先给定条件,是程序在不同的条件下执行不同的功能 程序段2 可以用这个办法求给日期第几天的问题。
# endif
19
十、指针
正确而灵活地运用它,可以有效地表示复杂的数据结构;能动态分配内存;方便地使用字符串;有效而方便地使用数组;在调用函数的时候能获得一个以上的结果;能直接处理内存单元地址等。
10.1地址和指针的概念
编译时,分配内存单元。
内存区每一个字节有一个编号,叫地址。类似房间号。地址所标志的内存单元中存放的数据,类似旅客。
在程序中一般是通过变量名对内存单元进行存取操作的。
程序经过编译以后已经将变量名转化为变量的地址。对变量值的存取都是通过地址进行的。
按变量地址存取变量值的方式称为“直接访问”方式。
间接方式即指针用途。P220 图
直接访问:已知变量i的地址。根据此地址直接对变量i的存储单元进行存取访问。 间接访问:先找到存放i地址的变量。从其中得到变量i的地址再找到i的存储单元进行访问。
一个变量的地址称为该变量的指针。
存放指针的变量叫做指针变量。
10.2 变量的指针和指向变量的指针变量。
为了表示指针变量和它所指向的变量之间的联系,程序中用*表示指向对象。
如果定义i_pointer为指针变量,那么*i_pointer表示i_pointer指向的变量。 加*脱皮 可以看到 *i_pointer和i是等价的;也就是i=3 ;等价于*i_pointer=3;
10.2.1 定义一个指针变量
先定义指定其类型,并按此分配内存单元。
例: int i , j;
int *i_pointer,*j_pointer;
下一个语句中的*表示指向整形变量的指针变量。
Int表示该指针变量指向的数据的数据类型,必须有的基类型。 指针变量的基类型用来指定该指针变量可以指向的变量的类型,上述可以指向i,j 但是不能指向别的数据类型,例如float的。
一般形式:基类型 *指针变量名;
用赋值语句使一个指针变量得到另一个变量的地址,从而使它指向一个该变量。 例:i_pointer=&i;
定义指针变量时要注意的两点:
1) 指针变量前面的*表示该变量类型为指针变量,指针变量名是i_pointer。
2) 在定义指针变量时必须指定基类型。
因为后面涉及到移位,不同的类型对应位不同。
特别注意:只有整型变量的地址才能放到指向整型变量的指针变量中,这个需要 一一对应。
20
10.2.2 指针变量的引用
牢记:指针变量中只能存放地址(指针)。
有两个相关的运算符:
① &:取地址运算符号。
② *:指针运算符(间接访问运算符),取指针所指向的对象的内容。 *p为指针变量p所指向的存储单元的内容。
P223 例10。1 了解!
下面对&和*在做些说明。
如果已知i_pointer=&a;
1)&*i_pointer的含义就是a的地址。
&*的优先级相同,但是按照自右向左结合。
2)*&a的含义是a
一定的意义上可以认为&*相反。
3)(*i_pointer)++相当于a++
++和*的优先级相同。
10.2.3 指针变量作为函数参数
函数的参数还可以是指针类型
它的作用是将一个变量的地址传送到一个函数中。P225. 例10.3
通过函数也可以变相得到多个返回值。P227下
定义一个指针变量以后该指针变量指的位置是任意的,不能随意的改变该指针变量所指向的值,有的时候很容易改变重要数据,做法是对地址进行操作。P226 细解
P225 只能用指针办到,用以前的办法不行。仔细看p227中间部分。
如果喜爱那个通过函数调用得到n个需要噶边的值,可以用指针。改地址。P227下 指针与前面所学的知识相结合。
10.3 数组与指针
所谓数组元素的指针就是数组元素的地址,使用指针法能使目标程序质量高(占内存小、运行速度快)
10.3.1 数组元素的指针
与前面类似
Int a[10]; int *p;
如果数组为int型,则指针变量的基类型也应为int型。
C语言规定数组名(不包括形参,形参数组名不占实际内存)代表数组中 首元素(即序号为0的元素)地址。
因此:p=&a[0] 等价p=a
可以这样写, int *p=&a[0];
等价于 int *p;
P=&a[0];
10.3.2 通过指针引用数组元素
*p=1;表示将1赋给p当前所指向的数组元素
P+1不是指向下一个单元格,是指向下一元素。
如果p的初值为&a[0],则:
1)p+i和a+i就是a[i]的地址或者说他们指向a数组第i个元素。(有第0个元素)
21
2)*(p+i)或*(a+i)是p+i或者a+i所指向的数组元素。
[ ]实际上是变址运算符,即将a[i]按a+i计算地址,然后指出此地址单元 中的值。
3)指向数组的指针变量也可以带下标。
如:p[i] 和*(p+i)
在使用指针变量指向数组元素时,有以下几个问题要注意:
1)可以通过改变指针变量的值指向不同的元素
P++成立因为是变量,a++不成立,因为a是首地址指针变量
2)要注意指针变量的当前值。
3)虽然定义数组时某指针变量包含10个元素,并用p指向某一数组元素,但实际上指针变量p可以指向数组以后的内存单元。
4)注意指针变量的运算符
①p++ p+=1
② *P++
③*(p++)和 *(++p)
④++(*p)
⑤P当前指向a数组第i个元素
*(p——) 相当于a[i——]
*(++p) 相当于a[++i] 234页
*(——p)相当于a[——i]
10.3.3 用数组名做函数参数
前面已介绍 当用数组名作参数时,如果形参数组中个元素的值发生变化,实参数组元素的值随着改变。(共用一个内存单元)p235了解为什么
P238 改变实参数组的4种办法。
注意:如果用指针变量做实参,必须先使指针变量有确定值。
10.3.4 多维数组与指针
可以实现不过比较复杂
1.多维数组元素的地址
二维数组其实是抽象的一维数组。原理也是从这里下手的。
a是第0行的首地址,那么a+1就是第1行的首地址。因为是“一维”数组。 又因为c语言规定了数组名代表数组首元素地址。则a[0]代表一维a[0]首地址,其实a[0]就是a[0][i]这个数组的数组名。也就是a[0]=&a[0][0],则0行1列代表a[0]+1
a[0]+1和*(a+0)+1都是*a[0][0]
*(a[0]+1)就是a[0][1]的值
*(*(a+0)+1)或*(*a+1)也是a[0][1]值
*(a+i)等价于a[i]
一维数组的a[i]是a数组中第i个元素,是对应内存中的值。
二维数组的a[i]是一维数组名,是一个地址。
P245例10.10 仔细了解
P243下表格 重要!!!
2.指向多维数组元素的指针变量
1)指向数组元素的指针变量
按照挨个的地址进行访问.p246 例题10.11
地址是以八进制数表示的(输出格式符为%o)
22
计算a[i][j]在数组中的相对位置的计算方法:i*m+j。m为列数(不同语言有差别)
2)指向由m个元素组成的一维数组的指针变量
int (*p)[4]表示p是一个指针变量,它指向包含4个整型元素的一维数组。两边的括号不能省略。
此时p只能指向一个包含4个元素的一维数组,p的值就是该一维数组的起始地址,p不能指向一维数组中的某一个元素。类似二维的起始地址的名字。
*(p+2)+3指第二行第三列数内部值
3)用指向数组的指针作函数参数
在用指针变量作形参以接受实参数组名传递来的地址时,有两种方法:
1) 用指向变量的指针变量。
2)用指向一维数组的指针变量
P249 例10.13 其实都是传的地址
P250 例10.14
10.4 字符串与指针
10.4.1 字符串的表达式
在c中,有两种方法访问一字符
1)用字符数组存放一个字符串,然后输出该字符串。输出字符串,直接用字符串的首地址就行
2)用字符指针指向一个字符串
可以不定义字符数组,而定义一个字符指针。用字符指针指向字符串中的字符。
对字符指针变量的string初始化,实际上是把字符串第一个元素的地址(即存放字符串的字符数组的首元素地址)赋给string
定义string部分: char *string=”i love china”;
等价于:char *string;
String=”i love china”;
不等价于:*string=”i love china”;
仅仅是把第一个元素的首地址传过来(记住!!!)
说明:通过字符数组名或字符指针变量可以输出一个字符串。而对一个数值型数组,是不能企图用数组名输出其全部元素的。因为%S.
对字符串中字符的存取,可以用下标方法也可以用指针方法。
10.4.2 字符指针作函数参数
将一个字符串从一个函数传递到另一个函数,可以用地址传递的办法。即用字符串数组名作参数,也可以用指向字符的指针变量做参数,在被调用的函数中可以改变字符串的内容。在主调函数中可以得到改变了的字符串。(共用一个字符串)
定义形参的*p是定义过程,不是使用过程中的*p,所以前者可以进行定义赋值初始化。 P255 p256重点例题,了解指针的魅力。
10.4.3 对使用字符指针变量和字符数组的讨论
字符数组和字符指针变量区别
1)字符数组由若干个元素组成,每个元素中放一个字符,而字符指针变量中村存放的是地址(字符中第一个字符的地址),决不是将字符串放到字符指针变量中。
2)赋值方式
对字符数组只能对各个元素赋值,不能用以下办法对字符数组赋值
23
Char str[14]; str=”i love china”;
而字符指针变量可以
Char *a; a=”i love china”;
3) 对字符指针变量赋初值
Char *a=”i love china”;
对数组初始化
Char str[14]=”i love china”;
但是不等价于
Char str[14]; str=”i love china”;
4)字符数组由确切的地址
定义的指针变量仅仅有一个地址,如果不初始化就是不确定因素。
5)指针变量的值可以改变。
数组的值不能改变。
未定义数组时,可以用指针变量的下标形式引用指针变量所指向的字符数组。 P259 例10.2.1
6)用指针变量指向一个格式字符中,可以用它代替printf函数中的格式字符。可变格式输出函数,可用字符串数组实现。
这个时候会有一对双引号的问题,记住!!!
10.5 指向函数的指针
10.5.1 用函数指针变量调用函数
一个函数在编译时被分配一个入口地址,这个入口地址是函数的指针。
Int (*p)(int,int) 用来定义p是一个指向函数的指针变量,该函数有两个整形参数,返回值是整形。
函数名代表该函数的入口地址。
且*p值指向函数入口处,不能指向函数中间的某一提哦啊指令处,因此不能用*(p+1)来表示函数的下标。
说明:
1)一般定义形式为
数据类型 (*指针变量名)(函数参数表列)
这里的数据类型是函数的返回值类型
定义的形式也就是把函数的大致性质告诉了人家指针
2)函数的调用可以通过函数名调用,也可以通过函数指针调用(即用指向函数的指针变量调用)
3) int (*P)(int,int) 表示定义了......
..................
..........
......
24
详细见课本262页261页
10.5.2 用指向函数的指针作函数参数
函数指针变量通常的用途之一是把指针作为参数传递到其他函数。
指向函数的指针也可以作为参数,以实现函数地址的传递,这样就能够在被调用的函数中使用实参函数。
原理:一个sub函数(假设),它有两个形参(x1,x2)。定义x1和x2为指向函数的指针变量,在调用函数sub时实参为俩个函数名的f1和f2,给形参传递的是函数f1和f2的地址,这样就在函数中调用了别的函数
详细见p263 例10.23了解
需要注意:对作为实参的函数,应在主调函数中用函数原型做函数声明!!!
10.6 返回指针值的函数
一般定义形式:
类型名 *函数名(参数列表)
例: int *a(int,int);
A是函数名,调用一个指向整形数据的指针,*a俩边没有括号。
有*表示此函数是指针型函数(函数的int表示返回值指针指向整形变量) P264 p267两例题。!
10.7 指针数组和指向指针的指针
10.7.1 指针数组的概念
基元素均为指针类型数据的数组叫做指针数组。
一般形式:
基型名 *数组名[数组长度];
例: int *p[4];
[]比*的优先级高,p[4]其实就是一数组;前面带的*表示存取的数据时指针型号的。每一个数组里面的没一个元素都是指针。
比较适合于用来指向若干个字符串,是字符串处理更加方便,对不同要求的字符串分别进行定义。用指针连线进行系统化。
P264 运用实例。
10.7.2 指向指针的指针
在指针数组的概念的基础上把指针数组看做一个普通的一维数组,则指向该数组的指针就叫做指向指针的指针。
P271 下
定义一个指向指针的指针变量:
Char **p; p前面有两个*,*是自右向左的运算符。则**P等价于*(*p)。 结合271页图。 P271 例10.27 了解**p
指针数组的元素可以不指向字符串,而指向整型数据或者实型数据等。 P272 例10.28
如果在一个指针变量中存放一个目标变量的地址,这就是单级间址。
指向指针的指针用的是二级间址。
10.7.3 指针数组做main函数的形参
指针数组的一个重要的应用是作为main函数的形参
main 函数可以有参数的。例: void main(int argc,char *argv[]); p273。 25
命令名: 参数1 参数2.......参数n。 具体参见课本。 不重要的一部分。 10.8 有关指针的数据类型和指针运算的小节
10.8.1和10.8.2 自己看看就好了,就是复习。
10.8.3 void指针类型
新定义的,也就是可以定义一个指针变量,但不指定它是指向哪一种数据的。主要又在后面的链表。
详细p277.
十一、结构体与共用体
11.1 概述
有时需要将不同类型的数据组成一个有机的整体,以便于又引用。这些组合在一个整体中的数据时相互联系的,c语言允许用户自己指定这样一种数据结构,它称为结构体,它相当于其他高级语言中的“记录”
例: struct student
{
int num;
char ....;
.......;
};
注意不要忽略最后的分号!!
新的结构体类型 struct student(struct 是声明结构体类型时所必须使用的关键字,不能省略),它声明的这一个结构体,包含整型,字符等等。。。。
Struct student是一个类型名,它是和float一样,都是用来定义变量的,只不过结构体是由用户自己定义的。
一般形式:
Struct 结构体名
{
成员表列
};
对各成员都要进行类型声明,即 类型名,成员名;
11.2 定义结构体类型变量的方法
为了能在程序中使用结构体类型的数据,应当定义结构体类型的变量,并在其中存放具体的数据。
1) 先声明结构体类型在定义变量
例: 结构体类型名 结构体变量名
之后其具有了struct student的类型结构。
定义之后,系统会为之分配内存单元
基本数据类型与结构体类型区别:
1)后者要求指定变量为结构体类型
2)后者要求指定为某一特定的结构体类型。因为结构体类型多种多样,不想定 26
义整形的时候,就一个int .
如果程序规模大,则对结构体类型的声明放到一个头文件中。
2) 在声明类型的同时定义变量
例: struct student
{
。。。。。。
}student1,student2;
一般类型:
struct 结构体名
{
成员表列
}变量名表列;
3) 直接定义结构体类型变量
一般类型:
struct
{
成员表列
}变量名表列;
也就是不出现结构体名,关于结构体类型,有几点要说明;:
1) 类型与变量是不同的概念,不能混同。只能对变量赋值存取或运算。而不能对一个类型赋值。存取或运算在编译时,对类型不分配空间(结构体类型是后妈!!!)
2)对结构体中的成员(即“域”)可以单独使用,它的作用与地位相当于普通变量。
3)成员也可以是一个结构体变量
例: struct date birthday;
4) 成员名可以与程序中的变量名相同,二者不代表统一对象。
11.3 结构体变量的引用
引用时,应遵守一下规定:
1)不能将一个结构体变量作为一个整体进行输入输出。只能对结构体变量中各个成员分别进入输入和输出
引用方式:
这是成员(分量)运算符,所有运算符中优先级最高。
2)如果成员本身又属于一个结构体类型,则要用若干个成员运算符。一级一级的找到最低的一级的成员,在进行操作。
3)对结构体变量的成员可以像普通变量一样进行各种运算(根据其类型决定可以进行的运算)。
4)可以引用结构体变量成员的地址,也可以引用结构体变量的地址。
结构体变量的地址主要用作函数参数,传递结构体变量的地址。
11.4 结构体变量的初始化
可以再定义时定义初始值
1)从变量名那里输入,不是成员那边。P285
2)也可以用上一节中成员运算符进行赋值。
27
11.5 结构体数组
结构体数组与以前介绍过的不同之处在于每一个数组元素都是以个结构体类型的数据,他们都分别包括各个成员(分量)项。
11.5.1 定义结构数组
和定义结构体变量方法相仿,只需说明其为数组就行。
例:
struct student
{
。。。。
};
类型 定义数组时候的内个玩意
也可以直接定义
struct student
{
。。。。
}stu[3];
或者
struct
{
。。。。
}stu[3];
数组各元素在内存中连续存放
11.5.2 结构体数组的初始化
初始化类似以前数组的初始化
struct student
{
。。。。
“。。“},{阿斯顿发},{“”}}; 可以不写数组长度,跟以前的一个意思。 上面的也可以分开写,先声明类型,之后定义数组+初始化。
系统一个结构体变量包括结构体中全部成员的值
初始化的一般形式是在数组后面加上={初值表列};
11.5.3 结构体数组应用举例
P287 重点理解代码
11.6 指向结构体类型数据的指针
一个结构体变量的指针就是该变量所占据的内存段的起始地址。
指针变量也可以用来指向结构体数组数组中的元素
11.6.1 指向结构体变量的指针
P289 例题
(*p)表示p指向的结构体变量
(*p)。Num是p指向的结构体变量的成员num括号不能省略。
28
指向运算符—>,下面三个等价
① 结构体变量。成员名
②(*p)。成员名
③ p—>成员名
p—>n++ 把p-n看做一个整体就容易理解了。
++p—>n
11.6.2 指向结构体数组元素的指针
对结构体数组及元素也可以用指针或指针变量来指向 p290例11.4
把结构体看做一个数组并且该数组还有好几个元素。这样p++时候就是指向下一个数组了。
注意;
1) 如果p的初值是stu,即指向第一个元素,则p+1后p就指向下一个元素。P291
2)已定义了p是指向struct student的,不能用 p=stu[0]。Name 档次不一样着呢!! 如果要是实现的话,就是用强制转化成员为p的格式。
P=(struct student *)stu[0]。Name;
11.6.3 用结构体变来那个和指向结构体的指针作函数参数
将一个结构体变量的值传递给另一个函数,有三个方法:
1)用结构体变量的成员做参数
2)用结构体变量做实参(使用较少)
3)用指向结构体变量(或数组)的指针作实参
将结构体变量(或数组)的地址传给形参
P292 例11.5 了解结构体定义在主函数之外的作用
P293例11.6
字符数组名本身就是地址,前面不带&!!!
11.7 用指针处理链表
11.7.1 链表概述
它是动态地进行存储分配的一种结构
用数组存放数据时们必须事先定义固定的长度(即元素个数)会造成浪费,链表根据需要开辟内存单元。
链表有一个“头指针”变量,它存放一个地址,该地址指向一个元素,链表中每一个元素称为“节点”,每一个节点都应该包括两个部分,用户需要的实际数据和下一个节点的地址。最后一个元素,称为表尾。它的地址部分放一个“NULL”表示空地址,链表到此结束。
可以看出链表个元素内存可以不连续,并且链表必须利用指针变量才能实现。 结构体变量做节点做合适不过了
一个指针类型的成员既可以指向其他类型的结构体数据,也可以指向自己所在的结构体类型的数据
注意:只有定义了变量,才分配内存单元。
11.7.2 简单链表
了解一下过程
所有节点都是程序中定义的。不能临时开辟的。也不能用完释放。这种链表称为“静态链表” 。
29
11.7.3 处理动态链表所需的函数
链表结构是动态的分配存储空间
1)malloc函数
函数原型: void *malloc(unsigned int size);
其作用是在内存的动态存储区中分配一个长度为size的连续空间。此函数的值是一个分配域的起始地址(void型)。如果此函数未能成功执行,那返回空指针(NULL).
2)callic 函数
函数原型; void *calloc(unsingned n,unsigned size);
其作用是在内存的动态存储区中分配n个长度为size空间,返回值是一个指向分配域起始位置的指针。如果分配不成功那返回空指针。
3)free函数
函数原型: void free(void *p);
其作用是释放由p指向的动态存储区,是这部分内存区能被其他变量使用,p是最近一次调用的malloc或calloc函数的返回值。Free函数无返回值。
剩下的链表内容看课本,都是宝贝!!!
11.8 共用体
11.8.1 共用体概念
有时需要使集中不同类型的变量存放到同一段内存单元中。例如:可以把一个整型、一浮点型,一个字符放到同一个地址开始的内存中。虽然字节数不等,但是都从同一地址开始存取。也就是使用覆盖技术。这种使n个不同变量共同用一段内存的结构,称为“共用体”类型的结构。
一般结构:
Union 共用体名
{
成员表列
}变量表列;
也可以将类型声明与变量定义分开,类似结构体
当然也可以直接定义共用体变量。
定义方式与结构图形似,但是含义不同。
结构体变量所占内存长度是各成员的内存长度之和。
共用体变量所占的内存长度等于最长成员的长度。
11.8.2 共同体变量的引用方式
先定义后使用,且只能引用共同体变量中的成员。
例: a。I;a。Ch;
但是不能printf(“%d”,a);
11.8.2 共同体类型数据的特点
1)同一个内存段可以用来存放集中不同类型的成员,但在每一个瞬间值能存放其中一个,而不是同时存放几种
2)共同体变量中起作用的成员是最后一次存放的成员,在存入一个新的成员后原有的成员失去作用,在引用共同体变量时应十分注意当前存放在共同体变量中的究竟是哪个成员。
3)共用体变量的地址和它的各成员的地址都是同一个地址。
30
4)不能对共同体变量名赋值,也不能企图引用变量名来得到一个值,又不能在定义共用体变量时对他初始化。
5)不能把共用体变量作为函数参数,也不能使函数带共用体变量,但是=可以使用指向共用体的指针。
6)共用体类型可以出现在结构体类型定义中 ,也可以定义共用体数组,反之结构体也可以出现在共用体类型定义中,数组也可以作为共用体的成员。
11.9 枚举类型
如果一个变量只有几种可能的值,则可以定义为枚举类型。
所谓“枚举”是指将变量的值,一一列举出来,变量的值只限于列举出来的值的范围内。
声明枚举类型用enum关键字。
例:
enum weekday {sun,a,d,f,g,d,s,};
定义 enum weekday,week_end.;
Weekday 和week_end 被定义为枚举变量。他的值只能上述大括号之间的一个值,也可以直接定义枚举l变量
31
+ 更多类似范文
┣ 语言学重点归纳 13200字
┣ C语言程序学习心得体会 2700字
┣ C语言心得体会 2000字
┣ 西工大C语言POJ作业 5500字
┣ 更多总结语言
┗ 搜索类似范文