标题:求助,The C programing language书中的两点疑惑(getword函数和折半查找)
只看楼主
giggsxbr
Rank: 1
等 级:新手上路
帖 子:16
专家分:0
注 册:2011-9-27
结帖率:0
已结贴  问题点数:10 回复次数:18 
求助,The C programing language书中的两点疑惑(getword函数和折半查找)
我看的是第二版,中文版。

第一个疑问:

书的118页,getword函数是从输入中读取下一个单词,ungetch函数在书的前面章节,是为了把某个字符存放在缓冲区,避免丢失

程序代码:
int getword(char *word, int lim)
{
    int c, getch(void);
    void ungetch(int);
    char *w = word;

    while (isspace(c = getch()))
        ;
    if (c != EOF)
        *w++ = c;
    if (!isalpha(c)) {
        *w = '\0';
        return c;
    }
    for ( ; --lim; w++)
        if (!isalnum(*w = getch())) {
            ungetch(*w);
            break;
        }
    *W = '\0';
    return word[0];
}


可为什么要声明一个指针w呢?看起来毫无必要啊,函数本来就是会生成参数word的一个拷贝不是吗?


第二个疑问:

120页,那个折半查找的函数

程序代码:
struct key *binsearch(char *word, struct 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;
}


为什么不用117页利用数组下标那种比较方式,这样写代码呢:

程序代码:
struct key *binsearch(char *word, struct key *tab, int n)
{
    int cond;
    struct key *low = &tab[0];
    struct key *high = &tab[n - 1];
    struct key *mid;

    while (low <= high) {
        mid = low + (high - low) / 2;
        if ((cond = strcmp(word, mid->word)) < 0)
            high = mid - 1;
        else if (cond > 0)
            low = mid + 1;
        else
            return mid;
    }
    return NULL;
}


我看了标准库里的函数,也用的是“<=”进行比较,并且在相应分支里给high赋值成mid-1

效果看起来是一样的,但我感觉这本书里这样别扭的比较是别有用意的,因为下面有一段话专门解释(正是这段解释让我一头雾水):tab[n]虽然越界,但是对它进行取地址是合法的操作。
搜索更多相关主题的帖子: 单词 缓冲区 中文版 word 
2012-01-06 15:28
lz1091914999
Rank: 14Rank: 14Rank: 14Rank: 14
来 自:四川
等 级:贵宾
威 望:37
帖 子:2011
专家分:5959
注 册:2010-11-1
得分:10 
1、因为w进行过指针运算,而且还要改变函数外部指针word引用的值。
2、tab + n 可以当作一个结束标记,这样循环条件就可以改为:low < high,当然也可以用tab + n - 1,这样循环条件就变为:low <= high,当然更好的方式是前者,因为它稍微比后者效率高一点,因为 <= 是"小于或者等于",这样就需要比较2次,但前者只需要一次。

[ 本帖最后由 lz1091914999 于 2012-1-6 16:11 编辑 ]

My life is brilliant
2012-01-06 16:04
giggsxbr
Rank: 1
等 级:新手上路
帖 子:16
专家分:0
注 册:2011-9-27
得分:0 
以下是引用lz1091914999在2012-1-6 16:04:52的发言:

1、因为w进行过指针运算。
2、tab + n 可以当作一个结束标记,这样循环条件就可以改为:low < high,当然也可以用tab + n - 1,这样循环条件就变为:low <= high,当然更好的方式是前者,因为它稍微比后者效率高一点,因为 <= 是"小于或者等于",这样就需要比较2次,但前者只需要一次。


你好,感谢你的解答。

1、你指的是自增运算吗?这个自增运算是针对word的拷贝,而不会改变程序中传入参数的啊

2、你的意思是“<=”这个运算符比“<”效率高?
2012-01-06 16:09
lz1091914999
Rank: 14Rank: 14Rank: 14Rank: 14
来 自:四川
等 级:贵宾
威 望:37
帖 子:2011
专家分:5959
注 册:2010-11-1
得分:0 
回复 3楼 giggsxbr
1、int getword(char *word, int lim); word的类型是char*,所以这里是传递地址。
2、也许吧,这是从逻辑上来理解的,但这点效率完全可以忽略掉。

