C语言期末复习指南

C语言期末复习指南基础篇1.C的输入输出2.C的判断—->条件语句if语句:switch语句:3.C的循环语句while循环:for循环:do…while循环:4.C的作用域规则和函数作用域局部变量:全局变量:形式参数:函数:5.数组进阶篇1.指针什么是指针?指针和数组指针和函数2.结构体什么是结构体?简单使用结构体3.链表初始化链表,添加节点链表的基本操作遍历链表&查找节点删除指定的节点在指定位置插入节点:修改指定节点:细节总结:几种常见的排序算法:题目模式:1.读程序题:2.程序填空题:3.任务驱动编程题:就这。

 

C语言期末复习指南

按照软件学院的惯例,C语言期末考试是不直接考概念填空题和选择题的。

所以我们今天要讲的基本是贴近代码的情况:

基础篇

1.C的输入输出

程序从main函数开始执行之类的概念相信已经不必多说了,所以我们先看到输入输出的一些考察点:

举例,通常情况下最多用到的输入函数是scanf:

通常考察的也就是格式控制地址符&,保持前面的格式控制和要存储的变量类型一致就OK了,另外,除了指针以外,变量前都是要加地址符&的。这种情况在改错题可能会遇到,还有自己写代码的时候也不能犯错。

输出一般也就是用到printf:

主要也是考察一个格式控制的问题,如果是指针记得加*

2.C的判断—->条件语句

C语言内置的条件语句有两个:

if语句:

一般在读程序题里考察:

这里的输出是

9 6

首先要明确if的工作方式:

程序执行到if的位置之后,

首先判断A的真假:

如果有多个if嵌套,用这样的逻辑去一层一层推导,就不会出问题。

switch语句:

switch更像是一个特殊化的if,用于简化只需要判断某一个变量的值的情况,需要注意的是,正常情况下switch的每一个case都需要以break结束,否则无法跳出,而default段可以有效的防止错误的变量造成的无法跳出switch

如果没有写break语句,执行完当前case之后,将继续执行下一个case代码段直到遇到break

3.C的循环语句

C当中主要有三个基本的循环语句:

while循环:

condition是判断语句,和if里那个判断语句一样,为真(1/true)则继续,为假(0/false)则终止,大括号内的语句也就是每次循环要执行的内容。

举个例子:

要注意的点是,while结束的时候的a值是多少?

尽管程序打印的a是到19就没有了,但是最后循环结束的a值应该是20,也就是刚好使得判断条件为假的值。

分析循环类的代码执行,最好分析出每次循环的变量的情况,避免出错。

for循环:

for循环其实和while循环大差不差,也就是多了几个更直观的表示方式:

init是循环开始前(刚执行到for语句时)要执行的语句,比如赋初值之类;condition还是判断语句,和while循环里那个一样;increment就是每次循环固定要执行的语句,比如大家经常见到的i++,目的是增强可读性,作用和把这个语句直接放进大括号最后一行没有区别。

do…while循环:

do...while循环也是一个特殊版的while循环:

它的特点是不管条件如何,第一次执行到这段代码的时候一定会执行一次statement,因为它是先执行,再判断。也就是说,不管我们condition是否为真,statement都会至少执行一次。

例如:

可以看到,a是不满足while语句中的条件的,但a仍然会被打印一次。

4.C的作用域规则和函数

作用域

C语言的作用域,主要是对三个概念的理解:

局部变量:

在某个函数或块的内部声明的变量称为局部变量

需要记住,在我们看到int、char之类的变量声明语句时,就已经限定它的作用范围。在这里,所有的变量 abcmain()函数的局部变量,如果有其他的函数存在,是不能直接使用这里的a b c的。

全局变量:

如果觉得自己搞不清楚全局变量的,记住,放在函数外面的,也就是没有放在大括号里的就是全局变量,这个变量是大家都可以使用的。

*注意:如果在函数里有和全局变量同名的局部变量定义,在函数内以局部变量优先。

