标题:求助,The C programing language书中的两点疑惑(getword函数和折半查找)
取消只看楼主
giggsxbr
Rank: 1
等 级:新手上路
帖 子:16
专家分:0
注 册:2011-9-27
结帖率:0
已结贴  问题点数:10 回复次数:8 
求助,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
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
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
giggsxbr
Rank: 1
等 级:新手上路
帖 子:16
专家分:0
注 册:2011-9-27
得分:0 
额,为啥,我本以为这本书就是经典入门教程呢。。。
2012-01-06 16:23
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
giggsxbr
Rank: 1
等 级:新手上路
帖 子:16
专家分:0
注 册:2011-9-27
得分:0 
以下是引用lz1091914999在2012-1-6 16:30:43的发言:

事实就是这样,这本并不是入门学者看的,参考一下这个:
http://list.


这本书排第一呀。。

话说,这本书为啥不适合初学者?
2012-01-06 16:36
giggsxbr
Rank: 1
等 级:新手上路
帖 子:16
专家分:0
注 册:2011-9-27
得分:0 
以下是引用lz1091914999在2012-1-6 16:59:33的发言:

1、呵呵,你可能理解有误,word是一个字符数组,类型是char*,所以word必需是char*,而w是一个复本而以,w和word都指向用户传入的这个数组首地址,因为最后需要返回这个数组的第一个元素,所以备份是当然的。
2、写库代码的人也不一定都是最好的,Java类库的正则表达式包里有一个类"Matcher",它是一个正则表达式的匹配器,里面有一个方法叫做,lookingAt(),它的功能是从输入序列和模式的开始匹配部分或全部,但是lookingAt这样不直观的方法名出现了,也就是说不能从名字看出这个方法功能的大概,对于Java这一个对名字有高度要求的语言来说,这样的错误,还是挺蛋疼的,而且这个方法的名字现在都还没有换掉,原因就是拖得太久了,已经有太多的程序员用过这个方法,如果更换,就必须叫所有用过这个方法的程序员改他们的源代码。取这样不直观名字的程序员曾经也在Sun工作,可以想象一下。。。
3、The C Programming language排名第一的原因有几个:
1、这个C语言之父写的(C语言之父有两个)。
2、有一位已经去世。
3、Professional C Programmer 必备。


灰常感谢你耐心的解答,嘿嘿

第一个问题我算是明白了,因为如果不备份指针的话,指针已经移到后面去,不好返回第一个元素了,呵呵

不过我依然不是很明白为什么那本书不适合初学者,是因为有些基础知识没有讲到吗,还是什么原因?(这本书我看了两遍了,感觉也不是很难懂啊,呵呵)
2012-01-06 19:25
giggsxbr
Rank: 1
等 级:新手上路
帖 子:16
专家分:0
注 册:2011-9-27
得分:0 
以下是引用lz1091914999在2012-1-6 16:59:33的发言:

1、呵呵,你可能理解有误,word是一个字符数组,类型是char*,所以word必需是char*,而w是一个复本而以,w和word都指向用户传入的这个数组首地址,因为最后需要返回这个数组的第一个元素,所以备份是当然的。
2、写库代码的人也不一定都是最好的,Java类库的正则表达式包里有一个类"Matcher",它是一个正则表达式的匹配器,里面有一个方法叫做,lookingAt(),它的功能是从输入序列和模式的开始匹配部分或全部,但是lookingAt这样不直观的方法名出现了,也就是说不能从名字看出这个方法功能的大概,对于Java这一个对名字有高度要求的语言来说,这样的错误,还是挺蛋疼的,而且这个方法的名字现在都还没有换掉,原因就是拖得太久了,已经有太多的程序员用过这个方法,如果更换,就必须叫所有用过这个方法的程序员改他们的源代码。取这样不直观名字的程序员曾经也在Sun工作,可以想象一下。。。
3、The C Programming language排名第一的原因有几个:
1、这个C语言之父写的(C语言之父有两个)。
2、有一位已经去世。
3、Professional C Programmer 必备。


其实第二个问题,我主要是不明白作者想表达的意思。

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

作者煞费苦心说了这么一大段话,还把本来看起来挺顺眼也挺符合正常思维的代码改动成了怎么看怎么别扭的样子。可是如果把low、high分别声明成&tab[0]和&tab[n-1],怎么可能出现越界呢?仅仅是因为“>=”的效率低于“>”?(也没再哪里看到过>=的效率比>低啊,呵呵)
2012-01-06 19:34
giggsxbr
Rank: 1
等 级:新手上路
帖 子:16
专家分:0
注 册:2011-9-27
得分:0 
以下是引用lz1091914999在2012-1-6 19:37:53的发言:

如果你具有悟性,那是再好不过,但是这本书还是不够深入,想要了解更多的东西还得去看看一本很厚的书才行呢。


呵呵,只是想入门,应付应付面试而已~
2012-01-06 19:42



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




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

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