一个语言的程序设计有一些常用的基本模式,这些模式是许多人长期工作的总结。在这个语言的程序中到处可见。对于一些典型问题,采用适当的模式是最容易把程序写好、写正确的。在这里我们将从简单到复杂,分门别类地列处一些C程序模式,供大家参考。这里列出的东西选自各种材料(包括《从问题到程序》书中)。这里列出的东西是很初步的。如果你认为有些东西也很重要,请给我们提示。
在所有模式描述中,用$$符号括起来的一段段文字表示的是应该实际写出的东西。
有关解释如果写了页数,请参考《从问题到程序》书中相关的页。
简单输出程序模式:
#include <stdio.h>
int main () {
$一个或几个输出语句,例如printf("Hello, world!\n");$
return 0;
}
----------------------------------------------------
例:
#include <stdio.h>
int main() {
printf("Welcome\n");
printf("to\n");
printf("Beijing!\n");
return 0;
}
简单表达式计算模式:
#include <stdio.h>
int main() {
printf($ 格式描述串$, $一个或几个表达式$);
return 0;
}
---------------------------------------------------
注意:格式描述串中转换描述与参数个数一致,类型一致。
---------------------------------------------------
#include <stdio.h>
int main() {
printf("%f * %f = %f", 3.14, 6.5, 3.14 * 6.5);
return 0;
}
简单算术计算函数定义:
double fun ($一个或几个参数的说明$) {
return $计算表达式$;
}
----------------------------------------------------
1,函数返回值类型根据需要写出,未必是double;
2,参数写出类型和参数名的对,多个参数用逗号分隔;
3,计算表达式描述如何由参数出发算出函数值;
4,如果计算中需要用数学函数,应该在程序开始写一行
#include <math.h>
----------------------------------------------------
例:
double circle_area (double r) {
return r * r * 3.14159265;
}
有函数定义的一般程序:
#include …
…… /* 函数定义写在这里(可以有一个或几个) */
int main () {
/* 主程序体,通常包含对函数的调用 */
return 0;
}
常用while循环形式:
n = 1; /* 初始化循环中使用的变量 */
while (n <= 100) { /* 已知次数的循环用for结构写得更多 */
/* 其他语句 */
n = n + 1; /* 循环最后更新辅助变量 */
}
注:这种更常见的是采用for循环形式写。见下。
----------------------------------------------------
/* 有关变量的初始化 */
while ($表达式$ >= 1E-6) {
/* 循环中的计算应该影响“表达式”的值,否则将导致无限循环 */
}
常用for循环形式:
for (n = 0; n < N; n++) {
$循环体里的语句$
}
---------------------------------------------------
注意:C语言里一般不用(除非有特殊目的):
for (n = 1; n <= N; n++) {
$循环体里的语句$
}
给程序计时:
#include <stdio.h>
#include <time.h>
/* 其他定义 */
int main () {
/* 其他程序变量的定义 */
double x;
x = clock() / CLOCKS_PER_SEC;
/* 需要计时的程序片段 */
x = clock() / CLOCKS_PER_SEC - x;
printf("Timing: %f\n", x); /* 输出形式自己确定 */
return 0;
}
---------------------------------------------------
注意:不同系统的计时精度可能不同。有些系统还有非标准的计时功能。
输入和处理由标准输入文件来的一系列字符
int c;
/* 其他定义或语句 */
while ((c = getchar()) != EOF) {
/* 对读入字符的处理 */
}
---------------------------------------------------
1,接收读入字符的变量(例如上面的c)必须用int类型;
2,注意while条件中的括号,不能写错;
3,应该写 #include <stdio.h>
最常见的数组操作
for (i = 0; i < N; i++) {
.... ....
.... a[i] .... b[i]
.... ....
}
---------------------------------------------------
1,循环范围不能超出数组下标的范围
典型的处理数组的函数
double sqsum(double a[], int n) {
double x = 0.0;
int i;
for (i = 0; i < n; i++)
x += a[i] * a[i];
return x;
}
---------------------------------------------------
1,注意数组参数的写法;
2,增加一个描述数组长度的参数,借助于它控制对数组元素的处理;
3,通过这种函数可以改变实际参数数组。
处理字符串的典型函数
void str_copy (char s[], char t[]) {
int i;
for (i = 0; t[i] != '\0'; i++)
s[i] = t[i];
s[i] = '\0';
}
---------------------------------------------------
void str_copy1 (char *s, char *t) {
for (; *t != '\0'; s++, t++)
*s = *t;
*s = '\0';
}
---------------------------------------------------
1,参数用 char s[] 或者 char *s 描述,两者等价,但用 char s[] 更具有提示性;
2,用遇到空字符'\0'作为循环结束条件;
3,还有些更紧凑的写法,参见有关书籍
逐个处理命令行参数
int main (int argc, char *argv[]) {
int i;
... ...
for (i = 0; i < argc; i++) {
.... argv[i] ....
}
... ...
}
---------------------------------------------------
int main (int argc, char *argv[]) {
... ...
for (; *agrv != NULL; argv++) {
... *argv ...
}
... ...
}
---------------------------------------------------
循环中的 *argv 将依次取各个命令行参数字符串。
注意:编号0的参数是命令名本身,如果不处理它应该先跳过去。
使用动态存储分配函数malloc或calloc
if ((p = (... *)malloc(...)) == NULL) {
.. ... /* 对分配未成功情况的处理 */
}
---------------------------------------------------
1,指针应当具有合适的类型;
2,在malloc名前写合适的转换描述;
3,malloc的参数应当借助sizeof计算。
链接表的处理模式(以扫描的方式逐个处理表中的数据)
for (p = head; p != NULL; p = p->next) {
.... p->data ....
}
---------------------------------------------------
假设head是指向表头结点的指针。
结点中的next成分是指向下一个结点的指针,data是数据。
文件使用的基本模式
FILE *fp;
.... ....
if ((fp = fopen($文件名$, $打开方式$)) == NULL) {
/* 当文件打不开时的处理 */
}
... ... /* 对文件的各种操作 */
fclose(fp);
---------------------------------------------------
执行文件打开操作之后,必须检查操作是否正常完成。
使用<stdlib.h>里的bsearch和qsort,比较函数的基本写法
1,确定被比较对象的顺序关系;
2,比较函数总用两个const void* 参数;
3,在函数开始时将参数正确转换到指向数组元素类型的指针;
4,在第一个参数大于、等于、小于第二个时分别返回1、0、-1;
5,注意使用方式。
---------------------------------------------------
例子:假定被排序的是整数数组。定义比较函数:
int icmp(const void *p, const void *q){
const int *m = p, *n = q;
return *m > *n ? 1 : (*m == *n ? 0 : -1);
}
使用:
int *p, a[] = {5, 6, 3, 28, 23, 34, 7, 9, 6, 14}, k = 7;
int main () {
... ...
qsort(a, sizeof(a)/sizeof(int), sizeof(int), icmp);
/* 这样,数组a的元素已经按照上升顺序排列好了 */
p = bsearch(&k, a, sizeof(a)/sizeof(int), sizeof(int), icmp);
/* 指针p将指向数组a中元素7的位置 */
... ...
}
---------------------------------------------------
请注意在这里如何为bsearch和qsort提供所要求的各个参数。
评论