输出如下:

value of a = 10, b = 20 and g = 30 100

形式参数:

形式参数本身起一个传递的作用,它的名称只对使用它的函数有意义。形式参数控制传入的参数的类型和数目,它在函数内可以被认为是一个局部变量,它的值由传入的变量确定并与传入变量的名称无关。

value of a in main() = 10

value of a in sum() = 10

value of b in sum() = 20

value of c in main() = 30

函数:

理解了前面关于作用域的意义之后,函数的重点也就是学会声明和调用函数。

*声明需要在调用之前。

声明调用举例:

return的类型一定要和函数定义时一致,否则会出错。

5.数组

在C语言中,当我们需要用一个变量存储多个数据的时候,我们就需要用到数组

数组可以存储一个固定大小的相同类型元素的顺序集合。

数组的声明很容易:

C语言中数组的声明必须确定数组长度,并且长度在声明之后不能再改变,数组的内容可以用大括号{}来表示,各元素用逗号,隔开。

数组容易考察的点:

数组按照下标索引来访问内容,起始的元素为下标为0

a[i]

需要注意:下标i不能超过数组长度-1(因为是从0开始),否则将会出错。

尽管我们在定义数组的时候直接把长度10填进了中括号内,但它只代表长度,a[10]是不存在的。

而如果要将一维数组传递给函数,可以有三种形式参数:

二维数组的传入则相对复杂一点,这里不多讲解。

进阶篇

1.指针

什么是指针?

在C语言中,每一个变量都有一个内存区域,每一个内存区域都定义了可使用 & 运算符访问的地址,它表示了在内存中的一个地址。

指针是一个变量,其值为另一个变量的地址,即,内存位置的直接地址。就像其他变量或常量一样,我们必须在使用指针存储其他变量地址之前,对其进行声明。指针变量声明的一般形式为:

type *var-name;

因为指针存储的是地址,所以要访问指针变量指向的内容要用取值符*

其实平时我们经常见到指针:

scanf函数:

这里的&a就是一个地址,可以存储到一个指针变量里。

所以我们也可以这样写代码:

效果是一样的,只不过要访问输入的值要加个*

定义指针的时候,良好的习惯是对其进行初始化,对于指针来说,初始化的值应为NULL或者一个变量的地址:

那么,说了这么多,指针有啥用呢?

指针和数组

首先:

任何能由数组下标来实现的操作都能用指针来完成

一个通过数组和下标实现的表达式可以等价地通过指针及其偏移量来实现:

指针数组和数组指针:

指针数组是数组,数组的每个元素都是一个指针。

数组指针是指针,指向一个数组。

指针和函数

首先,记住指针是指向一个内存地址的,是物理实体。

C语言的所有参数均是以“传值调用”的方式进行传递的,这意味着函数将获得参数值的一份拷贝,如果是普通变量,则是传递一个复制出的值,如果是指针变量,则是传递指针变量存储的值,也就是一个内存地址。

我们来看看这两段代码:

我们直接定义整形变量a = 10,然后调用changevalue函数修改a的值,再在main中打印出a的值。

打印的结果为:

10

a的值并没有发生改变。

再看看这一段代码:

我们选用指针来操作,输出的结果:

100

为什么会有这样的差别呢?

因为当changevalue函数被调用时,修改的变量是a这个指针变量,也就是对指定的内存空间进行了修改,这样a指向的值就发生了改变,尽管它们不在同一个作用域内。

这里我们就可以体会到指针的一个优点:

指针参数使得被调函数能够访问和修改主调函数中对象的值。

而这一点常常成为考点,在读程序题中可能要求给出指针变量最后的值,考查我们对指针在各种作用域中发生的变化。

另外,这里给出指针传递数组的例子:

函数指针:指向的对象是函数的指针

例如:

这样可以简化函数的调用。我们也可以在函数参数中添加其他函数的函数指针,在不同的作用域内使用。

