voshk

从问题到程序

2017/02/24 Share

1.程序设计和C语言

什么是程序?

C语言的由来

一个简单的C程序

加工:

  1. 编译。源代码-目标代码
  2. 链接。加入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
2
3
// 当时 p 指向变量 n,写 *p 就相当于直接写变量 n,因此这个操作完成的是给变量 n
赋值 17。
*p = 17;

指针作为函数的参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

// 交换两个数的值

void swap(int x, int y) {
int temp = x;
x = y;
y = t;
}

int m = 1, n = 2;
swap(m, n);

// 执行结果发现mn值没变。C语言的参数机制:形参xy交换了值,并不改变实参mn的值。

void swap0(int *p, int *q) {
int t = *p;
*p = *q;
*q = *;
}

与指针有关的一些问题

空指针

空指针值用 0 表示,这个值绝 不会是任何程序对象的地址。给一个指针赋值 0 就表示要它不指向任何有意义的东西。为了 提高程序的可读性,标准库定义了一个与 0 等价的符号常量 NULL

p = NULL;或者 p = 0;

指针初始化

如果定义指针变量时没做初始化,外部变量和局部静态变量将自动初始化为空指针(0 值), 局部自动变量和寄存器变量不自动初始化,建立后的值不确定。

指针使用中的常见错误

使用指针的最常见错误就是非法的间接访问;

1
2
3
// 语句“*p = 2;”是错误的。因为在执行这个语句时 p 没有指向任何整型变量,定义 p 时 没对它做初始化,后面也没做过指针赋值。这时通过 p 间接赋值会把值赋到何处?
int *p, n = 3;
*p = 2;

当一个指针没有保存当时合法的变量地址时,人们称它是悬空指针或者野指针。

通用指针

可以指向任何类型的变量。通用指针的类型用(void *)表示,因此也称为 void 指针。

指针转换

指针转换就可以看作一种观点转换。把一个整型指针转换为一个通用指针,地址 并没有改变,但却把类型信息丢掉了。

指针和数组

C语言中指针和数组的关系是它所特有的,除了由C语言派生出来的一些语言(如C++ 等)之外,一般程序语言里并没有这种关系。值得提出的是,这种关系现在已经被借用到其 他地方,成为一种很有用访问数据集合的一般性技术。

指向数组元素的指针

数组元素可以看作是相应类型的变量。因此,只要类型匹配,完全可以让指针指向数组
元素。

指针运算

当一个指针指向数组中的某个元素时,程序里不但可以通过该指针访问被指元素,还可 以通过它访问数组里的其他元素。

指针运算原理:为什么当一个指针指向数组时,可能计算出它所指数组中下一元素的位置?原因是
普通指针具有确定类型,总是指向确定类型的数据对象,而这种数据对象的大小总可以 静态确定。当指针 p 指向数组 a 时,由于 p 的指向类型与 a 的元素类型一致,而这种 类型的一个数据项占据的存储大小已知,显然指针值 p+1 可以根据指针 p 当时的值和 数组元素的大小算出来。知道数组里一个元素的位置,就可以计算出下一个元素的位置, 或几个元素之后的元素位置,这是指针运算的基础。
对于通用指针,即使它指在数组里的某个地方,因为没有确定的指向类型,对它也 不可能做一般的指针计算。对通用指针有效的指针运算只有比较。

数组写法与指针写法

基于指针运算的数组程序设计

数组参数与指针

字符指针与字符数组

指针数组

动态存储管理

8.文件和输入输出

9.结构和其他数据机制

10.程序开发技术

11.标准库