C 语言最重要的知识点复习资料!
总体上必须清楚的:
1) 程序结构是三种: 顺序结构 , 循环结构(三个循环结构), 选择结构(if 和 switch)
2) 读程序都要从main()入口, 然后从最上面顺序往下读(碰到循环做循环, 碰到选择做选择) 。
3) 计算机的数据在电脑中保存是以二进制的形式. 数据存放的位置就是它的地址.
4)bit 是位,是指为0或者1。 byte 是指字节, 一个字节 = 八个位.
5) 一定要记住 二进制 如何划成 十进制。
概念常考到的:
1、编译预处理不是C 语言的一部分,不再运行时间,占编译时间。C 语言编译的程序称为源程序,它以ASCII 数值存放在文本文件中。
2、每个C 语言程序中main 函数是有且只有一个。
3、在函数中不可以再定义函数。
4、算法的是一定要有输出的,他可以没有输入。
5、break 可用于循环结构和switch 语句,continue 只用于循环。
6、逗号运算符的级别最低。
第一、二章 C 语言基础及简单程序设计
1. c 语言由什么构成;(函数:一个C 语言程序由一个至多个函数组成,)
2. main()是主函数,该函数既是入口又是出口(一个入口,一个出口)
3. 数据类型:基本数据类型(整型, 字符, 实型, 枚举型), 占用内存的字节数, 表示范围
4. 常量:123,0101(没有8和9), 0x41, '1',-2.30, -1.2E+5
5. 在一个字节内, 字符通整型, 整型通字符
6. 合法的用户标识符考查:
合法的要求是由字母,数字,下划线组成, 并且第一个必须为字母或则是下划线。
关键字不可以作为用户标识符号。main define scanf printf 都不是关键字。迷惑你
的地方If 是可以做为用户标识符。因为If 中的第一个字母大写了,所以不是关键字。
7. 实型数据的合法形式:考试口诀:e 前e 后必有数,e 后必为整数。.
2.333e-1 就是合法的,且数据是2.333×10-1。
8. 字符和字符串数据的合法形式::
'1' 是字符占一个字节,"1" 是字符串占两个字节(含有一个结束符号) 。
'0' 的ASCII 数值表示为48,'a' 的ASCII 数值是97,'A' 的ASCII 数值是65。
9. 转义字符的考查(p28):转义符\: '\n', '\0', '\ddd', '\xdd'等
10. 强制类型转换:
一定是 (int )a 不是 int (a ),注意类型上一定有括号的。
注意(int )(a+b)和(int )a+b 的区别。 前是把a+b转型,后是把a 转型再加b 。
11. 自加、自减表达式:假设a=5,++a(是为6), a++(为5);
运行的机理:++a 是先把变量的数值加上1,然后把得到的数值放到变量a 中,然后再
用这个++a表达式的数值为6,而a++是先用该表达式的数值为5,然后再把a 的数值
加上1为6,再放到变量a 中。 进行了++a和a++后在下面的程序中再用到a 的话都
是变量a 中的6了。
考试口诀:++在前先加后用,++在后先用后加。
12. 逗号表达式:优先级别最低 ;表达式的数值逗号最右边的那个表达式的数值。如(2,
3,4)的表达式的数值就是4。
13. 位运算的考查:口诀:先转二进制再运算
总的处理方法:(先把十进制变成二进制再变成十进制)。
例1: char a = 6, b;
b = a
例2: 在没有舍去数据的时候,>右移一位表示除以2。
14. % 符号两边要求是整数。不是整数就错了。
15. 变量:变量的命名规则满足标识符的命名规则,区分大小写,关键字(p7)除外, 变量的定
义一般都要放在函数或程序的开头位置(即先定义后使用)
16. 分号: 表示一个语句结束
17. 变量的定义: 类型名 变量名列表; (不同的类型要写成两句), 定义的时候给值成为变量
的初始化,初始化的时候不能连等
。
18. 变量的赋值: 变量名=表达式 或 变量名复合赋值运算符表达式 (复合赋值运算
符:+=,*=,^=,...), 如: xyz+2=c行吗?不行(赋值表达式左边只能是变量)!赋值的时候
可以连等。
19. 输入一个字符: x=getchar(), putchar(x), 有这两个函数及FILE 时一定要加上
#include //标准输入输出的头文件包含
20. getch(), 表示暂停程序运行,可直接查看结果,否则运行完后不显示结果(需按
ALT+F5)。
21. printf("xxxxxxxxxxxxxxx"); 或 printf("格式控制符", 变量列表) ;变量列表不加&
22. scanf("格式控制符", 地址列表), 地址列表可为数组名、指针变量名及普通变量名(普
通变量名前要加加&)。
23. printf("%m.nf", 32.6789)
24. scanf 的格式控制符中, 除了逗号, 一般不加其他字符;一定要记住, 有逗号时输入要加逗
号, 否则:数据用空格隔开,字符连着输入; 没有"%m.nf"的写法, 只有"%mf"的写
法,
float 型用"%f", double型用"%lf", long double用"%Lf"
25. 不同类型的数值型数据进行混合运算
不同类型的数值型数据进行混合运算时,
先要把低数据类型向高数据类型转换, 成为同一类型后才进行运算。
横向箭头表示必须进行的转换。
逗号运算符是最低的运算符
常量不能++、--;
例:b=(a=1,a++,a++),
又例:b=(a=2)+(a=3),
又例:a=1;b=(++a)+(++a)
=与==的区别(赋值和等号)
26. 在C 语言中,对于逻辑运算,非零的数(不管实数还是整数)都认为是真的,真的就是
1,假的就是0;
27. 关系运算的结果是逻辑值(真为1假为0)。
28. 运算符:
运算符的优先序(p246):成单算移关于,异或逻条赋逗。
运算符的结合性(p246):条件、单目、赋值运算符。(printf 输出也是自右而左运算)
例如. 以下程序的运行结果是
struct st
{ int n; float x;
}*p;
void main()
{ struct st arr[3]={{10,5.6},{12,7.1},{14,6.7}};
p=arr;
printf(“%d \n”,++p->n);
p++;
printf(“%d,%.2f \n”,p->n,p->x);
}
A) 12 B) 11 C) 11 D)12
12,7.10 10,5.60 12,7.10 14,6.70
第三、四章 选择和循环结构
1.
2.
3.
4. C 程序一般采用自顶向下的编写格式, 模块化(函数) C 程序结构有三种: 顺序, 选择(分支), 循环 { }: 用在函数, 或复合语句 分支结构(或选择结构)[if结构和switch 结构]
①. if 分支结构
单分支: if(表达式) 语句; 或if(表达式) {语句组}
双分支: if(表达式) 语句1;
else 语句2;
多分支if : if(表达式1) 语句1;
else if(表达式2) 语句2;
...
else if(表达式n-1) 语句n-1;
else 语句n;
②. 多分支switch:
switch(x)
{ case x1: 语句1;[break;]
...
case xn: 语句n; [break;]
default: 语句; [break;]
}
例:main()
{ int c;
while((c=getchar())!= '\n')
{ switch(c-'2')
{ case 0 :
case 1 : putchar(c+4);
case 2 : putchar(c+4); break;
case 3 : putchar(c+3);
default: putchar(c+2); break;
}
}
printf("\n");
}
当输入:247,程序的输出结果是( )。
(A) 689 (B) 6689 (C) 66778 (D) 66887
switch 总结:
● 其语义是:先计算出表达式的值,用此值与哪个case 后的常量表达式的值相
一致,则执行那个case 后的语句组,如果语句组后有break 语句则直接退出switch
结构,如语句组执行后没有break 语句则继续执行后续case 后的语句组,直到遇到
break 语句退出switch 结构,如没有break 语句则会执行后续所有case 或default
后的语句组再退出switch 结构。
● 若计算出表达式的值与case 后的所有常量表达式的值都不同则只执行
default 及之后的语句组一直执行到最后(若遇break 则终止退出switch 结构),如
没有default 语句则直接退出switch 结构。
5. 循环语句:
(1) for(表达式1; 表达式2; 表达式3) 或 for(表达式1; 表达式2; 表达式3)
{ 循环体语句组; 循环体语句;
...
[break;] /*用于结束当层循环,跳到当层循环后面的语句。*/
...
[continue;] /*用于结束当次循环,跳过当次循环后面的语句,进入下次循环。*/
...
}
(2) while(表达式) while(表达式)
{ 循环体语句组; 循环体语句;
...
[break;]
...
[continue;]
...
}
(3) do
{ 循环体语句组;
...
[break;]
...
[continue;]
...
}while(表达式);
例:
for (i=1; i
{ {
if ( i%2==0 ) break; if ( i%2==0 ) continue;
printf(“%d”, i); printf(“%d”, i);
} }
6. 循环嵌套: 从外循环进来,内循环结束后,再到外循环,如此反复,直到外循环结束) x=0; 或 x=0;
for(i=1; i
for(j=1; j
x+=i*j; while(j
{ x+=i*j; j++;
} } 7.
8. break 可用于switch 和循环语句, 一个break 只退出一层; 而continue 只对循环有效 记住:质数的判断,斐波那契数列, 辗转相除法,求数列的和(有正符号如何处理?置
标志位)
• for 循环与 while 循环类似,属于先判断后执行; do while,属于先执行后判断
• for 语句中有三个表达式:表达式1通常用来给循环变量赋初值;表达式2通常是循
环条件;表达式3用来更新循环变量的值
• for 语句中的各个表达式都可以省略,但要注意分号分隔符不能省略
• 如果省略表达式2和表达式3需要在循环体内设法结束循环,否则会导致死循环 • break 语句用在循环中时,可以直接终止当前循环,将控制转向循环后面的语句 • continue 语句的作用是跳过循环体中剩余的语句而执行下一次循环
• 嵌套循环时,必须将被嵌套的循环语句完整地包含在外层循环的循环体内
第五章 函数
1. 系统函数:数学类函数(math.h ),输入输出函数(stdio.h ),字符串类函数(string.h )
2. 自定义函数:格式
类型名 函数名(形式参数列表)
{
函数体
}
3. 不写函数类型名默认为整型
4. 如果函数类型名为void 表示无返回值函数(不写return )
5.
(或字符型) ,则在调用
函数名(形式参数函数中或调用函数之前应该先声明列表) ;
6. 函数的递归:直接或者间接调用自身。(如阶乘)
7. 全局变量:在函数外定义的变量,如果定义时没给值,默认为0
8. 局部变量:在函数内定义的变量、形式参数、复合语句中定义的变量,如果没给具体
的值,该值不确定
9. 对于全局变量和局部变量主要观察在函数中是否被重新定义,若全局变量和局部变量
同名,则自动屏蔽掉全局变量。
10. 函数调用时,实参向形参传递:
(1) 按值传递:形参的变化不会改变实参的变化。
(若有返回值将值带回,否则带回控制流,函数的返回值类型与函数类型一致);
(2) 按地址传递:形参的变化就会有可能改变实参的变化。
(3) 数组传递,通常就把数组名及数组元素传过去
11. 如果一个函数名为:fun(x),严禁出现:fun(x)=…, 不管递归与否(满足标识符命
名)
12.
13. return y; 或return (y ); 不要写成 return y1, y2; 静态变量: static int x; (1) 没给值,默认为0; (2) 始终占用内存,其值会保
留下来(即赋值一次,不再重新赋值,保留上次运行结果)
[静态变量]举例
eg :以下程序的运行结果是( C )。
fun3(int x) main()
{ static int a=3; { int k=2,m=1,n;
a+=x; n=fun3(k);
return a; n=fun3(m);
} printf("%d\n",n);
}
A 、3 B 、4 C 、6 D 、9
14. 宏定义:#define 标识符 字符串,宏一定要先替换后计算
分带参和无参宏定义 无参宏定义 如#define P x*x //表示碰到P 时用x*x替换
带参宏定义 如#define P (x ) x*x //表示碰到P (x )时用x*x替换
[无参宏定义]举例
若有定义:#define N 3+2,则表达式N*2的值为( B )。
A 、5 B 、 7 C 、10 D 、0
解释:N*2=3+2*2=3+4=7。
[带参宏定义]举例
以下程序运行后输出结果是( B ) 。
#define MIN(m,n) m
解释:c=2*MIN(a,b)=2* a
第六章 数组
1. 一维数组的定义格式为:类型说明符 数组名[常量表达式];例如: int a[10]; 常量表达式可以是整型常量或字符常量或枚举值或符号常量表达式(注意不能包含变量). 例如,下面这样定义数组是不行的:
•
① int n; scanf(“%d″,&n); int a[n ];
② int k,M=5, a[k],b[M]; /* 不能用变量说明数组大小*/
③ float a[0]; /* 数组大小为0没有意义 */
④ int b(2); /* 不能使用圆括号 */
2. 数组元素下标可以是整型常量、变量、变量或整型表达式。
3. C 语言规定,下标的最小值是0,最大值则是数组大小减1 。
eg :m[8]中,表示数组m 有8个元素,下标从0开始一直到7。这8个数组元素分别是:m[0]、 m[1]、 m[2]、 m[3]、 m[4]、 m[5]、 m[6]、 m[7],注意没有m[8]。
4. 对一维数组的初始化赋值
(1)可以只给部分元素赋初值。没有赋值的元素:对于数值型数组,自动赋初值为0;对字符型数组,自动赋初值为空字符。
(2)只能给元素逐个赋值,不能给数组整体赋值。int m[5]={2,2,2,2,2};
不能写成: int m[5]=2;
(3)如果给全部元素赋值,则在数组说明中,可以不给出数组元素的个数,其长度等于初值表中数组元素的个数。 int m[]={1,2,3,4,5};
5. 二维数组元素的引用 形式: 数组名[下标1][下标2];
6. 二维数组元素的初始化
(1) 分行初始化:存储类型符 数据类型 数组变量名[行常量表达式][列常量表达式] =
{{第0行初值表},{第1行初值表},……,{最后1行初值表}};
Eg :若有定义:int s[3][4]={{1,2},{0},{3,4,5}};则s[2][1]的值为( B )。
A. 3 B. 4 C. 0 D. 1
(2) 省略一维大小:存储类型符 数据类型 数组变量名[行常量表达式][列常量表达式]
={ 初值表 };
Eg :int a[][4]={1,2,3,4,5,6,7,8,9,10,11,12}; printf("%d\n",a[1][2]);
A. 2 B. 3
C. 6 D. 7 11
7. 字符数组的定义格式:char 数组名[常量表达式];
8. 在c 语言中,没有专门的字符串变量,通常是用一个字符数组来存放一个字符串,由于
字符串总是以‘\0’作为串的结束标志,因此当把一个字符串存入一个数组时,也把结束符‘\0’存入数组,并以此作为该字符串结束的标志
9. C 语言允许用字符串的方式对数组做初始化赋值。有两种方式:
(1)按单个字符的方式赋初值,其中必须有一个字符是字符串的结束标记(但字符数组可以不包括’\0’) 。 如char s[]={‘1’, ’2’, ’3’, ’\0’};
10. (2) 直接在初值表中写一个字符串常量。如char s[]={“123”};{}可以省略
char s[]={‘1’, ’2’, ’3’, ’\0’}; char s[]={“123”}; char s[]=“123”;
11. 设已定义char s[ ]="\"Name\\Address\023\n";,则字符串所占的字节数是( B )。
A.19 B. 16
12. 字符串的常用串函数
① strlen 函数——测试字符串长度
• 格式: strlen (字符数组);
• 功能:测试指定字符串的实际长度(不含字符串结束标志‘\0’),并返回字符串的长度 其中,函数的参数可以是字符型数组名或字符串常数,函数的返回值是字符串的长度。 strlen 得到的是有效字符的个数(不包括‘\0’)
sizeof 得到的是整个数组的长度(包括‘\0’)
②. strcat 函数——字符串连接函数
格式: strcat(字符数组1,字符数组 2) ;
功能:把字符数组2中的字符串连接到字符数组1中字符串的后面,同时删去字符串1
的串标志‘\0’,组成新的字符串。该函数返回值是字符数组1的首地址
③. s trcmp 函数——字符串比较函数
格式:strcmp(字符串1,字符串2) ;
功能:字符串1和字符串2可以是字符型数组名或字符串常量。按照ASCII 码顺序比
较两个数组中的字符串,并由函数返回值返回比较结果
④. strcpy 函数——字符串拷贝函数
格式: strcpy(字符数组1,字符数组2) ;
功能:把字符数组2中的字符串拷贝到字符数组1中。字符串结束标志‘\0’也一同
拷贝。字符数组2也可以是一个字符串常量,这时相当于把一个字符串赋予一
12 C. 18 D. 14
个字符数组
注意:
字符数组1必须定义的足够大,以便能容纳被复制的字符串,字符数组1的长度不应该小于字符串2的长度;
字符数组1必须写成数组名形式,字符数组2可以是字符数组名,也可以是一个字符串常量;
有时只需要复制字符数组2中前面若干个字符,这些用strcpy 函数也能实现。
如:strcpy (m1,m2,3)表示将m2前面3个字符复制到m1中,从而取代m1中最前面的3个字符。
13. 冒泡排序、直接排序、交换排序
14. 杨辉三角、矩阵转置(矩阵转置只要循环一半就可以)。
15. 一维数组倒序存放、矩阵转置只要循环一半就可以
13
第七章
⏹ 本章主要内容: 指针
指针的概念、定义和引用、指针与函数、指针与数组、指针与字符串、指针数据类型小结
1. 指针变量的本质是用来放地址,而一般的变量是放数值的。
int *p 中 *p和p 的差别:
*p可以当做变量来用;*的作用是取后面地址p 指向的数值,p 是当作地址来使用。 *p++ 和 (*p)++的之间的差别:改错题目中很重要
*p++是 地址会变化;(*p)++ 是数值会要变化。
2. 指针变量的定义:一般形式为:类型符 *指针变量名; 如:int *p;
3. 指针变量的引用。两种基本的指针运算:
☐
☐ &:取变量的地址 * :指针运算符(或称“间接访问”运算符)
4. 指针变量作函数参数
[例7. 3] 用函数实现两个变量的交换
v o i d s w a p (i n t *p 1, i n t *p 2)
{ i n t *t ;
t =*p 1; *p 1=*p 2; *p 2=t ;
}
m a i n ()
{ i n t a =5, b =9;
s w a p (&a , &b ) ;
p r i n t f (“a =%d , b =%d \n ”, a , b ) ;
}
5. 指针函数(函数的返回值为指针)
一般定义为:类型符 *函数名(参数表) {……}
把两个数中的最大值设为0
i n t *m a x (i n t *q 1, i n t *q 2)
{ r e t u r n *q 1 > *q 2 ? q 1 : q 2; }
m a i n ()
{ i n t x =5, y =9, *p ;
p =m a x (&x , &y ) ;
*p =0;
p r i n t f (" x =%d , y =%d \n " , x , y ) ;
}
6. 函数指针(用一个指针变量存储一个函数入口地址,即指向函数,这样的指针称函数指针) ①. 定义形式为:类型符 (*函数指针变量) () ; 如:i n t (*p ) () ;
14
②. 使函数指针指向一个函数,一般的格式为:函数指针变量=函数名;如:p =m a x ; ③. 调用函数。一般格式为: (*函数指针) (实参表) 如:c =(*p ) (a , b ) ;
[ 例7. 5] 通过函数指针调用函数
i n t m a x (i n t x , i n t y ) {r e t u r n x >y ? x :y ; }
i n t m i n (i n t x , i n t y ) {r e t u r n x
m a i n ()
{ i n t a =5, b =9, c , d ;
i n t (*p ) () ; //定义函数指针
p =m a x ; //指向函数
c =(*p ) (a , b ) ; //调用函数
p =m i n ; d =(*p ) (a , b ) ;
p r i n t f (“M a x =%d , M i n =%d \n ”, c , d ) ;
}
7. 指针与数组的关系
一个变量有地址,一个数组包含若干个数组元素,每个数组元素都在内存中占用存储单元,它们都有相应的地址,这个地址就可以用指针来实现存储。
如有:i n t a [5], *p , *q ;
p =&a [0]; q =&a [2];
*p =5; *q =8; 则a [0]和a [2]值分别为5和8。
8. C 语言规定:数组名代表数组的首地址,也就是第一个元素a [0]的地址。
因此: a ⇔ &a [0]。
若: p =a ; /* 或写成p =&a [0]; */
则: p +1 ⇔ &a [1] *(p +1) ⇔ a [1] p +i ⇔ &a [i ] *(p +i ) ⇔ a [i ]
9. 引用一个数组元素,可以用指针法。
☐ 通过数组的起始地址计算数组元素的地址 ,即*(a +i ) 或*(p +i ) 形式。
☐ ,即p ++ 形式:
m a i n ()
{ i n t a [5]={3, 8, 9, 2, 6}, i , *p ;
p =a ;
f o r (i =0; i
{ p r i n t f (“%d “, *p ) ; p ++; }
}
【例7. 5 】指针运算符“*”与增1运算符“++”同时作用于一个指针变量的情况。 m a i n ()
15
{
i n t i , a []={ 11, 22, 33, 44, 55, 66 }, *p =a ;
p r i n t f (" %3d , " , (*p ) ++) ; 11
p r i n t f (" %3d , " , *p ++) ; 12
p r i n t f (" %3d , " , *++p ) ; 33
p r i n t f (" %3d \n " , ++*p ) ; 34
f o r (p =a ; p
p r i n t f (" %3d , " , *p ) ; 12 22 34 44 55 66
p r i n t f (" \n " ) ;
g e t c h () ;
}
2、通过指针引用二维数组元素
(1) 二维数组和数组元素的地址
i n t a [3][4]={{ 1, 2, 3, 4 }, {6, 7, 8, 9}, {11, 12, 13, 14} }
a [0] a [1] a [2]
则 a &a [0], a +1 &a [1], a +2 &a [2]
对于一维数组名为a [0], 则
a [0] &a [0][0], a [0]+1 &a [0][1].
所以第0行第1列的地址表示为a [0]+1.
所以a [i ]+j 是第i 行第j 列元素的地址 &a [i ][j ],
又a [i ] 等价于 *(a +i )
所以在二维数组里*(a +i ) +j 和a [i ]+j 都表示地址。
(2) 通过地址访问二维数组
假设有如下定义: i n t a [3][5], i , j ;
则二维数组a 中的任一元素a [i ][j ],可以用下述表达式之一来引用表示:
①. *(a [i ]+j ) 由上述知a [i ]+j 是第i 行第j 列元素的地址,因此*(a [i ]+j ) 与a [i ][j ]等价
②. *(*(a +i ) +j ) , *(a +i ) +j 也是第i 行第j 列元素的地址,因此*(*(a +i ) +j ) 与a [i ][j ]等价 ③. (*(a +i ) ) [j ],相当于先取*(a +i ) +j 地址,再取其内的值,所以与a [i ][j ]等价
④. *(&a [0][0]+5*i +j ) 由于每行5个元素,&a [0][0]+5*i +j 就是第i 行第j 列元素的地址,
因此*(&a [0][0]+5*i +j ) 也与a [i ][j ]等价
*(&a [0][0]+5*i +j ) *(a [0]+5*i +j ) *(*a +5*i +j ) a [i ][j ]
16
(3) 通过指向元素指针访问二维数组
如: i n t a [3][5], i , j , *p ; p =&a [0][0]; 或 p =*a ; 或 p =a [0];
则 a [i ][j ] 等价于 *(p +i *5+j ) 等价于 p [i *5+j ]
10. 数组名作函数参数的指针解释
对形参数组改为指针。
i n t a r r a y _m a x (i n t x [ ], i n t n )
{
}
m a i n ()
{ i n t a [ ]={8, 7, 55, 23, 49}, m a x ;
}
11. 指针数组
一般说明形式为:类型符 *数组名[数组大小]; 如:i n t *p [5];
指针数组的简单使用
m a i n ()
{ i n t a [5]={1, 3, 5, 7, 9};
i n t *n u m [5], i ;
f o r (i =0; i
n u m [i ]=&a [i ];
f o r (i =0; i
p r i n t f (“%d “, *n u m [i ]) ;
}
12. 多级指针
有:i n t a , *p =&a ; 若使:q =&p ; 则q 是就指向指针变量的指针变量,称q 为二级指针。 二级指针定义的一般形式为:类型符 **指针变量名; 如:i n t **q ;
则:a =5; 或*p =5; 或**q =5; 结果相同。
同样可以有三级、四级指针等等,我们把二级及二级以上的指针称为多级指针。
[例7. 9] 数组的输出
m a i n ()
17 i n t i , m = x [0] ; f o r (i =1; i
{ i n t a [5]={1, 3, 5, 7, 9};
i n t *b [5], i , **p ;
f o r (i =0; i
b [i ]=&a [i ];
p =b ;
f o r (i =0; i
p r i n t f (“%d “, **p ++) ;
}
13. 指针与字符串
字符串的表示形式 c h a r 字符数组名[数组元素个数]
如有: c h a r s t r [80]=“C h i n a ”, *p =s t r ;
p r i n t f (“%s ”, s t r ) ; p r i n t f (“%s ”, p ) ; p r i n t f (“%s ”, ”C h i n a ”) ; 用%s 输入/输出字符串时, 只需要知道字符串的开始地址即可。
使p 指向字符串的开始地址,可写成: c h a r *p =”C h i n a ”;
14. 字符指针作函数参数
[例7. 11] 将例7. 10改用函数完成
i n t S t r L e n (c h a r *s )
{ i n t n =0;
w h i l e (*s ++) n ++;
r e t u r n n ;
}
m a i n ( )
{
}
运行结果:a b c 的长度为3
15. 返回字符串的函数
[例7. 13] 改写字符串复制函数
c h a r *S t r C o p y (c h a r *s t r 1, c h a r *s t r 2)
18 c h a r s t r [ ]=”a b c ”, *p ; i n t l e n ; p =s t r ; l e n =S t r L e n (p ) ; p r i n t f (“%s 的长度为%d \n ”, p , l e n ) ;
{ c h a r *p =s t r 1;
w h i l e ((*s t r 1=*s t r 2) ! =’\0’)
{ s t r 1++; s t r 2++; }
r e t u r n p ;
}
m a i n ()
{ c h a r s 1[80], s 2[ ]= “a b c ”;
p r i n t f (“复制之后的字符串:%s \n ”, S t r C o p y (s 1, s 2) ) ;
}
复制之后的字符串:a b c
16. 字符指针数组
[例7. 14]将若干字符串输出
m a i n ()
{
}
[例7. 15]使用多级指针完成若干字符串输出
m a i n ()
{
}
输出:W o r d
E x c e l c h a r *s t r [ ]={“W o r d ”, ”E x c e l ”, ”O u t l o o k ”}; c h a r **p ; f o r (p =s t r ; p
O u t l o o k
17. 字符指针与字符数组的讨论
占用的内存空间不同 19
c h a r s t r [80]; c h a r *p ;
⏹ 初始化的概念不同
⏹ c h a r s t r [80]=“a b c ”; c h a r *p =“a b c ”; 数组名是常量,字符指针是变量
s t r =s t r +2; /* E r r o r */
p =s t r +2; /* O k */
c h a r s t r [80], *p ; s c a n f (“%s ”, s t r ) ; /* O k */ s c a n f (“%s ”, p ) ; /* e r r o r */ ⏹ 字符数组有一块确定的、连续的内存单元;而指针只有一个字的内存单元。所以:
18. 指针数据类型小结
⏹ 各种指针定义小结
i n t x ; 整型变量x
i n t *p ; 整型指针p
i n t a [n ]; a 是一个整型数组,有n 个元素
i n t *p [n ]; p 是一个整型指针数组,有n 个元素
i n t f () ; f 是一个函数,返回一个整型值
i n t *p () ; p 是一个函数,返回一个整型变量的地址
i n t (*p ) () ; p 为一个指针,它可以指向一个整型函数
i n t **p ; p 为一个二级指针,它存储另一个指针的地址
⏹ 指针运算小结
1、指针变量加、减一个整数, 指的是移到向上或向下一个单位的地址 例如:p ++、p --、p +i 、p -i 、p +=i 、p -=i 等。
2、指针变量赋值
如有:i n t a , *p 1, *p 2, a r r a y [10], m a x () , (*p 3) () ; 则:
p 1=&a ; /* 取变量a 的地址,使p 1指向a */ /* p 2指向a r r a y 数组的起始地址 */ p 2=a r r a y ; p 1=&a r r a y [4]; /* p 1指向a r r a y [4]元素 */ p 3=m a x ; p 2=p 1; /* p 3指向m a x 函数 */ /* p 2的指向与p 1的指向相同 */ 20
p 1=2000; a =p 2;
/* e r r o r ,类型不同 */
/* e r r o r ,类型不同 */
19. 三名主义:(考试的重点)
数组名:表示第一个元素的地址。数组名不可以自加自减,它是地址常量名。 函数名:表示该函数的入口地址。 字符串常量名:表示第一个字符的地址。 20. 一维数组的重要概念:
对a[10]这个数组的讨论。
1、a 表示数组名,是第一个元素的地址,也就是元素a[0]的地址。
2、a 是地址常量,所以只要出现a++,或者是a=a+2赋值的都是错误的。 3、a 是一维数组名,所以它是列指针,也就是说a+1是跳一列。 对 a[3][3]的讨论。
1、a 表示数组名,是第一个元素的地址,也就是元素a[0][0]的地址。 2、a 是地址常量,所以只要出现a++,或者是a=a+2赋值的都是错误的。 3、a 是二维数组名,所以它是行指针,也就是说a+1是跳一行。
4、a[0]、a[1]、a[2]也都是地址常量,不可以对它进行赋值操作,同时它们都是列指针 a[0]+1,a[1]+1,a[2]+1都是跳一列。
5、注意a 和a[0] 、a[1]、a[2]是不同的,它们的基类型是不同的。前者是一行元素,后三者是一列元素。 21. 二维数组做题目的技巧:
如果有a[3] [3]={1,2,3,4,5,6,7,8,9}这样的题目。
步骤一:把他们写成: 第一列 第二列 第三列 a[0] 1 2 3 ->第一行 a[1] 4 5 6 —>第二行 a[2] 7 8 9 ->第三行 步骤二:这样作题目间很简单:
*(a[0]+1)我们就知道是第一行的第一个元素往后面跳一列,那么这里就是a[0][1]元素,所以是1。 *(a[1]+2)我们就知道是第二行的第一个元素往后面跳二列。那么这里就是 a[1][2]元素,所以是6。
一定记住:只要是二维数组的题目,一定是写成如上的格式,再去做题目,这样会比较简单。
数组的初始化,一维和二维的,一维可以不写,二维第二个一定要写
int a[]={1,2} 合法。int a[][4]={2,3,4}合法 。但int a[4][]={2,3,4}非法。 16. 二维数组中的行指针
int a[1][2];
其中a 现在就是一个行指针,a+1跳一行数组元素。 搭配(*)p[2]指针
a[0],a[1]现在就是一个列指针。a[0]+1 跳一个数组元素。搭配*p[2]指针数组使用
还有记住脱衣服法则:
a[2] 变成 *(a+2) a[2][3]变成 *(a+2)[3]再可以变成 *(*(a+2)+3) 这个思想很重要!
17. 不能对字符数组整体赋值,而字符指针允许整体赋值
18. 指针p 可以p++(后移)或p--(前移)或p+i,而数组名a 只能用,a+i(注意一维
数组和二维数组的区别)
19. 两个地址(指针)可以比较大小,后面大前面小;可以相减表示差几个元素 20. 对字符数组或字符串的操作一般用:
while(*s) 或while(s[i]) 或for(p=a; p
{ …; s++} {…; i++} 注意:新生成的字符串是否有结束符’\0’ 10.字符串打印: char s1[10], s2[6][10], *s3;
(1) (2)
一维数组:printf(“%s”, ……) ; 二维数组:printf(“%s”, ……) ;
第八章 结构体、共用体和枚举
1. 2.
记住数组也属于自定义类型 结构类型 struct [staff] {
char no[5];
char name[10]; char sex; struct { int year;
int month; int day;} birthday; float wages[2];
}worker, workers[100], *p=&worker, *q=workers;
[struct staff a,b;] //若 定 义 的 结 构 体 无 结 构 体 名 则 只 能 直 接 定 义结 构 体 变 量,不 能 间 接 定 义 。
3.
※ 通过指针访问结构体变量的成员 ① 结构变量名. 成员名(名字引用); ② 结构指针->成员名(指针引用);
③ (*结构指针). 成员名(将指针转化为名字引用); 4.
『结构变量占用内存情况』结构变量的各个成员分量在内存中占用连续存储区域,所占内存大小为结构中每个成员的占用内存的长度之和。
5.
联合类型(union )
(1) (2) (3) (4) (5) (6)
6.
表示法同结构类型 首地址起共用 允许对第一个成员赋值
共用体变量任何时刻-只有一个成员存在
共用体变量定义分配内存, 长度=最长成员所占字节数(即字节数取最大的) 共用体变量的定义形式有三种(类似结构体变量的定义)
枚举类型
enum weekdays {Sun,Mon,Tue,Wed,Thu,Fri,Sat}; (1) (2)
枚举型仅适应于取值有限的数据。
取值表中的值称为枚举元素,枚举元素是常量。在C编译器中,按定义的顺序取值0、1、2、... 。所以枚举元素可以进行比较,比较规则是:序号大者为大。例如,上例中的Sun=0、Mon=1、……、Sat=6,所以Mon>Sun、Sat 最大。
(3)
枚举元素的值也是可以人为改变的:定义时由程序指定。例如,如果enum weekdays {Sun=7, Mon=1 ,Tue, Wed, Thu, Fri, Sat}; 则Sun=7,Mon=1,从Tue=2开始,依次增1。
7. 定义别名
int X, Y[10], *Z;
X a; Y b; Z c;
其中a ,b ,c 各代表什么?
整型变量a, 整型数组b[10], 整型指针变量c 。
第九章 文件操作与位运算
1. 6个位运算符 : 位左移>、按位取反~、位与&、位或 |、位异或 ^。 2. 位运算题目计算是先要把十进制化成二进制,再做位运算。
在没有舍去数据的时候,>右移一位表示除以2。 3. 所谓“文件”一般指存储在外部介质上数据的集合。
按文件中数据的组织形式来分,可分为文本文件(即ASCII 码文件)和二进制文件。 4. 文件操作的过程:对磁盘文件的操作必须“先打开,后读写,最后关闭”。 5. 文件的打开方式
6. 常用文件操作函数
7. 文件输入输出小结
分类 函数名 功能 打开文件 fopen() 打开文件 关闭文件 fclose() 关闭文件
文件定位 fseek() 改变文件位置指针的位置 rewind() 使文件位置指针重新至于文件开头 ftell() 返回文件位置指针的当前值 文件状态 feof() 若到文件末尾,函数值为真 ferror() 若对文件操作出错,函数值为真 文件读写 clearerr() fgetc() fputc() fgets() fputs() getw()
putw() fread() fwrite() fscanf() fprintf()
使ferror 和feof()函数值置零 getc()从指定文件取得一个字符 putc()把字符输出到指定文件 从指定文件读取字符串 把字符串输出到指定文件 从指定文件读取一个字(int 型) 把一个字输出到指定文件 从指定文件中读取数据项 把数据项写到指定文件中 从指定文件按格式输入数据 按指定格式将数据写到指定文件中
C 语言最重要的知识点复习资料!
总体上必须清楚的:
1) 程序结构是三种: 顺序结构 , 循环结构(三个循环结构), 选择结构(if 和 switch)
2) 读程序都要从main()入口, 然后从最上面顺序往下读(碰到循环做循环, 碰到选择做选择) 。
3) 计算机的数据在电脑中保存是以二进制的形式. 数据存放的位置就是它的地址.
4)bit 是位,是指为0或者1。 byte 是指字节, 一个字节 = 八个位.
5) 一定要记住 二进制 如何划成 十进制。
概念常考到的:
1、编译预处理不是C 语言的一部分,不再运行时间,占编译时间。C 语言编译的程序称为源程序,它以ASCII 数值存放在文本文件中。
2、每个C 语言程序中main 函数是有且只有一个。
3、在函数中不可以再定义函数。
4、算法的是一定要有输出的,他可以没有输入。
5、break 可用于循环结构和switch 语句,continue 只用于循环。
6、逗号运算符的级别最低。
第一、二章 C 语言基础及简单程序设计
1. c 语言由什么构成;(函数:一个C 语言程序由一个至多个函数组成,)
2. main()是主函数,该函数既是入口又是出口(一个入口,一个出口)
3. 数据类型:基本数据类型(整型, 字符, 实型, 枚举型), 占用内存的字节数, 表示范围
4. 常量:123,0101(没有8和9), 0x41, '1',-2.30, -1.2E+5
5. 在一个字节内, 字符通整型, 整型通字符
6. 合法的用户标识符考查:
合法的要求是由字母,数字,下划线组成, 并且第一个必须为字母或则是下划线。
关键字不可以作为用户标识符号。main define scanf printf 都不是关键字。迷惑你
的地方If 是可以做为用户标识符。因为If 中的第一个字母大写了,所以不是关键字。
7. 实型数据的合法形式:考试口诀:e 前e 后必有数,e 后必为整数。.
2.333e-1 就是合法的,且数据是2.333×10-1。
8. 字符和字符串数据的合法形式::
'1' 是字符占一个字节,"1" 是字符串占两个字节(含有一个结束符号) 。
'0' 的ASCII 数值表示为48,'a' 的ASCII 数值是97,'A' 的ASCII 数值是65。
9. 转义字符的考查(p28):转义符\: '\n', '\0', '\ddd', '\xdd'等
10. 强制类型转换:
一定是 (int )a 不是 int (a ),注意类型上一定有括号的。
注意(int )(a+b)和(int )a+b 的区别。 前是把a+b转型,后是把a 转型再加b 。
11. 自加、自减表达式:假设a=5,++a(是为6), a++(为5);
运行的机理:++a 是先把变量的数值加上1,然后把得到的数值放到变量a 中,然后再
用这个++a表达式的数值为6,而a++是先用该表达式的数值为5,然后再把a 的数值
加上1为6,再放到变量a 中。 进行了++a和a++后在下面的程序中再用到a 的话都
是变量a 中的6了。
考试口诀:++在前先加后用,++在后先用后加。
12. 逗号表达式:优先级别最低 ;表达式的数值逗号最右边的那个表达式的数值。如(2,
3,4)的表达式的数值就是4。
13. 位运算的考查:口诀:先转二进制再运算
总的处理方法:(先把十进制变成二进制再变成十进制)。
例1: char a = 6, b;
b = a
例2: 在没有舍去数据的时候,>右移一位表示除以2。
14. % 符号两边要求是整数。不是整数就错了。
15. 变量:变量的命名规则满足标识符的命名规则,区分大小写,关键字(p7)除外, 变量的定
义一般都要放在函数或程序的开头位置(即先定义后使用)
16. 分号: 表示一个语句结束
17. 变量的定义: 类型名 变量名列表; (不同的类型要写成两句), 定义的时候给值成为变量
的初始化,初始化的时候不能连等
。
18. 变量的赋值: 变量名=表达式 或 变量名复合赋值运算符表达式 (复合赋值运算
符:+=,*=,^=,...), 如: xyz+2=c行吗?不行(赋值表达式左边只能是变量)!赋值的时候
可以连等。
19. 输入一个字符: x=getchar(), putchar(x), 有这两个函数及FILE 时一定要加上
#include //标准输入输出的头文件包含
20. getch(), 表示暂停程序运行,可直接查看结果,否则运行完后不显示结果(需按
ALT+F5)。
21. printf("xxxxxxxxxxxxxxx"); 或 printf("格式控制符", 变量列表) ;变量列表不加&
22. scanf("格式控制符", 地址列表), 地址列表可为数组名、指针变量名及普通变量名(普
通变量名前要加加&)。
23. printf("%m.nf", 32.6789)
24. scanf 的格式控制符中, 除了逗号, 一般不加其他字符;一定要记住, 有逗号时输入要加逗
号, 否则:数据用空格隔开,字符连着输入; 没有"%m.nf"的写法, 只有"%mf"的写
法,
float 型用"%f", double型用"%lf", long double用"%Lf"
25. 不同类型的数值型数据进行混合运算
不同类型的数值型数据进行混合运算时,
先要把低数据类型向高数据类型转换, 成为同一类型后才进行运算。
横向箭头表示必须进行的转换。
逗号运算符是最低的运算符
常量不能++、--;
例:b=(a=1,a++,a++),
又例:b=(a=2)+(a=3),
又例:a=1;b=(++a)+(++a)
=与==的区别(赋值和等号)
26. 在C 语言中,对于逻辑运算,非零的数(不管实数还是整数)都认为是真的,真的就是
1,假的就是0;
27. 关系运算的结果是逻辑值(真为1假为0)。
28. 运算符:
运算符的优先序(p246):成单算移关于,异或逻条赋逗。
运算符的结合性(p246):条件、单目、赋值运算符。(printf 输出也是自右而左运算)
例如. 以下程序的运行结果是
struct st
{ int n; float x;
}*p;
void main()
{ struct st arr[3]={{10,5.6},{12,7.1},{14,6.7}};
p=arr;
printf(“%d \n”,++p->n);
p++;
printf(“%d,%.2f \n”,p->n,p->x);
}
A) 12 B) 11 C) 11 D)12
12,7.10 10,5.60 12,7.10 14,6.70
第三、四章 选择和循环结构
1.
2.
3.
4. C 程序一般采用自顶向下的编写格式, 模块化(函数) C 程序结构有三种: 顺序, 选择(分支), 循环 { }: 用在函数, 或复合语句 分支结构(或选择结构)[if结构和switch 结构]
①. if 分支结构
单分支: if(表达式) 语句; 或if(表达式) {语句组}
双分支: if(表达式) 语句1;
else 语句2;
多分支if : if(表达式1) 语句1;
else if(表达式2) 语句2;
...
else if(表达式n-1) 语句n-1;
else 语句n;
②. 多分支switch:
switch(x)
{ case x1: 语句1;[break;]
...
case xn: 语句n; [break;]
default: 语句; [break;]
}
例:main()
{ int c;
while((c=getchar())!= '\n')
{ switch(c-'2')
{ case 0 :
case 1 : putchar(c+4);
case 2 : putchar(c+4); break;
case 3 : putchar(c+3);
default: putchar(c+2); break;
}
}
printf("\n");
}
当输入:247,程序的输出结果是( )。
(A) 689 (B) 6689 (C) 66778 (D) 66887
switch 总结:
● 其语义是:先计算出表达式的值,用此值与哪个case 后的常量表达式的值相
一致,则执行那个case 后的语句组,如果语句组后有break 语句则直接退出switch
结构,如语句组执行后没有break 语句则继续执行后续case 后的语句组,直到遇到
break 语句退出switch 结构,如没有break 语句则会执行后续所有case 或default
后的语句组再退出switch 结构。
● 若计算出表达式的值与case 后的所有常量表达式的值都不同则只执行
default 及之后的语句组一直执行到最后(若遇break 则终止退出switch 结构),如
没有default 语句则直接退出switch 结构。
5. 循环语句:
(1) for(表达式1; 表达式2; 表达式3) 或 for(表达式1; 表达式2; 表达式3)
{ 循环体语句组; 循环体语句;
...
[break;] /*用于结束当层循环,跳到当层循环后面的语句。*/
...
[continue;] /*用于结束当次循环,跳过当次循环后面的语句,进入下次循环。*/
...
}
(2) while(表达式) while(表达式)
{ 循环体语句组; 循环体语句;
...
[break;]
...
[continue;]
...
}
(3) do
{ 循环体语句组;
...
[break;]
...
[continue;]
...
}while(表达式);
例:
for (i=1; i
{ {
if ( i%2==0 ) break; if ( i%2==0 ) continue;
printf(“%d”, i); printf(“%d”, i);
} }
6. 循环嵌套: 从外循环进来,内循环结束后,再到外循环,如此反复,直到外循环结束) x=0; 或 x=0;
for(i=1; i
for(j=1; j
x+=i*j; while(j
{ x+=i*j; j++;
} } 7.
8. break 可用于switch 和循环语句, 一个break 只退出一层; 而continue 只对循环有效 记住:质数的判断,斐波那契数列, 辗转相除法,求数列的和(有正符号如何处理?置
标志位)
• for 循环与 while 循环类似,属于先判断后执行; do while,属于先执行后判断
• for 语句中有三个表达式:表达式1通常用来给循环变量赋初值;表达式2通常是循
环条件;表达式3用来更新循环变量的值
• for 语句中的各个表达式都可以省略,但要注意分号分隔符不能省略
• 如果省略表达式2和表达式3需要在循环体内设法结束循环,否则会导致死循环 • break 语句用在循环中时,可以直接终止当前循环,将控制转向循环后面的语句 • continue 语句的作用是跳过循环体中剩余的语句而执行下一次循环
• 嵌套循环时,必须将被嵌套的循环语句完整地包含在外层循环的循环体内
第五章 函数
1. 系统函数:数学类函数(math.h ),输入输出函数(stdio.h ),字符串类函数(string.h )
2. 自定义函数:格式
类型名 函数名(形式参数列表)
{
函数体
}
3. 不写函数类型名默认为整型
4. 如果函数类型名为void 表示无返回值函数(不写return )
5.
(或字符型) ,则在调用
函数名(形式参数函数中或调用函数之前应该先声明列表) ;
6. 函数的递归:直接或者间接调用自身。(如阶乘)
7. 全局变量:在函数外定义的变量,如果定义时没给值,默认为0
8. 局部变量:在函数内定义的变量、形式参数、复合语句中定义的变量,如果没给具体
的值,该值不确定
9. 对于全局变量和局部变量主要观察在函数中是否被重新定义,若全局变量和局部变量
同名,则自动屏蔽掉全局变量。
10. 函数调用时,实参向形参传递:
(1) 按值传递:形参的变化不会改变实参的变化。
(若有返回值将值带回,否则带回控制流,函数的返回值类型与函数类型一致);
(2) 按地址传递:形参的变化就会有可能改变实参的变化。
(3) 数组传递,通常就把数组名及数组元素传过去
11. 如果一个函数名为:fun(x),严禁出现:fun(x)=…, 不管递归与否(满足标识符命
名)
12.
13. return y; 或return (y ); 不要写成 return y1, y2; 静态变量: static int x; (1) 没给值,默认为0; (2) 始终占用内存,其值会保
留下来(即赋值一次,不再重新赋值,保留上次运行结果)
[静态变量]举例
eg :以下程序的运行结果是( C )。
fun3(int x) main()
{ static int a=3; { int k=2,m=1,n;
a+=x; n=fun3(k);
return a; n=fun3(m);
} printf("%d\n",n);
}
A 、3 B 、4 C 、6 D 、9
14. 宏定义:#define 标识符 字符串,宏一定要先替换后计算
分带参和无参宏定义 无参宏定义 如#define P x*x //表示碰到P 时用x*x替换
带参宏定义 如#define P (x ) x*x //表示碰到P (x )时用x*x替换
[无参宏定义]举例
若有定义:#define N 3+2,则表达式N*2的值为( B )。
A 、5 B 、 7 C 、10 D 、0
解释:N*2=3+2*2=3+4=7。
[带参宏定义]举例
以下程序运行后输出结果是( B ) 。
#define MIN(m,n) m
解释:c=2*MIN(a,b)=2* a
第六章 数组
1. 一维数组的定义格式为:类型说明符 数组名[常量表达式];例如: int a[10]; 常量表达式可以是整型常量或字符常量或枚举值或符号常量表达式(注意不能包含变量). 例如,下面这样定义数组是不行的:
•
① int n; scanf(“%d″,&n); int a[n ];
② int k,M=5, a[k],b[M]; /* 不能用变量说明数组大小*/
③ float a[0]; /* 数组大小为0没有意义 */
④ int b(2); /* 不能使用圆括号 */
2. 数组元素下标可以是整型常量、变量、变量或整型表达式。
3. C 语言规定,下标的最小值是0,最大值则是数组大小减1 。
eg :m[8]中,表示数组m 有8个元素,下标从0开始一直到7。这8个数组元素分别是:m[0]、 m[1]、 m[2]、 m[3]、 m[4]、 m[5]、 m[6]、 m[7],注意没有m[8]。
4. 对一维数组的初始化赋值
(1)可以只给部分元素赋初值。没有赋值的元素:对于数值型数组,自动赋初值为0;对字符型数组,自动赋初值为空字符。
(2)只能给元素逐个赋值,不能给数组整体赋值。int m[5]={2,2,2,2,2};
不能写成: int m[5]=2;
(3)如果给全部元素赋值,则在数组说明中,可以不给出数组元素的个数,其长度等于初值表中数组元素的个数。 int m[]={1,2,3,4,5};
5. 二维数组元素的引用 形式: 数组名[下标1][下标2];
6. 二维数组元素的初始化
(1) 分行初始化:存储类型符 数据类型 数组变量名[行常量表达式][列常量表达式] =
{{第0行初值表},{第1行初值表},……,{最后1行初值表}};
Eg :若有定义:int s[3][4]={{1,2},{0},{3,4,5}};则s[2][1]的值为( B )。
A. 3 B. 4 C. 0 D. 1
(2) 省略一维大小:存储类型符 数据类型 数组变量名[行常量表达式][列常量表达式]
={ 初值表 };
Eg :int a[][4]={1,2,3,4,5,6,7,8,9,10,11,12}; printf("%d\n",a[1][2]);
A. 2 B. 3
C. 6 D. 7 11
7. 字符数组的定义格式:char 数组名[常量表达式];
8. 在c 语言中,没有专门的字符串变量,通常是用一个字符数组来存放一个字符串,由于
字符串总是以‘\0’作为串的结束标志,因此当把一个字符串存入一个数组时,也把结束符‘\0’存入数组,并以此作为该字符串结束的标志
9. C 语言允许用字符串的方式对数组做初始化赋值。有两种方式:
(1)按单个字符的方式赋初值,其中必须有一个字符是字符串的结束标记(但字符数组可以不包括’\0’) 。 如char s[]={‘1’, ’2’, ’3’, ’\0’};
10. (2) 直接在初值表中写一个字符串常量。如char s[]={“123”};{}可以省略
char s[]={‘1’, ’2’, ’3’, ’\0’}; char s[]={“123”}; char s[]=“123”;
11. 设已定义char s[ ]="\"Name\\Address\023\n";,则字符串所占的字节数是( B )。
A.19 B. 16
12. 字符串的常用串函数
① strlen 函数——测试字符串长度
• 格式: strlen (字符数组);
• 功能:测试指定字符串的实际长度(不含字符串结束标志‘\0’),并返回字符串的长度 其中,函数的参数可以是字符型数组名或字符串常数,函数的返回值是字符串的长度。 strlen 得到的是有效字符的个数(不包括‘\0’)
sizeof 得到的是整个数组的长度(包括‘\0’)
②. strcat 函数——字符串连接函数
格式: strcat(字符数组1,字符数组 2) ;
功能:把字符数组2中的字符串连接到字符数组1中字符串的后面,同时删去字符串1
的串标志‘\0’,组成新的字符串。该函数返回值是字符数组1的首地址
③. s trcmp 函数——字符串比较函数
格式:strcmp(字符串1,字符串2) ;
功能:字符串1和字符串2可以是字符型数组名或字符串常量。按照ASCII 码顺序比
较两个数组中的字符串,并由函数返回值返回比较结果
④. strcpy 函数——字符串拷贝函数
格式: strcpy(字符数组1,字符数组2) ;
功能:把字符数组2中的字符串拷贝到字符数组1中。字符串结束标志‘\0’也一同
拷贝。字符数组2也可以是一个字符串常量,这时相当于把一个字符串赋予一
12 C. 18 D. 14
个字符数组
注意:
字符数组1必须定义的足够大,以便能容纳被复制的字符串,字符数组1的长度不应该小于字符串2的长度;
字符数组1必须写成数组名形式,字符数组2可以是字符数组名,也可以是一个字符串常量;
有时只需要复制字符数组2中前面若干个字符,这些用strcpy 函数也能实现。
如:strcpy (m1,m2,3)表示将m2前面3个字符复制到m1中,从而取代m1中最前面的3个字符。
13. 冒泡排序、直接排序、交换排序
14. 杨辉三角、矩阵转置(矩阵转置只要循环一半就可以)。
15. 一维数组倒序存放、矩阵转置只要循环一半就可以
13
第七章
⏹ 本章主要内容: 指针
指针的概念、定义和引用、指针与函数、指针与数组、指针与字符串、指针数据类型小结
1. 指针变量的本质是用来放地址,而一般的变量是放数值的。
int *p 中 *p和p 的差别:
*p可以当做变量来用;*的作用是取后面地址p 指向的数值,p 是当作地址来使用。 *p++ 和 (*p)++的之间的差别:改错题目中很重要
*p++是 地址会变化;(*p)++ 是数值会要变化。
2. 指针变量的定义:一般形式为:类型符 *指针变量名; 如:int *p;
3. 指针变量的引用。两种基本的指针运算:
☐
☐ &:取变量的地址 * :指针运算符(或称“间接访问”运算符)
4. 指针变量作函数参数
[例7. 3] 用函数实现两个变量的交换
v o i d s w a p (i n t *p 1, i n t *p 2)
{ i n t *t ;
t =*p 1; *p 1=*p 2; *p 2=t ;
}
m a i n ()
{ i n t a =5, b =9;
s w a p (&a , &b ) ;
p r i n t f (“a =%d , b =%d \n ”, a , b ) ;
}
5. 指针函数(函数的返回值为指针)
一般定义为:类型符 *函数名(参数表) {……}
把两个数中的最大值设为0
i n t *m a x (i n t *q 1, i n t *q 2)
{ r e t u r n *q 1 > *q 2 ? q 1 : q 2; }
m a i n ()
{ i n t x =5, y =9, *p ;
p =m a x (&x , &y ) ;
*p =0;
p r i n t f (" x =%d , y =%d \n " , x , y ) ;
}
6. 函数指针(用一个指针变量存储一个函数入口地址,即指向函数,这样的指针称函数指针) ①. 定义形式为:类型符 (*函数指针变量) () ; 如:i n t (*p ) () ;
14
②. 使函数指针指向一个函数,一般的格式为:函数指针变量=函数名;如:p =m a x ; ③. 调用函数。一般格式为: (*函数指针) (实参表) 如:c =(*p ) (a , b ) ;
[ 例7. 5] 通过函数指针调用函数
i n t m a x (i n t x , i n t y ) {r e t u r n x >y ? x :y ; }
i n t m i n (i n t x , i n t y ) {r e t u r n x
m a i n ()
{ i n t a =5, b =9, c , d ;
i n t (*p ) () ; //定义函数指针
p =m a x ; //指向函数
c =(*p ) (a , b ) ; //调用函数
p =m i n ; d =(*p ) (a , b ) ;
p r i n t f (“M a x =%d , M i n =%d \n ”, c , d ) ;
}
7. 指针与数组的关系
一个变量有地址,一个数组包含若干个数组元素,每个数组元素都在内存中占用存储单元,它们都有相应的地址,这个地址就可以用指针来实现存储。
如有:i n t a [5], *p , *q ;
p =&a [0]; q =&a [2];
*p =5; *q =8; 则a [0]和a [2]值分别为5和8。
8. C 语言规定:数组名代表数组的首地址,也就是第一个元素a [0]的地址。
因此: a ⇔ &a [0]。
若: p =a ; /* 或写成p =&a [0]; */
则: p +1 ⇔ &a [1] *(p +1) ⇔ a [1] p +i ⇔ &a [i ] *(p +i ) ⇔ a [i ]
9. 引用一个数组元素,可以用指针法。
☐ 通过数组的起始地址计算数组元素的地址 ,即*(a +i ) 或*(p +i ) 形式。
☐ ,即p ++ 形式:
m a i n ()
{ i n t a [5]={3, 8, 9, 2, 6}, i , *p ;
p =a ;
f o r (i =0; i
{ p r i n t f (“%d “, *p ) ; p ++; }
}
【例7. 5 】指针运算符“*”与增1运算符“++”同时作用于一个指针变量的情况。 m a i n ()
15
{
i n t i , a []={ 11, 22, 33, 44, 55, 66 }, *p =a ;
p r i n t f (" %3d , " , (*p ) ++) ; 11
p r i n t f (" %3d , " , *p ++) ; 12
p r i n t f (" %3d , " , *++p ) ; 33
p r i n t f (" %3d \n " , ++*p ) ; 34
f o r (p =a ; p
p r i n t f (" %3d , " , *p ) ; 12 22 34 44 55 66
p r i n t f (" \n " ) ;
g e t c h () ;
}
2、通过指针引用二维数组元素
(1) 二维数组和数组元素的地址
i n t a [3][4]={{ 1, 2, 3, 4 }, {6, 7, 8, 9}, {11, 12, 13, 14} }
a [0] a [1] a [2]
则 a &a [0], a +1 &a [1], a +2 &a [2]
对于一维数组名为a [0], 则
a [0] &a [0][0], a [0]+1 &a [0][1].
所以第0行第1列的地址表示为a [0]+1.
所以a [i ]+j 是第i 行第j 列元素的地址 &a [i ][j ],
又a [i ] 等价于 *(a +i )
所以在二维数组里*(a +i ) +j 和a [i ]+j 都表示地址。
(2) 通过地址访问二维数组
假设有如下定义: i n t a [3][5], i , j ;
则二维数组a 中的任一元素a [i ][j ],可以用下述表达式之一来引用表示:
①. *(a [i ]+j ) 由上述知a [i ]+j 是第i 行第j 列元素的地址,因此*(a [i ]+j ) 与a [i ][j ]等价
②. *(*(a +i ) +j ) , *(a +i ) +j 也是第i 行第j 列元素的地址,因此*(*(a +i ) +j ) 与a [i ][j ]等价 ③. (*(a +i ) ) [j ],相当于先取*(a +i ) +j 地址,再取其内的值,所以与a [i ][j ]等价
④. *(&a [0][0]+5*i +j ) 由于每行5个元素,&a [0][0]+5*i +j 就是第i 行第j 列元素的地址,
因此*(&a [0][0]+5*i +j ) 也与a [i ][j ]等价
*(&a [0][0]+5*i +j ) *(a [0]+5*i +j ) *(*a +5*i +j ) a [i ][j ]
16
(3) 通过指向元素指针访问二维数组
如: i n t a [3][5], i , j , *p ; p =&a [0][0]; 或 p =*a ; 或 p =a [0];
则 a [i ][j ] 等价于 *(p +i *5+j ) 等价于 p [i *5+j ]
10. 数组名作函数参数的指针解释
对形参数组改为指针。
i n t a r r a y _m a x (i n t x [ ], i n t n )
{
}
m a i n ()
{ i n t a [ ]={8, 7, 55, 23, 49}, m a x ;
}
11. 指针数组
一般说明形式为:类型符 *数组名[数组大小]; 如:i n t *p [5];
指针数组的简单使用
m a i n ()
{ i n t a [5]={1, 3, 5, 7, 9};
i n t *n u m [5], i ;
f o r (i =0; i
n u m [i ]=&a [i ];
f o r (i =0; i
p r i n t f (“%d “, *n u m [i ]) ;
}
12. 多级指针
有:i n t a , *p =&a ; 若使:q =&p ; 则q 是就指向指针变量的指针变量,称q 为二级指针。 二级指针定义的一般形式为:类型符 **指针变量名; 如:i n t **q ;
则:a =5; 或*p =5; 或**q =5; 结果相同。
同样可以有三级、四级指针等等,我们把二级及二级以上的指针称为多级指针。
[例7. 9] 数组的输出
m a i n ()
17 i n t i , m = x [0] ; f o r (i =1; i
{ i n t a [5]={1, 3, 5, 7, 9};
i n t *b [5], i , **p ;
f o r (i =0; i
b [i ]=&a [i ];
p =b ;
f o r (i =0; i
p r i n t f (“%d “, **p ++) ;
}
13. 指针与字符串
字符串的表示形式 c h a r 字符数组名[数组元素个数]
如有: c h a r s t r [80]=“C h i n a ”, *p =s t r ;
p r i n t f (“%s ”, s t r ) ; p r i n t f (“%s ”, p ) ; p r i n t f (“%s ”, ”C h i n a ”) ; 用%s 输入/输出字符串时, 只需要知道字符串的开始地址即可。
使p 指向字符串的开始地址,可写成: c h a r *p =”C h i n a ”;
14. 字符指针作函数参数
[例7. 11] 将例7. 10改用函数完成
i n t S t r L e n (c h a r *s )
{ i n t n =0;
w h i l e (*s ++) n ++;
r e t u r n n ;
}
m a i n ( )
{
}
运行结果:a b c 的长度为3
15. 返回字符串的函数
[例7. 13] 改写字符串复制函数
c h a r *S t r C o p y (c h a r *s t r 1, c h a r *s t r 2)
18 c h a r s t r [ ]=”a b c ”, *p ; i n t l e n ; p =s t r ; l e n =S t r L e n (p ) ; p r i n t f (“%s 的长度为%d \n ”, p , l e n ) ;
{ c h a r *p =s t r 1;
w h i l e ((*s t r 1=*s t r 2) ! =’\0’)
{ s t r 1++; s t r 2++; }
r e t u r n p ;
}
m a i n ()
{ c h a r s 1[80], s 2[ ]= “a b c ”;
p r i n t f (“复制之后的字符串:%s \n ”, S t r C o p y (s 1, s 2) ) ;
}
复制之后的字符串:a b c
16. 字符指针数组
[例7. 14]将若干字符串输出
m a i n ()
{
}
[例7. 15]使用多级指针完成若干字符串输出
m a i n ()
{
}
输出:W o r d
E x c e l c h a r *s t r [ ]={“W o r d ”, ”E x c e l ”, ”O u t l o o k ”}; c h a r **p ; f o r (p =s t r ; p
O u t l o o k
17. 字符指针与字符数组的讨论
占用的内存空间不同 19
c h a r s t r [80]; c h a r *p ;
⏹ 初始化的概念不同
⏹ c h a r s t r [80]=“a b c ”; c h a r *p =“a b c ”; 数组名是常量,字符指针是变量
s t r =s t r +2; /* E r r o r */
p =s t r +2; /* O k */
c h a r s t r [80], *p ; s c a n f (“%s ”, s t r ) ; /* O k */ s c a n f (“%s ”, p ) ; /* e r r o r */ ⏹ 字符数组有一块确定的、连续的内存单元;而指针只有一个字的内存单元。所以:
18. 指针数据类型小结
⏹ 各种指针定义小结
i n t x ; 整型变量x
i n t *p ; 整型指针p
i n t a [n ]; a 是一个整型数组,有n 个元素
i n t *p [n ]; p 是一个整型指针数组,有n 个元素
i n t f () ; f 是一个函数,返回一个整型值
i n t *p () ; p 是一个函数,返回一个整型变量的地址
i n t (*p ) () ; p 为一个指针,它可以指向一个整型函数
i n t **p ; p 为一个二级指针,它存储另一个指针的地址
⏹ 指针运算小结
1、指针变量加、减一个整数, 指的是移到向上或向下一个单位的地址 例如:p ++、p --、p +i 、p -i 、p +=i 、p -=i 等。
2、指针变量赋值
如有:i n t a , *p 1, *p 2, a r r a y [10], m a x () , (*p 3) () ; 则:
p 1=&a ; /* 取变量a 的地址,使p 1指向a */ /* p 2指向a r r a y 数组的起始地址 */ p 2=a r r a y ; p 1=&a r r a y [4]; /* p 1指向a r r a y [4]元素 */ p 3=m a x ; p 2=p 1; /* p 3指向m a x 函数 */ /* p 2的指向与p 1的指向相同 */ 20
p 1=2000; a =p 2;
/* e r r o r ,类型不同 */
/* e r r o r ,类型不同 */
19. 三名主义:(考试的重点)
数组名:表示第一个元素的地址。数组名不可以自加自减,它是地址常量名。 函数名:表示该函数的入口地址。 字符串常量名:表示第一个字符的地址。 20. 一维数组的重要概念:
对a[10]这个数组的讨论。
1、a 表示数组名,是第一个元素的地址,也就是元素a[0]的地址。
2、a 是地址常量,所以只要出现a++,或者是a=a+2赋值的都是错误的。 3、a 是一维数组名,所以它是列指针,也就是说a+1是跳一列。 对 a[3][3]的讨论。
1、a 表示数组名,是第一个元素的地址,也就是元素a[0][0]的地址。 2、a 是地址常量,所以只要出现a++,或者是a=a+2赋值的都是错误的。 3、a 是二维数组名,所以它是行指针,也就是说a+1是跳一行。
4、a[0]、a[1]、a[2]也都是地址常量,不可以对它进行赋值操作,同时它们都是列指针 a[0]+1,a[1]+1,a[2]+1都是跳一列。
5、注意a 和a[0] 、a[1]、a[2]是不同的,它们的基类型是不同的。前者是一行元素,后三者是一列元素。 21. 二维数组做题目的技巧:
如果有a[3] [3]={1,2,3,4,5,6,7,8,9}这样的题目。
步骤一:把他们写成: 第一列 第二列 第三列 a[0] 1 2 3 ->第一行 a[1] 4 5 6 —>第二行 a[2] 7 8 9 ->第三行 步骤二:这样作题目间很简单:
*(a[0]+1)我们就知道是第一行的第一个元素往后面跳一列,那么这里就是a[0][1]元素,所以是1。 *(a[1]+2)我们就知道是第二行的第一个元素往后面跳二列。那么这里就是 a[1][2]元素,所以是6。
一定记住:只要是二维数组的题目,一定是写成如上的格式,再去做题目,这样会比较简单。
数组的初始化,一维和二维的,一维可以不写,二维第二个一定要写
int a[]={1,2} 合法。int a[][4]={2,3,4}合法 。但int a[4][]={2,3,4}非法。 16. 二维数组中的行指针
int a[1][2];
其中a 现在就是一个行指针,a+1跳一行数组元素。 搭配(*)p[2]指针
a[0],a[1]现在就是一个列指针。a[0]+1 跳一个数组元素。搭配*p[2]指针数组使用
还有记住脱衣服法则:
a[2] 变成 *(a+2) a[2][3]变成 *(a+2)[3]再可以变成 *(*(a+2)+3) 这个思想很重要!
17. 不能对字符数组整体赋值,而字符指针允许整体赋值
18. 指针p 可以p++(后移)或p--(前移)或p+i,而数组名a 只能用,a+i(注意一维
数组和二维数组的区别)
19. 两个地址(指针)可以比较大小,后面大前面小;可以相减表示差几个元素 20. 对字符数组或字符串的操作一般用:
while(*s) 或while(s[i]) 或for(p=a; p
{ …; s++} {…; i++} 注意:新生成的字符串是否有结束符’\0’ 10.字符串打印: char s1[10], s2[6][10], *s3;
(1) (2)
一维数组:printf(“%s”, ……) ; 二维数组:printf(“%s”, ……) ;
第八章 结构体、共用体和枚举
1. 2.
记住数组也属于自定义类型 结构类型 struct [staff] {
char no[5];
char name[10]; char sex; struct { int year;
int month; int day;} birthday; float wages[2];
}worker, workers[100], *p=&worker, *q=workers;
[struct staff a,b;] //若 定 义 的 结 构 体 无 结 构 体 名 则 只 能 直 接 定 义结 构 体 变 量,不 能 间 接 定 义 。
3.
※ 通过指针访问结构体变量的成员 ① 结构变量名. 成员名(名字引用); ② 结构指针->成员名(指针引用);
③ (*结构指针). 成员名(将指针转化为名字引用); 4.
『结构变量占用内存情况』结构变量的各个成员分量在内存中占用连续存储区域,所占内存大小为结构中每个成员的占用内存的长度之和。
5.
联合类型(union )
(1) (2) (3) (4) (5) (6)
6.
表示法同结构类型 首地址起共用 允许对第一个成员赋值
共用体变量任何时刻-只有一个成员存在
共用体变量定义分配内存, 长度=最长成员所占字节数(即字节数取最大的) 共用体变量的定义形式有三种(类似结构体变量的定义)
枚举类型
enum weekdays {Sun,Mon,Tue,Wed,Thu,Fri,Sat}; (1) (2)
枚举型仅适应于取值有限的数据。
取值表中的值称为枚举元素,枚举元素是常量。在C编译器中,按定义的顺序取值0、1、2、... 。所以枚举元素可以进行比较,比较规则是:序号大者为大。例如,上例中的Sun=0、Mon=1、……、Sat=6,所以Mon>Sun、Sat 最大。
(3)
枚举元素的值也是可以人为改变的:定义时由程序指定。例如,如果enum weekdays {Sun=7, Mon=1 ,Tue, Wed, Thu, Fri, Sat}; 则Sun=7,Mon=1,从Tue=2开始,依次增1。
7. 定义别名
int X, Y[10], *Z;
X a; Y b; Z c;
其中a ,b ,c 各代表什么?
整型变量a, 整型数组b[10], 整型指针变量c 。
第九章 文件操作与位运算
1. 6个位运算符 : 位左移>、按位取反~、位与&、位或 |、位异或 ^。 2. 位运算题目计算是先要把十进制化成二进制,再做位运算。
在没有舍去数据的时候,>右移一位表示除以2。 3. 所谓“文件”一般指存储在外部介质上数据的集合。
按文件中数据的组织形式来分,可分为文本文件(即ASCII 码文件)和二进制文件。 4. 文件操作的过程:对磁盘文件的操作必须“先打开,后读写,最后关闭”。 5. 文件的打开方式
6. 常用文件操作函数
7. 文件输入输出小结
分类 函数名 功能 打开文件 fopen() 打开文件 关闭文件 fclose() 关闭文件
文件定位 fseek() 改变文件位置指针的位置 rewind() 使文件位置指针重新至于文件开头 ftell() 返回文件位置指针的当前值 文件状态 feof() 若到文件末尾,函数值为真 ferror() 若对文件操作出错,函数值为真 文件读写 clearerr() fgetc() fputc() fgets() fputs() getw()
putw() fread() fwrite() fscanf() fprintf()
使ferror 和feof()函数值置零 getc()从指定文件取得一个字符 putc()把字符输出到指定文件 从指定文件读取字符串 把字符串输出到指定文件 从指定文件读取一个字(int 型) 把一个字输出到指定文件 从指定文件中读取数据项 把数据项写到指定文件中 从指定文件按格式输入数据 按指定格式将数据写到指定文件中