V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
KickTR
V2EX  ›  程序员

[C++]指针被莫名其妙修改了……

  •  
  •   KickTR · 2013-09-29 22:05:11 +08:00 · 4918 次点击
    这是一个创建于 4075 天前的主题,其中的信息可能已经有所发展或是发生改变。
    先别急着吐槽下面这段代码有多烂_(:з」∠)_(因为老师教的时候就有问题我还傻愣愣地按照老师的那套思路去做)
    在学校机房的VC++6上调试会有问题,自己的Ubuntu上eclipse调试也是同样的问题:指针被莫名其妙修改了。

    主要就是输入数字模拟抽取手牌的过程,手上如果有相同的牌就把手上的牌扔掉,没有的话就按从小到大排序好。

    #include <iostream>
    #include <malloc.h>
    using namespace std;

    typedef struct card
    {
    int data;
    struct card *next;
    } aCard, *list;
    ——————下面可以忽略(应该没问题吧?)——————
    int insertc(list handcard)
    {
    aCard inputcard;
    list p;
    cin>>inputcard.data;
    inputcard.next=NULL;
    p=handcard;
    //check first card
    if (handcard->next==NULL)
    {
    cout<<"1st card"<<endl;
    handcard->next=&inputcard;
    return 0;
    }
    while(p->next->data<inputcard.data && p->next!=NULL)
    {
    p=p->next;
    }

    //add card at the end
    if (p->next->next==NULL)
    {
    p->next->next=handcard;
    return 0;
    }

    //delete card;
    if (p->next->data==inputcard.data)
    {
    list q;
    q=p->next;
    p->next=p->next->next;
    free(q);
    cout<<"free a card"<<endl;
    return 0;
    }

    //insertcard
    if (p->next->data<inputcard.data)
    {
    inputcard.next=p->next->next;
    p->next->next=&inputcard;
    }
    return 0;
    }

    list createlist()
    {
    list Clist;
    Clist=(card*)malloc(sizeof(card));
    Clist->data=0;
    Clist->next=NULL;
    return Clist;
    }
    ——————上面可以忽略——————
    int main()
    {
    list handcard,p;
    handcard=createlist();
    p=handcard;
    for (int i=0;i<5;i++)
    {
    insertc(handcard);
    while (p->next)
    {
    //重点在这里
    //一旦执行了下面任何一句话都会使得后一句指针p的指向内容以及next被修改掉,使得p=p->next这句毫无意义并且废掉了p
    //本意是为了抓取一次新牌后就打印一次手里的所有牌,结果发现指针莫名其妙被修改
    //因为*p和*handcard指向相同空间所以handcard里面的内容也会被改掉
    //————问题代码——————
    //printf("1234");
    //cout<<p->data<<" "<<endl;
    //cout<<"anything"<<endl;
    //————(end)————
    p=p->next; //单独执行这句就不会有问题,不过一旦while结束后继续执行后面的代码指针p指向内容也会瞬间乱掉
    }
    cout<<endl;
    }
    return 0;
    }

    为什么随便打印点东西都会让p指向混乱呢?试着单步跟每次都是跟到while开始下一句执行时p就乱了。
    另外,其实main函数是有点问题的还没完全调试好,不能正确连续打印手牌,不过和上面所述问题无关,我只想知道为什么执行一下输出都会扰乱指针p的内容
    相当纠结,本人水平很弱,特此处女贴来求助……
    21 条回复    1970-01-01 08:00:00 +08:00
    SErHo
        1
    SErHo  
       2013-09-29 22:19:39 +08:00 via Android   ❤️ 1
    你的代码中createlist 返回的到底是个什么东西?编译时不会报错,警告吗?
    SErHo
        2
    SErHo  
       2013-09-29 22:26:32 +08:00 via Android
    @SErHo 哦,对不起,看错了。
    zorceta
        3
    zorceta  
       2013-09-29 22:36:01 +08:00 via Android
    C++为嘛不上new/delete
    pomelowu
        4
    pomelowu  
       2013-09-29 22:38:13 +08:00   ❤️ 1
    aCard inputcard;
    是局部變量。
    SErHo
        5
    SErHo  
       2013-09-29 22:38:37 +08:00 via Android   ❤️ 1
    主要就是插入节点的时候用的是局部变量inputcard,你应该使用malloc。
    raptium
        6
    raptium  
       2013-09-29 22:39:13 +08:00
    你为你 createlist 返回的东西在 stack 里
    不在 heap 里
    raptium
        7
    raptium  
       2013-09-29 22:39:25 +08:00
    因为*
    leunggamciu
        8
    leunggamciu  
       2013-09-29 22:39:31 +08:00
    上GDB,上单步,当你最终发现问题的时候你会有一种豁然开朗和想一刀捅死自己的感觉!
    raptium
        9
    raptium  
       2013-09-29 22:42:47 +08:00   ❤️ 1
    哦 说错了 不是 createlist,是 insertcard 里插入的东西
    嗯 都是一个意思= =
    pathletboy
        10
    pathletboy  
       2013-09-29 22:45:21 +08:00   ❤️ 1
    int insertc(list handcard)
    {
    aCard inputcard;
    list p;
    cin>>inputcard.data;
    inputcard.next=NULL;
    p=handcard;
    //check first card
    if (handcard->next==NULL)
    {
    cout<<"1st card"<<endl;
    handcard->next=&inputcard;
    return 0;
    }

    妥妥的有问题 ,你inputcard是局部变量。
    frogs
        11
    frogs  
       2013-09-29 23:05:19 +08:00
    gcc -S
    xdeng
        12
    xdeng  
       2013-09-30 00:24:28 +08:00 via iPhone
    查查字节对齐 这也是一个很坑爹的问题
    lukic
        13
    lukic  
       2013-09-30 08:55:34 +08:00
    @raptium
    @pathletboy
    正解。
    helayzhang
        14
    helayzhang  
       2013-09-30 08:57:53 +08:00
    9L正解
    chchwy
        15
    chchwy  
       2013-09-30 09:30:15 +08:00
    http://www.v2ex.com/t/74249 [V2EX技巧] 贴图和贴代码的方法
    KickTR
        16
    KickTR  
    OP
       2013-09-30 15:53:24 +08:00
    @SErHo @raptium @pathletboy @pomelowu @lukic @helayzhang 感谢各位的相助,的确是局部变量问题,new之后就没事了。
    这段代码其实还有诸多小错误,现在都已经差不多修正好了。

    @zorceta 因为老师上课时是用VC演示,使用的cpp,但是代码正文却混合了c和c++极其不规范,还采用h头文件,他是用的malloc,当时我还不太了解,后来查了之后才知道c++中应该使用new不再需要malloc。这个老师的编程习惯也很不好,经常没有对齐的,哎。

    @chchwy thx~

    感谢各位相助。不过我还是有一点不太明白,在单步跟踪时,既然inputcard是局部变量,完成了插入节点函数之后为什么对应inputcard的连在链表上的数据没有被立即销毁(变量监视中看到的)?而且可以继续在主函数里单独执行p=p->next,变量监视中也能显示正确连上去
    pathletboy
        17
    pathletboy  
       2013-09-30 16:06:17 +08:00   ❤️ 1
    @KickTR 内存销毁不是你想象的不可访问,只是在编译器中标记了这段内存无主了,其他人可以使用,局部变量是在堆栈中的,堆栈是编译器为线程申请的一块内存,一般为2M,由ebp/esp寄存器控制进行访问,在同个线程中,堆栈是给该线程调用的所有函数复用的。
    KickTR
        18
    KickTR  
    OP
       2013-09-30 16:21:55 +08:00
    @pathletboy 谢谢,意思是不是说,局部变量在所在函数结束后,变量对应空间的内容没有被立即清零,只是变量对应空间被标注可用,所以空间里存储的数据可能仍然存在,但是内容所处空间会随时可能被任何其他函数调用导致内容被修改?
    pathletboy
        19
    pathletboy  
       2013-09-30 16:26:36 +08:00   ❤️ 1
    @KickTR 嗯,是这样,如果没有其他函数对你那块堆栈值修改,那块内存你就可以一直使用,这有点像一块公共区域,你放置了一个东西,在其他人没搬走丢弃你的东西之前,你一直可以使用。
    KickTR
        20
    KickTR  
    OP
       2013-09-30 16:36:56 +08:00
    @pathletboy 十分感谢!
    kelvin_fly
        21
    kelvin_fly  
       2013-10-01 09:36:37 +08:00
    @KickTR 释放掉不代表清零,也不会清零。 请查询free的具体意义。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1300 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 23:32 · PVG 07:32 · LAX 15:32 · JFK 18:32
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.