2.结构体

什么是结构体?

结构是 C 编程中另一种用户自定义的可用的数据类型,它允许我们存储不同类型的数据项。

比如我们想要描述一个物体的多个特征,比如一个叫Kevin的人:

简单使用结构体

我们在定义这样的一个结构体时,要遵循下面的规范:

实例:

这里的Person是大的类型,而KevinPerson这个类型里的一个变量

为了访问结构的成员,我们使用成员访问运算符.:

Kevin.id

Kevin.age

Kevin.nickname

使用举例:

当然,结构体也可以作为函数的参数传入,它支持常规的变量所支持的应用方式,这里就不展开细讲了。

3.链表

结构体一旦和指针联系起来,我们就不得不提到链表了。

链表是一种数据结构,它和数组的主要区别在于是否只能顺序访问。

*数组是顺序存储在内存中的数据结构,特点是访问快,结构简单,我们可以直接访问它位于某一位置的数据。

链表中的每个元素我们称为节点(node)

它具有如下特点:

是不是感觉有点困惑?没有关系,我们接着往下看。

我们可以看到,在这个节点中存在一个和这个节点的结构体类型相同的指针*next,它将指向下一个节点。

举个例子:

Node1.next
Node1
Node2

在正式创建链表之前,我们先认识一下这几个概念:

首节点主要是为了和头节点区分,头节点通常无意义,相当于数组a[10]中的变量名a起到的作用。

初始化链表,添加节点

其实单链表添加节点的逻辑很简单:

为空
不为空
创建一个节点并对节点数据赋值
判断链表是否为空
赋值给头节点的下一个节点
head->next = temp
赋值给尾节点的下一个节点
end->next = temp
保证尾节点始终指向最后一个节点
end = temp

通过反复的调用AddNewNode函数,我们就可以不断添加新的节点到链表中。

链表的基本操作

有了初始化好的链表之后,我们来看看与链表相关的基本操作

遍历链表&查找节点

回顾对数组的操作,我们大部分的操作都涉及到了遍历数组这个过程。

遍历链表很容易:

这里的temp= temp->next就相当于数组遍历时的i++,细微的差距是判断结束的条件temp != NULL

借助遍历查找节点也很容易:

删除指定的节点

如果要删除链表中的某个节点,是怎样的情形?

比如我们的节点连接是这样的:

Node1.next
Node2.next
Node1
Node2
Node3

如果我们要删除Node2,只需要将Node1.next指向Node3,然后把Node2.next指向NULL, 再将Node2释放掉就好了

 

New
Node1.next
Node2.next
Node1.next
Node2.next
Node3
Node1
NULL
free(Node2)
Node2
在指定位置插入节点:

了解了删除某个节点之后,我们还需要了解对应的插入节点操作

以这个图为例:

Node1.next
Node1
Node2

如果要插入一个Node_newNode1Node2之间,我们需要什么样的操作?

new
old
Node1.next
Node1.next
Node_new.next
Node_new
Node2
Node1

可以很容易看到我们需要干的事情:将Node_new.next指向Node2,再将Node1.next指向Node_new

修改指定节点:

增删查改,接下来要讲到的就是修改指定的节点内容了,我们仍然建立在遍历的基础上:

相对比较简单,我们就不再细讲。

细节总结:

几种常见的排序算法:

python可视化排序

题目模式:

1.读程序题:

阅读这段程序并写出它输出的结果。

2.程序填空题:

一般可能不会直接给出程序的具体功能,但是从程序名称可以大致确定,例如这道题是排序,我们需要通过观察已有的代码确定它使用的排序方式并正确补全。

3.任务驱动编程题:

1.用户输入一个有理数,请分离其符号部分,整数部分,以及小数部分。

2.创建数组保存周一之周日名称,用户输入一个字符串,判断是否属于已经保存的名称之一。 是则输出名称,否则输出None。

题目给出需求目标,自行设计完整代码完成需求。

就这。