指针与数组
输出数组名,数组名是固定的,指向数组的指针变量却是灵活可变的
指针与函数
输出函数名,函数名是固定的,指向函数的指针变量却是灵活可变的
在下面的例子中,getfile函数用来在备份/还原过程中处理文件,它接受两个参数,fill和skip(都是指向函数的指针)。这两个参数用来指示如何读取或跳过数据。
/*
* Extract a file from the tape.
* When an allocated block is found it is passed to the fill function;
* when an unallocated block (hole) is found, a zeroed buffer is passed
* to the skip function.
*/
void
getfile(fill, skip)
void (*fill) __P((char *, long));
void (*skip) __P((char *, long));
{
int i;
int curblk = 0;
quad_t size = spcl.c_dinode.di_size;
static char clearedbuf[MAXBSIZE];
char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE];
char junk[TP_BSIZE];
#ifdef __GNUC__ /* XXX: to shut up gcc warnings */
(void)&curblk;
(void)&size;
#endif
if (spcl.c_type == TS_END)
panic("ran off end of tape\n");
if (spcl.c_magic != NFS_MAGIC)
panic("not at beginning of a file\n");
if (!gettingfile && setjmp(restart) != 0)
return;
gettingfile++;
loop:
for (i = 0; i < spcl.c_count; i++) {
if (spcl.c_addr[i]) {
readtape(&buf[curblk++][0]);
if (curblk == fssize / TP_BSIZE) {
(*fill)((char *)buf, (long)(size > TP_BSIZE ?
fssize : (curblk - 1) * TP_BSIZE + size));
curblk = 0;
}
} else {
if (curblk > 0) {
(*fill)((char *)buf, (long)(size > TP_BSIZE ?
curblk * TP_BSIZE :
(curblk - 1) * TP_BSIZE + size));
curblk = 0;
}
(*skip)(clearedbuf, (long)(size > TP_BSIZE ?
TP_BSIZE : size));
}
if ((size -= TP_BSIZE) <= 0) {
for (i++; i < spcl.c_count; i++)
if (spcl.c_addr[i])
readtape(junk);
break;
}
}
if (gethead(&spcl) == GOOD && size > 0) {
if (spcl.c_type == TS_ADDR)
goto loop;
dprintf(stdout,
"Missing address (header) block for %s at %d blocks\n",
curfile.name, blksread);
}
if (curblk > 0)
(*fill)((char *)buf, (long)((curblk * TP_BSIZE) + size));
findinode(&spcl);
gettingfile = 0;
}
借助函数指针,开发者还可以参数化代码体的控制流程,在下面的例子中,closefunc保存着关闭fin流时需要调用的函数指针。在运行时,实际调用的函数取决于fin流的打开方式。
void
retrieve(cmd, name)
char *cmd, *name;
{
FILE *fin = NULL, *dout;
struct stat st;
int (*closefunc) __P((FILE *)) = NULL;
int log;
log = (cmd == 0);
if (cmd == 0) {
fin = fopen(name, "r"), closefunc = fclose;
if (fin == NULL)
cmd = do_conversion(name);
}
if (cmd) {
char line[BUFSIZ];
(void)snprintf(line, sizeof(line), cmd, name), name = line;
fin = ftpd_popen(line, "r", 1), closefunc = ftpd_pclose;
st.st_size = -1;
st.st_blksize = BUFSIZ;
}
if (fin == NULL) {
if (errno != 0) {
perror_reply(550, name);
if (log) {
LOGCMD("get", name);
}
}
return;
}
byte_count = -1;
if (cmd == 0 && (fstat(fileno(fin), &st) < 0 || !S_ISREG(st.st_mode))) {
reply(550, "%s: not a plain file.", name);
goto done;
}
if (restart_point) {
if (type == TYPE_A) {
off_t i, n;
int c;
n = restart_point;
i = 0;
while (i++ < n) {
if ((c=getc(fin)) == EOF) {
perror_reply(550, name);
goto done;
}
if (c == '\n')
i++;
}
} else if (lseek(fileno(fin), restart_point, SEEK_SET) < 0) {
perror_reply(550, name);
goto done;
}
}
dout = dataconn(name, st.st_size, "w");
if (dout == NULL)
goto done;
send_data(fin, dout, st.st_blksize);
(void) fclose(dout);
data = -1;
pdata = -1;
done:
if (log)
LOGBYTES("get", name, byte_count);
(*closefunc)(fin);
}