The C Programming Language(第 2 版) 笔记 / 6 结构 / 6.4 指向结构的指针

目录、参考文献


6.4 指向结构的指针

为了进一步说明指向结构的指针和结构数组,我们重新编写关键字统计程序,这次采用指针,而不使用数组下标

keytab 的外部声明不需要修改,但 mainbinsearch 函数必须修改:

#include <stdio.h> 
#include <ctype.h> 
#include <string.h> 
#define MAXWORD 100

int getword(char *, int); 
struct key *binsearch(char *, struct key *, int);

/* count C keywords; pointer version */ 
main() 
{ 
    char word[MAXWORD]; 
    struct key *p; 
    while (getword(word, MAXWORD) != EOF) 
        if (isalpha(word[0])) 
            if ((p = binsearch(word, keytab, NKEYS)) != NULL) 
                p->count++; 
    for (p = keytab; p < keytab + NKEYS; p++) 
        if (p->count > 0) 
            printf("%4d %s\n", p->count, p->word); 
    return 0; 
}

/* binsearch: find word in tab[0]...tab[n-1] */ 
struct key *binsearch(char *word, struck key *tab, int n) 
{ 
    int cond; 
    struct key *low = &tab[0]; 
    struct key *high = &tab[n]; 
    struct key *mid;
    
    while (low < high) { 
        mid = low + (high - low) / 2; 
        if ((cond = strcmp(word, mid->word)) < 0) 
            high = mid; 
        else if (cond > 0) 
            low = mid + 1; 
        else 
            return mid; 
    } 
    return NULL; 
}

这里需要注意几点

首先,binsearch 函数在声明中必须表明:它返回的值类型是一个指向 struct key 类型的指针,而非整型
这在函数原型及 binsearch 函数中都要声明
如果 binsearch 找到与输入单词匹配的数组元素,它将返回一个指向该元素的指针,否则返回 NULL

其次,keytab 的元素在这里是通过指针访问的,这就需要对 binsearch 做较大的修改
lowhigh 的初值分别是指向表头元素的指针和指向表尾元素后面的一个元素的指针
这样就无法简单地通过 mid = (low + high) / 2 /* WRONG */ 表达式计算中间元素的位置
这是因为,两个指针之间的加法运算是非法的
但是,指针的减法运算却是合法的,high - low 的值就是数组元素的个数
因此,可以用 mid = low + (high - low) / 2mid 设置为指向位于 highlow 之间的中间元素的指针

对算法的最重要修改在于,要确保不会生成非法的指针,或者是试图访问数组范围之外的元素
问题在于 &tab[-1]&tab[n] 都超出了数组 tab 的范围
前者是绝对非法的,而对后者的间接引用也是非法的
但是,C 语言的定义保证数组末尾之后的第一个元素(即 &tab[n])的指针算术运算可以正确执行

主程序 main 中有下列语句:

for (p = keytab; p < keytab + NKEYS; p++)

如果 p 是指向结构的指针,则对 p 的算术运算需要考虑结构的长度
所以,表达式 p++ 执行时,将在 p 的基础上加上一个正确的值,以确保得到结构数组的下一个元素
这样,上述测试条件便可以保证循环正确终止

但是,千万不要认为结构的长度等于各成员长度的和
因为不同的对象有不同的对齐要求,所以,结构中可能会出现未命名的空穴(hole)
例如,假设 char 类型占用一个字节,int 类型占用 4 个字节,则下列结构:

struct {
    char c;
    int i;
};

可能需要 8 个字节的存储空间,而不是 5 个字节
使用 sizeof 运算符可以返回正确的对象长度

最后,说明一点程序的格式问题:当函数的返回值类型比较复杂时(如结构指针):

struct key *binsearch(char *word, struct key *tab, int n)

很难看出函数名,也不太容易使用文本编辑器找到函数名
可以采用另一种格式书写上述语句:

struct key *  
binsearch(char *word, struct key *tab, int n)  

具体采用哪种写法属于个人的习惯问题,可以选择自己喜欢的方式并始终保持自己的风格


目录、参考文献

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值