注: 笔者按照自己学校的考试内容对C语言程序设计教程(第5版)的复习总结
部分章节内容与书本不完全一致(根据笔者自身水平与想法进行删改),内容有所欠缺
笔者分享出来目的仅在记录学习过程,可供有需要的人快速复习阅览
由于笔者是将markdown笔记直接粘贴过来的,故观感可能有所欠缺,请见谅
若有好的批评建议,欢迎指正
第一章:引言
·C语言的前身演变:ALGOL60 => CPL => BCPL => B语言(第一个UNIX系统) => C语言(第一个标准:ANSI C)
·C语言类型:面向过程的语言
·c语言程序的基本单位是函数
·源程序中main函数可以在任意位置
·复合语句是由一对花括号 {} 包围的语句序列
·关键字:
数据类型:char int float double void short long signed unsigned
自定义数据类型:struct union(声明结构体数据类型) enum(声明枚举数据类型)
控制类型:if else switch case default for while do...while continue break goto(转移到指定语句处) return
存储类型:auto(声明自动变量) extern(声明外部变量) register(声明寄存器变量) static
其他类型:const(声明只读变量) sizeof(计算类型长度) typedef(给自定义数据类型取别名) volatile(变量在程序执行中可隐含的被改变)
·程序结构:(注意:一个最简单的C语言程序可以只包含文件包含部分和主函数部分)
1.文件包含部分
2.预处理部分
3.变量说明部分
4.函数原型声明部分
5.主函数部分
6.函数定义部分
·C语言程序生成过程:(注意:一旦生成无需修改的可执行程序,即可反复被加载执行,无需重新编译链接)
1.编辑 通过程序语言编写程序--源程序 file.c
2.编译 将源程序翻译成机器语言的过程 file.obj
3.链接 得到可执行程序(存储在磁盘存储器上的文件) Link /out:mytest.exe file.obj
4.加载
第二章:基本的程序语句
·定点数与浮点数:
定点数:小数点位置固定的数(整数型和纯小数通常是用定点数来表示)
浮点数:小数点位置不固定可浮动(同时有整数和小数部分的数一般用浮点数表示)
·基本数据类型:(1字节等于8位(bit))(以DEV C++ VS编译器举例)(ANSI C++标准)
char 1字节 sizeof(char)=1 0~255
short int 2字节 sizeof(short int)=2 -32768~32767(65535)
int 4字节 sizeof(int)=4 略
long int 4字节 sizeof(long int)=4
float 4字节 sizeof(float)=4
double 8字节 sizeof(double)=8
·标识符(各种对象的命名名称)
标识符的第1个字符必须是字母或下划线,随后可以是字母数字下划线。
·常量表示
%o 八进制
%d 十进制
%x 十六进制 0XFF--255 0X1A--26
·部分字符所对应的ASCⅡ的值
0--48 1--49 A--65 B--66 a--97 b--98
·字符串常量:
字符串常量在内存中存储时,系统会自动在字符串末尾加一个\0(结束标志)
用“”包裹
·字符型常量:
用‘’包裹
·转义字符:
\n换到新的一行 \r回车符 \?问号字符 \\反斜杠 \"双引号
·符号常量:(预处理 宏定义f)
#define <常量符号名> <常量>
·算术运算符:
高优先级:++ —— a++与++a(后者立即加1改变原数a 即a=2)
中优先级:* / % (%不能进行浮点运算且要求两边数据类型一致)
低优先级:+ -
如:#include <stdio.h>
void main() {
int a=16, a1, a2, a3;
a1=a++;
a2=a++;
a3=a++;
printf("a1=%d,a2=%d,a3=%d",a1,a2,a3);
a1=++a;
a2=++a;
a3=++a;
printf("a1=%d,a2=%d,a3=%d",a1,a2,a3);
}
运行结果:
a1=16,a2=17,a3=18
a1=20,a2=21,a3=22
·关系运算符:
高优先级: >= <= < >
低优先级: == !=
·逻辑运算符:
高优先级:!
中优先级:&&
低优先级:||
·位运算符:
高优先级: ~(接位取反)
中优先级:<<(位左移) >>(位右移)
低优先级:&(位与) ^(位异或)(AB不同输出1) |(位或)
-----------------------------------
A B A|B A^B A&B ~A ~B
-----------------------------------
1 1 1 0 1 0 0
-----------------------------------
1 0 1 1 0 0 1
-----------------------------------
0 0 0 0 0 1 1
-----------------------------------
0 1 1 1 0 1 0
-----------------------------------
·条件运算符(三目运算)
表达式1?表达式2:表达式3
·数据类型转换:
1.当一个表达式中混有不同类型的常量和变量,编译器会将较短的数据类型的值转换成较长数据类型的值
2.强制转换 int a = 15; float t; t = (float) a/30; t = 0;
·格式化输出函数: printf() %[<修饰符>]<格式字符>
%e 按科学计数法输出
%o 按八进制输出
%x 按十六进制输出
%c 按字符型输出
%s 按字符串输出
%d 按十进制输出
%f 按浮点型小数输出
%u 按无符号整数输出
%m.nf 以宽度m输出实型小数,小数位为n位
%md 以宽度m输出整型数,数据宽度不足m时,左补空格
%0md 以宽度m输出整型数,数据宽度不足m时,左补0
(可以在%后加上一个负号“-” 使得数据输出方式改为左对齐)
如:i=123,a=12.34567;
printf("%4d%10.4f",i,a); 输出:_123___12.34567
printf("%-4d%-10.4f",i,a); 123_12.34567___
printf("%-05d",--i); 122
·格式化输入函数:scanf("控制字符串",输入项表)
scanf()函数的输入项列表中的变量地址,就是变量名前加上地址操作符&(注意:传递的是地址不是值)
在输入格式的修饰符中,*表示按规定格式输入但不赋予相应变量,作用是跳过相应的数据
如:int X=0,y=0,z=0
scanf(%d*%d%d,&x,&y,&z);
则x=11 y=33 z未赋值
第三四五章:算法设计
·结构化算法的结构:
1.顺序结构
2.分支结构 if else-if switch-case(if的真 = 非0数; 假 = 0)
3.循环结构 for do-while while
(注意区分分支结构与循环结构 其中continue与break只适用于循环结构)
(区别于switch中的break,其中的break是用来退出case而不是跳出循环)
(while和do-while的主要区别:do-while循环体至少执行一一次)
·break和continue的运用:
// 输出50~100中不被3整除的数
如:#include <stdio.h>
void main() {
int n=50;
for(;n<=100;n++) {
if(n%3 == 0)
continue;
else
printf("%d\t",n);
}
}
// 了解break的作用
如:#include <stdio.h>
void main() {
int x;
for(x=1;x<=10;x++) {
if(x==5)
break;
}
printf("break at x=%d",x);
}
第六章:函数 =>(简单算法)
//斐波那契数列: f(0)=0 f(1)=1 f(n)=f(n-1)+f(n-2)
int fibonacci(int n) {
if(n==2 || n == 1) {
return 1;
}
int result = fn(n-1)+f(n-2)
return result;
}
int fibonacci(int n) {
if (n == 0) {
return 0; // 特殊情况:第0个斐波那契数是0
} else if (n == 1) {
return 1; // 特殊情况:第1个斐波那契数是1
}
int a = 0, b = 1, temp;
for (int i = 2; i <= n; i++) { // 从第2个斐波那契数开始计算
temp = a + b; // 计算下一个斐波那契数
a = b; // 更新a为前一个斐波那契数
b = temp; // 更新b为当前斐波那契数
}
return b; // 返回第n个斐波那契数
}
-----------------------------------------------------------------------------
//计算n!
int factorial(int n) {
// 终止
if(n == 0 || n == 1)
return 1;
// 递
int res = factorial(n-1);
// 归
return n*res;
}
-----------------------------------------------------------------------------
//计算x(x-1)(x-2)...(x-n)
int recursive(int n,int x) {
if (n == 0)
return 1;
int res = recursive(n-1,x-1);
return x*res;
}
-----------------------------------------------------------------------------
// 冒泡排序函数
void bubbleSort(int arr[], int n) {
int i, j;
for (i = 0; i < n-1; i++) {
// 最后 i 个元素已经到位
for (j = 0; j < n-i-1; j++) { // 交换次数
if (arr[j] > arr[j+1]) {
swap(&arr[j], &arr[j+1]);
}
}
}
}
第七八章:数组 指针
注意:不能对指针进行算数运算 如p++
// 指针作为函数参数调用
void swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
//错误形式
void swap(int *a, int *b) {
int *temp;
*temp = a; //将a的值赋值给*temp指针
a = b; //将b的值赋值给a
b = *temp; //将*temp指针即a的值赋值给b
//实际上*a指针指向的还是1,*b指向2
}
int main() {
int x = 1, y = 2;
swap(&x, &y); // 传递变量的地址
printf("x: %d, y: %d\n", x, y); // 输出: x: 2, y: 1
return 0;
}
-----------------------------------------------------------------------------
// 一维数组与指针
a[5] = {1,10,3,4,5}
*a = 1 *a+1 = 2 *(a+1) = 10
// 二维数组与指针
#include <stdio.h>
int main () {
int arr[3][3] = {
{1,10,3},
{4,5,6},
{7,8,9},
};
int *p = arr[0];
printf("a[0][0]的地址是%d\n",arr); a[0][0]的地址是a6487536
printf("a[1][0]的地址是%d\n",arr + 1); a[1][0]的地址是a6487548
printf("a[0][1]的地址是%d\n",*arr + 1); a[0][1]的地址是a6487540
return 0;
}
// 由此可以推导得 第i行j列的地址为 *[*(a+i)+j]
-----------------------------------------------------------------------------
//注意:用指针声明二维数组时 形如int (*i)[5]而不是 int *i[5] 后者为整型指针数组
-----------------------------------------------------------------------------
//指向函数的指针
int max(int a, int b) {
return a>b?a:b;
}
void main() {
int (*p)(int,int);
p = max;
printf("The max of (3,4) is %d\n", (*p)(3,4))
}
第九章:构造数据类型
// 结构体
#include <stdio.h>
struct Student {
int num;
char name[20];
int score;
};
int main() {
struct Student stu[5] = {
{11, "aa", 78},
{11, "aa", 78},
{11, "aa", 78},
{11, "aa", 78},
{11, "aa", 78}
};
struct Student *p;
for(p = stu; p < 5; p++) {
printf("%d %s %d\n", p->num, p->name, p->score);
}
return 0;
}
例题
1.已知:int x=3,y=0,执行语句x=!x&&x<++y后,x,y的值正确的是( )
A. x=0,y=0; B. x=3,y=0; C.x=0,y=1; D.x=3,y=1;
2.已知x=1;则表达式“++x+x++”的值为( )
A. 2 B.3 C. 4 D.6
3.已知int j,i=1;执行语句“j=i++;”后,变量i的值是( )
A. 1 B. 2 C. –1 D. -2
4.若int i=10;执行下列程序后,变量i的正确结果是( )
switch ( i )
{case 0: i+=1;
case 10: i+=1;
case 11: i+=1;
default: i+=1; }
A. 10 B. 11 C. 12 D. 13
5.以下程序的运行结果是( )
typedef union
{long a[1];
int b[2];
char c[8];
} TEST;
TEST m;
main( )
{ printf(“%d\n”,sizeof(m)); }
A.32 B. 16 C. 8 D. 24
6. C语言中规定,简单变量做实参时,它和对应形参之间的数据传递方式是( )
A.地址传递 B.单向值传递
C.有实参传给形参,再由形参传回给实参 D.由用户指定传递方式
7. 有以下程序
#include <stdio.h>
int m[3][3]={{1},{2},{3}};
int n[3][3]={1,2 ,3};
main( )
{ printf(“%d,”, m[1][0]+n[0][0]);
printf(“%d\n”,m[0][1]+n[1][0]);}
运行结果为:_________
解答
1.主要考察的是对逻辑运算符&&的理解
根据逻辑运算的短路特性 当左侧操作数为假时不再计算右侧操作数 易得A
2.主要考察的是对自增运算符++的理解
首先计算前置自增(++x)此时x的值变为2
然后计算后置自增(x++)此时x的值是2,但在表达式中用的是自增前的值即2 得C
3.执行流程:
首先将i当前的值赋值给j,所以j的值为1
然后i的值增加1,i变为2 得B
4.主要考察对switch语句的理解
由于case后没有break,故程序会一直执行到default 得D
5.考察对union的理解
union联合体的大小取决于成员中占用空间最大的那个成员大小 故选C
6.B
7. 相当于int m[3][3]={{1,0,0},{2,0,0},{3,0,0}}; int n[3][3]={1,2 ,3,0,0,0,0,0,0};
3 0