| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 1041 人关注过本帖
标题:C 和指针 程序 6.3 在一组字符串中查找: 版本 2
只看楼主 加入收藏
TonyDeng
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:贵宾
威 望:304
帖 子:25859
专家分:48889
注 册:2011-6-22
收藏
得分:0 
看看下面的调试结果就知道了:

程序代码:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <conio.h>

#define TRUE 1
#define FALSE 0

void show_memory(const char* const strings[]);
int find_char(const char** strings, int value);

int main(void)
{
    const char* arr[] = { "abc", "def", NULL };

    show_memory(arr);
    if (find_char(arr, 'a'))
    {
        puts("ok!\n");
    }
    show_memory(arr);

    _getch();
    return EXIT_SUCCESS;
}

void show_memory(const char* const strings[])
{
    for (size_t index = 0; strings[index] != NULL; ++index)
    {
        printf_s("%s, %p, %p, %p, %c\n", strings[index], strings[index], strings, *strings, **strings);
    }
    putchar('\n');
}

int find_char(const char** strings, int value)
{
    assert(strings != NULL);

    while (*strings != NULL)                    // 数据入口判断是从*string所指向的位置开始的
    {
        while (**strings != '\0')
        {
            if (*(*strings)++ == value)         // 在这里修改了*strings的值
            {
                show_memory(strings);
                return TRUE;
            }
        }
        strings++;
    }

    putchar('\n');
    return FALSE;
}


运行结果:
图片附件: 游客没有浏览图片的权限,请 登录注册


strings指针本身的地址是没变,但查寻数据并不是看指针的地址,而是看指针所指向的位置,即*strings,这个指向已经被改变!这就是指针间接使用数据的陷阱,把地址当作数据。


[ 本帖最后由 TonyDeng 于 2014-9-30 16:55 编辑 ]

授人以渔,不授人以鱼。
2014-09-30 16:45
TonyDeng
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:贵宾
威 望:304
帖 子:25859
专家分:48889
注 册:2011-6-22
收藏
得分:0 
一般来说,代码中最难看、最难理解的部分,是错误源头的可能性居多。这个例子的代码,最难看的正是if (*(*strings)++ == value)那一行,我第一眼就敏感是这行的问题,事实证明的确如此。

这个程序,有两方面的缺陷:第一,强行使用指针,又不注意保护数据,偏偏任谁都知道指针解引用是针对无法复制数据而绕远路修改的特殊手段,这个代码自己把自己绕了进去,其实安全的做法是使用中间变量访问二维数组的每个元素,即用下标或指针加减法,而不是用自增这种修改自身的操作符,表面上的简练,结果造成如此隐蔽的BUG,事与愿违;第二,函数的设计就是失败的,在二维数组中查找数据,至少应返回在哪一行上查到,这个代码没有,完全把二维数据当一维处理(又是指针迷途,妄想一个指针自增到尾,所谓的节省资源),不写直接代码,结果只能害了自己,实际上,回归二维数组,就是逐行查找字符串中是否存在指定字符,对每行应用strchr()就行了(自己写个仿strchr()的函数也可以,编程本来就要这种分解小问题的思路),把代码写得那么复杂干嘛呢。

弄懂了这个问题的错误根源,难道就帮助你写出好的代码?不见得!换句话说,就算不知道这个代码为什么错,但既然知道有错,又找不到原因,干脆就改个思路,另外写一个,不必非在一棵树上吊死,实践不是读书。


[ 本帖最后由 TonyDeng 于 2014-10-1 13:34 编辑 ]

授人以渔,不授人以鱼。
2014-10-01 13:29
wssy213
Rank: 12Rank: 12Rank: 12
来 自:湖南
等 级:贵宾
威 望:10
帖 子:967
专家分:3703
注 册:2014-6-6
收藏
得分:0 
以下是引用TonyDeng在2014-10-1 13:29:48的发言:

一般来说,代码中最难看、最难理解的部分,是错误源头的可能性居多。这个例子的代码,最难看的正是if (*(*strings)++ == value)那一行,我第一眼就敏感是这行的问题,事实证明的确如此。

这个程序,有两方面的缺陷:第一,强行使用指针,又不注意保护数据,偏偏任谁都知道指针解引用是针对无法复制数据而绕远路修改的特殊手段,这个代码自己把自己绕了进去,其实安全的做法是使用中间变量访问二维数组的每个元素,即用下标或指针加减法,而不是用自增这种修改自身的操作符,表面上的简练,结果造成如此隐蔽的BUG,事与愿违;第二,函数的设计就是失败的,在二维数组中查找数据,至少应返回在哪一行上查到,这个代码没有,完全把二维数据当一维处理(又是指针迷途,妄想一个指针自增到尾,所谓的节省资源),不写直接代码,结果只能害了自己,实际上,回归二维数组,就是逐行查找字符串中是否存在指定字符,对每行应用strchr()就行了(自己写个仿strchr()的函数也可以,编程本来就要这种分解小问题的思路),把代码写得那么复杂干嘛呢。

弄懂了这个问题的错误根源,难道就帮助你写出好的代码?不见得!换句话说,就算不知道这个代码为什么错,但既然知道有错,又找不到原因,干脆就改个思路,另外写一个,不必非在一棵树上吊死,实践不是读书。

赞一个

坚持----------------------------------唯一的道路
shit ! ! !
2014-10-01 16:08
wssy213
Rank: 12Rank: 12Rank: 12
来 自:湖南
等 级:贵宾
威 望:10
帖 子:967
专家分:3703
注 册:2014-6-6
收藏
得分:0 
回复 11 楼 TonyDeng
int find_char(const char** strings, int value)
{
    assert(strings != NULL);

    while (*strings != NULL)
    {
        while (**strings != '\0')
        {
            if (*(*strings)++ == value)/* 在这里修改了*strings的值,亦即main函数中的strings[i](i为可能取到的值)的值,而且致命的是它会在main下一次对find_char的调用中用到。这样可能会更好理解一些:)*/
            {
                show_memory(strings);
                return TRUE;
            }
        }
        strings++;
    }
我看了老一会才看出来,这种错误确实难找


[ 本帖最后由 wssy213 于 2014-10-1 16:21 编辑 ]

坚持----------------------------------唯一的道路
shit ! ! !
2014-10-01 16:15
wssy213
Rank: 12Rank: 12Rank: 12
来 自:湖南
等 级:贵宾
威 望:10
帖 子:967
专家分:3703
注 册:2014-6-6
收藏
得分:0 
回复 11 楼 TonyDeng
恩 学习

坚持----------------------------------唯一的道路
shit ! ! !
2014-10-01 16:23
TonyDeng
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:贵宾
威 望:304
帖 子:25859
专家分:48889
注 册:2011-6-22
收藏
得分:0 
回复 14 楼 wssy213
是这次扫描过的部分被修改了,即在return TRUE之前的都改过,所以在第二次调用时,如果目标在后面能够被找到,就不会出错,因为这次在上次中断的地方接下去扫描的。

授人以渔,不授人以鱼。
2014-10-01 20:55
xiehou314159
Rank: 2
等 级:论坛游民
帖 子:35
专家分:86
注 册:2011-5-11
收藏
得分:0 
回复 11 楼 TonyDeng
这几天都没时间进论坛,学习了,还得加把劲
2014-10-06 23:02
快速回复:C 和指针 程序 6.3 在一组字符串中查找: 版本 2
数据加载中...
 
   



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

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