《The C Programming Language, 2nd Edition》K&R Chapter 4 - Functions and Program Structure 笔记
编译
UNIX中cc命令cc main.c getline.o strindex.o
将main.c重新编译,之后与getline.o、strindex.o一起添加到可执行文件a.out中。
外部变量和函数
C程序可以看作由一系列外部对象组成,外部对象可以是函数或变量。外部指函数外,内部指函数内。
因为C语言不允许在函数内定义函数,所以函数本身是外部的。
没有声明原型的函数,在第一次被调用时,隐式声明为返回int。
同一个名字的所有外部对象的所有引用,都指向同一个对象,即外部链接。
外部对象的作用域从声明开始到文件末尾。
使用在其他源文件中的外部对象时,必须声明为extern。当声明时存储类别(Storage Class)缺省,外部对象隐式声明为extern。
extern声明不需要指明数组的长度。
static声明的外部对象为静态、内部链接,对其他源文件不可见,避免了名称冲突。
static声明的内部变量为静态、无链接,只能在函数中被访问(与自动变量相同),之后一直占据存储空间不随函数退出消失(与自动变量不同)。
register
register声明表示该变量使用频率较高,建议编译器将变量放在寄存器中(程序更小,速度更快),但编译器可以选择无视。
register声明只适用于自动变量和函数形参。
无论register声明的变量是否最终放在寄存器中,它的地址都是不可访问的。
初始化
block内声明的自动变量,每次进入block时都初始化,离开block时消失。
block内声明的静态变量,第一次进入block时初始化。
block内声明block外存在的变量,会隐藏block外的变量,声明新的变量。
不进行显式初始化的情况下,静态变量都初始化为0,自动变量和寄存器变量是未定义的。
静态变量的初始化表达式必须是常量表达式,且只初始化一次(在程序开始前,或第一次进入block时)。
自动变量与寄存器变量的初始化表达式任意,每次进入函数或block时都被初始化。
数组声明时允许后跟一个初始化表达式列表进行初始化。当省略数组长度时,长度为列表中初始化表达式的个数。当初始化表达式的个数比数组长度小时,则初始化为0。如果初始化表达式的个数大于数组长度是错误的。
字符数组允许以一个字符串替代初始化表达式列表,数组元素包含字符串末尾的'\0'。
递归
递归不节省内存,执行速度也不快,但代码紧凑,更容易编写和理解。
预处理
#include如果文件名用引号,则表示先从源文件位置查找该文件,如果没找到则按文件名用尖括号相同的规则查找该文件,具体规则取决于具体实现。
在大程序中用#include将所有声明放在一起是比较好的方法,保证了所有源文件使用相同的声明。缺点是当内容发生变化时,所有依赖于这个文件的源文件都必须重新编译。
#define定义的名字,作用域从定义位置起到文件末尾。太长的宏定义可以使用「\」换行。
#define允许带参数,如#define max(A, B) ((A) > (B) ? (A) : (B))
。
将函数定义成宏,可以减少函数调用的开销。
#undef取消#define定义的名称。
「#」:#define dprint(expr) printf(#expr " = %g\n", expr)
,dprint(x/y);
等价于printf("x/y = %g\n", x/y);
。
「##」:#define paste(front, back) front ## back
,paste(name, 1);
等价于变量名name1。
#elif类似于else if。
#if define(名字)
,当名字定义时,值1,否则为0。等价于#ifdef。#if !define(名字)
等价于#ifndef。
例程
找出所有包含指定字符串的行
#include <stdio.h>
#define MAXLINE 1000 /* maximum input line length */
int getline(char line[], int max);
int strindex(char source[], char searchfor[]);
char pattern[] = "ould"; /* pattern to search for */
/* find all lines matching pattern */
main()
{
char line[MAXLINE];
int found = 0;
while (getline(line, MAXLINE) > 0)
if (strindex(line, pattern) >= 0) {
printf("%s", line);
found++;
}
return found;
}
/* getline: get line into s, return length */
int getline(char s[], int lim)
{
int c, i;
i = 0;
while (--lim > 0 && (c=getchar()) != EOF && c != '\n')
s[i++] = c;
if (c == '\n')
s[i++] = c;
s[i] = '\0';
return i;
}
/* strindex: return index of t in s, -1 if none */
int strindex(char s[], char t[])
{
int i, j, k;
for (i = 0; s[i] != '\0'; i++) {
for (j=i, k=0; t[k]!='\0' && s[j]==t[k]; j++, k++)
;
if (k > 0 && t[k] == '\0')
return i;
}
return -1;
}
atof函数(将字符串转换为浮点)
#include <ctype.h>
/* atof: convert string s to double */
double atof(char s[])
{
double val, power;
int i, sign;
for (i = 0; isspace(s[i]); i++) /* skip white space */
;
sign = (s[i] == '-') ? -1 : 1;
if (s[i] == '+' || s[i] == '-')
i++;
for (val = 0.0; isdigit(s[i]); i++)
val = 10.0 * val + (s[i] - '0');
if (s[i] == '.')
i++;
for (power = 1.0; isdigit(s[i]); i++) {
val = 10.0 * val + (s[i] - '0');
power *= 10;
}
return sign * val / power;
}
atoi函数(将字符串转换为整数)
/* atoi: convert string s to integer using atof */
int atoi(char s[])
{
double atof(char s[]);
return (int) atof(s);
}
逆波兰计算器
(1 - 2) * (4 + 5)
逆波兰表示法为1 2 - 4 5 + *
。
calc.h
#define NUMBER '0' /* signal that a number was found */
void push(double);
double pop(void);
int getop(char []);
int getch(void);
void ungetch(int c);
main.c
#include <stdio.h>
#include <stdlib.h> /* for atof() */
#include "calc.h"
#define MAXOP 100 /* max size of operand or operator */
/* reverse Polish calculator */
main()
{
int type;
double op2;
char s[MAXOP];
while ((type = getop(s)) != EOF) {
switch (type) {
case NUMBER:
push(atof(s));
break;
case '+':
push(pop() + pop());
break;
case '*':
push(pop() * pop());
break;
case '-':
op2 = pop();
push(pop() - op2);
break;
case '/':
op2 = pop();
if (op2 != 0.0)
push(pop() / op2);
else
printf("error: zero divisor\n");
break;
case '\n':
printf("\t%.8g\n", pop());
break;
default:
printf("error: unknown command %s\n", s);
break;
}
}
return 0;
}
getop.c
#include <stdio.h>
#include <ctype.h>
#include "calc.h"
/* getop: get next character or numeric operand */
int getop(char s[])
{
int i, c;
while ((s[0] = c = getch()) == ' ' || c == '\t')
;
s[1] = '\0';
if (!isdigit(c) && c != '.')
return c; /* not a number */
i = 0;
if (isdigit(c)) /* collect integer part */
while (isdigit(s[++i] = c = getch()))
;
if (c == '.') /* collect fraction part */
while (isdigit(s[++i] = c = getch()))
;
s[i] = '\0';
if (c != EOF)
ungetch(c);
return NUMBER;
}
stack.h
#include <stdio.h>
#include "calc.h"
#define MAXVAL 100 /* maximum depth of val stack */
int sp = 0; /* next free stack position */
double val[MAXVAL]; /* value stack */
/* push: push f onto value stack */
void push(double f)
{
if (sp < MAXVAL)
val[sp++] = f;
else
printf("error: stack full, can't push %g\n", f);
}
/* pop: pop and return top value from stack */
double pop(void)
{
if (sp > 0)
return val[--sp];
else {
printf("error: stack empty\n");
return 0.0;
}
}
getch.c
#include <stdio.h>
#define BUFSIZE 100
char buf[BUFSIZE]; /* buffer for ungetch */
int bufp = 0; /* next free position in buf */
int getch(void) /* get a (possibly pushed-back) character */
{
return (bufp > 0) ? buf[--bufp] : getchar();
}
void ungetch(int c) /* push character back on input */
{
if (bufp >= BUFSIZE)
printf("ungetch: too many characters\n");
else
buf[bufp++] = c;
}
打印十进制整数
#include <stdio.h>
/* printd: print n in decimal */
void printd(int n)
{
if (n < 0) {
putchar('-');
n = -n;
}
if (n / 10)
printd(n / 10);
putchar(n % 10 + '0');
}
快速排序
/* qsort: sort v[left]...v[right] into increasing order */
void qsort(int v[], int left, int right)
{
int i, last;
void swap(int v[], int i, int j);
if (left >= right) /* do nothing if array contains */
return; /* fewer than two elements */
swap(v, left, (left + right)/2); /* move partition elem */
last = left; /* to v[0] */
for (i = left + 1; i <= right; i++) /* partition */
if (v[i] < v[left])
swap(v, ++last, i);
swap(v, left, last); /* restore partition elem */
qsort(v, left, last-1);
qsort(v, last+1, right);
}
/* swap: interchange v[i] and v[j] */
void swap(int v[], int i, int j)
{
int temp;
temp = v[i];
v[i] = v[j];
v[j] = temp;
}