My life is brilliant
2012-01-06 16:15
giggsxbr
Rank: 1
等 级:新手上路
帖 子:16
专家分:0
注 册:2011-9-27
得分:0 
以下是引用lz1091914999在2012-1-6 16:15:50的发言:

1、int getword(char *word, int lim); word的类型是char*,所以这里是传递地址。
2、也许吧,这是从逻辑上来理解的,但这点效率完全可以忽略掉。


1、对啊,传递地址,所以函数可以改变指针指向的东西,但改变不了指针本身,不是吗?

2、但库函数用的是<=
程序代码:
void * __cdecl bsearch (
        REG4 const void *key,
        const void *base,
        size_t num,
        size_t width,
        int (__cdecl *compare)(const void *, const void *)
        )
{
        REG1 char *lo = (char *)base;
        REG2 char *hi = (char *)base + (num - 1) * width;
        REG3 char *mid;
        unsigned int half;
        int result;

        while (lo <= hi)
                if (half = num / 2)
                {
                        mid = lo + (num & 1 ? half : (half - 1)) * width;
                        if (!(result = (*compare)(key,mid)))
                                return(mid);
                        else if (result < 0)
                        {
                                hi = mid - width;
                                num = num & 1 ? half : half-1;
                        }
                        else    {
                                lo = mid + width;
                                num = half;
                        }
                }
                else if (num)
                        return((*compare)(key,lo) ? NULL : lo);
                else
                        break;

        return(NULL);
}
2012-01-06 16:19
lz1091914999
Rank: 14Rank: 14Rank: 14Rank: 14
来 自:四川
等 级:贵宾
威 望:37
帖 子:2011
专家分:5959
注 册:2010-11-1
得分:0 
初学就不要看这本了吧,可以去看看C Primer Plus,但这本书比较罗嗦,不过有耐心就行。

My life is brilliant
2012-01-06 16:20
giggsxbr
Rank: 1
等 级:新手上路
帖 子:16
专家分:0
注 册:2011-9-27
得分:0 
额,为啥,我本以为这本书就是经典入门教程呢。。。
2012-01-06 16:23
lz1091914999
Rank: 14Rank: 14Rank: 14Rank: 14
来 自:四川
等 级:贵宾
威 望:37
帖 子:2011
专家分:5959
注 册:2010-11-1
得分:0 
回复 5楼 giggsxbr
1、没错,如果要想改变得用char**。
2、呵呵,现在软件行业最重要并不是代码优化(太多的代码优化编译器就能完成了),而是算法和设计模式,"<"和"<="前者的效率可能只在60、70年代才能体现出来,现在效率完全是靠算法来操作的,但能写漂亮的代码并不是什么环处。

My life is brilliant
2012-01-06 16:29
lz1091914999
Rank: 14Rank: 14Rank: 14Rank: 14
来 自:四川
等 级:贵宾
威 望:37
帖 子:2011
专家分:5959
注 册:2010-11-1
得分:0 
回复 7楼 giggsxbr
事实就是这样,这本并不是入门学者看的,参考一下这个:
http://list.

My life is brilliant
2012-01-06 16:30
giggsxbr
Rank: 1
等 级:新手上路
帖 子:16
专家分:0
注 册:2011-9-27
得分:0 
以下是引用lz1091914999在2012-1-6 16:29:17的发言:

1、没错,如果要想改变得用char**。
2、呵呵,现在软件行业最重要并不是代码优化(太多的代码优化编译器就能完成了),而是算法和设计模式,"<"和"<="前者的效率可能只在60、70年代才能体现出来,现在效率完全是靠算法来操作的,但能写漂亮的代码并不是什么环处。


1、对啊,既然不会破坏原有的指针,为什么函数体内要弄一个w呢?直接用word不就行了?

2、感觉库函数的代码一般都是“不可超越”的,呵呵
2012-01-06 16:34



参与讨论请移步原网站贴子:https://bbs.bccn.net/thread-359258-1-1.html




关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.014171 second(s), 7 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved