1.程序设计和C语言
什么是程序?
C语言的由来
一个简单的C程序
加工:
- 编译。源代码-目标代码
- 链接。加入C的运行系统、函数库提供的功能模块等。
程序开发过程:分析问题 - 编写程序 - 编译 - 链接 - 调试程序 - 完成
程序错误
编译时错误:
- 局部语法错误:要点集中精力解决编译后的第一个错误。
- 上下文关系错误:用到的未定义等等。
运行时错误:
- 违反系统环境的基本要求
- 进入不能结束的状态:死循环。
- 执行过程中出现某些情况,无法继续下去而停止
- 程序执行结束也不出错,但产生的效果不符合要求。
动态运行错误的排查
静态错误:编译程序、链接程序能发现的错误都属于这一类。熟悉对应语言的语法规则、结构形式、上下文关系方面的规定。
动态运行错误:追踪、监视、设置断点、中断执行。
问题与程序设计
- 分析问题的能力
- 掌握所用的程序语言
- 学会写程序
- 检查程序错误的能力
- 熟悉所用工具和环境
2.数据对象与计算
基本字符、名字表示、标识符和关键字
名字(标识符)的构成
- 数字
- 大小写字母
- 其他一些可打印字符(标点符号、运算符号、括号)
- 一些特殊字符:空格符、换行符、制表符(统称:空白字符)
标识符由字母和数字组成的连续字符(不能有空白字符),第一个字符必须是字母(C中下划线当做字母看待)
关键字
有预先定义好的特殊意义,不能用于其他目的。main不是关键字。
数据与类型
基本类型和数据表示
运算符、表达式与计算
数学函数库及其使用
3.变量、函数和控制结构
语句、复合结构
变量-概念、定义和使用
定义函数
语句与控制结构
4.基本程序设计技术
5.程序结构
6.数据对象的顺序组合:数组
7.指针
地址与指针
给变量赋值是将值存入对应单元;使用变量值时从相应单元中取用。外部变 量和静态局部变量的存在期贯穿整个程序执行期,其存储位置在程序开始前确定,并保持到 程序结束。局部自动变量则不同,设 x 是函数 fun 里定义的自动变量,只有执行进入 x 的 定义所在的复合语句时才为x确定存储。x占据该块存储直至执行离开这个复合语句。如果 执行再次进入该复合语句(包括 fun 再次执行),就会再次为 x 分配存储,但是其位置与前 一次无关。这些情况决定了自动变量的各种特性。
变量存在期就是它占据被分配存储位置的期间。虽然不同变量在这方面的性质不同,但 它们在存在期里都有一个固定地址*。既然变量都有地址,地址也用二进制编码,那么就有 可能将地址作为处理的数据。问题是这样做有什么价值?
把程序对象(如变量)的地址作为一种可处理数据,称为地址值或指针值, 以地址为值的变量称为指针变量,简称指针(pointer)。
机器语言层对各种对象 的操作都要通过地址。指针变量里保存程序对象的地址,通过它们就可以访问和处理有关对 象。高级语言里的指针是访问程序对象的手段,以便能更灵活方便地实施操作。
对指针变量的操作:
- 将程序对象的地址(如变量地址,还有其他情况。为简单 起见,下面以变量为例)存入指针变量,这称为指针赋值。当一个指针变量保存了某个变量 的地址时,也说该指针指向了那个变量。
- 通过指针访问被指对象(变量),称为间接访 问。
由于指针值是数据,指针变量可以赋值,所以一个指针的指向在程序执行中可以改变。 指针 p 在执行中某时刻指向变量 x,在另一时刻也可以指向变量 y(不应对 此感到奇怪,就像一个整型变量在某时可能保存着 0,另一时刻可能保存着 2)。这样,同一 个通过 p 使用被它指向的对象的
语句,在前一时刻访问的就是 x,
后一时刻访问的就是 y。这样就
带来了新的灵活性
指针变量的定义和使用
C 语言的指针有类型,每个指针只能指向一种特定类型的变量,保存这种类型变量的地 址。
指针操作
- 取地址运算
& 取变量的地址。指针变量可以做相等判断。
相等就是值相等,对指针变量而 言,值相等意味着两个指针指向 同一位置。
- 间接运算
由指针得到被指变量。
这种表达式可以像普通变量一样用:放在表达式里表示 取值参加运算;或放在赋值运算符左边给被指变量赋值。
1 | // 当时 p 指向变量 n,写 *p 就相当于直接写变量 n,因此这个操作完成的是给变量 n |
指针作为函数的参数
1 |
|
与指针有关的一些问题
空指针
空指针值用 0 表示,这个值绝 不会是任何程序对象的地址。给一个指针赋值 0 就表示要它不指向任何有意义的东西。为了 提高程序的可读性,标准库定义了一个与 0 等价的符号常量 NULL
p = NULL;或者 p = 0;
指针初始化
如果定义指针变量时没做初始化,外部变量和局部静态变量将自动初始化为空指针(0 值), 局部自动变量和寄存器变量不自动初始化,建立后的值不确定。
指针使用中的常见错误
使用指针的最常见错误就是非法的间接访问;
1 | // 语句“*p = 2;”是错误的。因为在执行这个语句时 p 没有指向任何整型变量,定义 p 时 没对它做初始化,后面也没做过指针赋值。这时通过 p 间接赋值会把值赋到何处? |
当一个指针没有保存当时合法的变量地址时,人们称它是悬空指针或者野指针。
通用指针
可以指向任何类型的变量。通用指针的类型用(void *)表示,因此也称为 void 指针。
指针转换
指针转换就可以看作一种观点转换。把一个整型指针转换为一个通用指针,地址 并没有改变,但却把类型信息丢掉了。
指针和数组
C语言中指针和数组的关系是它所特有的,除了由C语言派生出来的一些语言(如C++ 等)之外,一般程序语言里并没有这种关系。值得提出的是,这种关系现在已经被借用到其 他地方,成为一种很有用访问数据集合的一般性技术。
指向数组元素的指针
数组元素可以看作是相应类型的变量。因此,只要类型匹配,完全可以让指针指向数组
元素。
指针运算
当一个指针指向数组中的某个元素时,程序里不但可以通过该指针访问被指元素,还可 以通过它访问数组里的其他元素。
指针运算原理:为什么当一个指针指向数组时,可能计算出它所指数组中下一元素的位置?原因是
普通指针具有确定类型,总是指向确定类型的数据对象,而这种数据对象的大小总可以 静态确定。当指针 p 指向数组 a 时,由于 p 的指向类型与 a 的元素类型一致,而这种 类型的一个数据项占据的存储大小已知,显然指针值 p+1 可以根据指针 p 当时的值和 数组元素的大小算出来。知道数组里一个元素的位置,就可以计算出下一个元素的位置, 或几个元素之后的元素位置,这是指针运算的基础。
对于通用指针,即使它指在数组里的某个地方,因为没有确定的指向类型,对它也 不可能做一般的指针计算。对通用指针有效的指针运算只有比较。
数组写法与指针写法