A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

本文参考C陷阱与缺陷,帮你彻底解决自增自减在程序设计中的问题。
大神绕道!不惜勿喷,我就是一个小菜鸟,发表一下自己的认识和理解!
书中说明:如果编译器的输入流截止某个字符之前都已经被分解为一个个符号,name下一个符号将包括从该字符之后可能组成的一个符号的最长字符串。
什么意思呢?给大家看俩我写的小小的测试代码:
#include<stdio.h>
int main()
{
        int a=4;
        int *p=NULL;
        int r=0;
        p=&a;
        r=8/*p;                 //这句是重点
        printf("%d\n",r);
        return 0;
}
如上,大家觉得输出结果是什么呢……
好了,不买关子了,结果是:代码出错了!!!
#include<stdio.h>
int main()
{
        int a=4;
        int *p=NULL;
        int r=0;
        p=&a;
        r=8/ *p;            //再看这句加了一个空格
        printf("%d\n",r);
        return 0;
}
然后结果为2,正常结束!
为什么呢???因为编译器遇到/*,便默认为注释的起始位置,然后当然出错了!这个叫做代码的准二义性问题。加了空格之后,编译器便从左到右依次读数据,首先读到操作数8,继续遇到“/”,编译器没明白这是一个运算符,继续,读到空格,编译器便认为“/”是一个二元运算符号,于是乎,编译器继续傻傻的读,寻找第二个操作数,遇到“*”,编译器傻傻的吧这个作为“*”运算符,可是编译器记得如果是“*”运算符,那么之前读入的“/”,就没法解释了,于是编译器认为这是一个指针,再继续,遇到p,再继续遇到分号,编译器明白了,这就是*p,于是进行运算!
再来看一道刚入门的小伙伴经常遇到的问题:
#include<stdio.h>
int main()
{
        int a=2;
        int r=0;
        r=++a + ++a + ++a;
        printf("%d\n",r);
        return 0;
}
思考:输出结果是什么呢?………….
结果是:13
不知道与你想的一样不,不一样?放心,我来告诉你怎么回事!
首先,编译器从左到右傻傻的读,遇到“++”,单目运算符,接着找第一个操作数,遇到a,在接着读遇到“+”双目运算符,哈哈,这次编译器明白了++a是一个自增运算,由于先进行“++”,所以a先自增1,此时a=3,;此时遇到了“+”双目运算符,编译器有找到了第一个操作数,于是接着寻找第二个操作数。
遇到“++”,同理,继续,遇到a,在继续遇到“+”,此时,编译器明白前面的两个数是操作数,由于先进行“++”,所以a先自增1,此时a=4;然后编译器,不继续进行下去了,因为两个操作数已经找到了,而且下一个运算符为“+”,优先级一样,此时计算机便先进行计算,4+4=8;OK!(想知道为什么这时酒宴进行计算吗?这就是贪心原则!)
继续进行,先前已经遇到了“+”双目运算符,于是同理,编译器找到了第一个操作数8,继续如上述那样执行,a自增1后再运算,此时a=5;这是两个操作数找到,最后计算8+5=13;运行结束,赋值给r;
以上所述皆为本人对那句话的理解,如有高见,还请分享!


以上所述其实就是编译器执行代码时的贪心原则,编译器总是一旦遇到可以解决的运算,并且判断之后的运算级别对当前运算不造成影响,就尽可能的先执行、运算,在继续想下执行!
看到这里我出现一个问题?为什么计算机会准确的计算呢?于是呼我开始解决这个问题,计算机计算各种运算,本质就是入栈和出栈操作,然后结合贪心原则和运算符的优先级,然后开始执行操作和运算!
由于本人比较懒,就去问了以为美女大神!于是呼她给了我她写的贪心算法计算器的原代码,我贴出来跟大家分享下!
   此法分析中的贪心算法/*************************************************************************
    > 转载请注明出处http://blog.csdn.net/acvcla/article/details/41732447
    > File Name: evaluator.cpp
    > Author: acvcla
    > version 1.01
    > QQ:acvcla@gmail.com  
    > Mail: acvcla@gmail.
    > Created Time: 2014年11月17日 星期一 23时34分13秒
    >本计算器支持加减乘除四种运算,支持浮点,输入表达式后,按回车计算结果
    >退出请输入EOF(win下按ctrl+z,linux下按ctrl+d)
    >代码在G++环境下编译通过,推荐使用codeblocks编译运行,强烈不推荐VC++6.0
    >若没有codeblocks,可以使用dev c++或者VS2010以上版本
*************************************************************************/  
#include<iostream>  
#include<string>  
#include<cctype>  
using namespace std;  
const int init_size=10;  
const int maxn=100005;  
#define Debug  
template <typename T>  
struct Stack  
{  
    string name;  
    T *base,*top;  
    int size;  
    Stack(const string s="None"):name(s)/*初始化栈*/  
    {  
        top=base=new T[size=init_size];  
    }  
    void Expansion();  
    void push(T e)/*入栈*/  
    {  
        Expansion();  
        #ifdef Debug  
        cout<<name<<"    push       "<<e<<endl;  
        #endif  
        *top++=e;  
    }  
    T & Top()const/*取栈顶引用*/  
    {  
        return *(top-1);  
    }  
    bool empty()const/*判断栈是否为空*/  
    {  
        return base==top;  
    }  
    T pop()/*返回栈顶元素并出栈*/  
    {  
        if(empty()) {  
            cout<<name<<" is empty"<<endl;  
            return T(NULL);  
        }  
        #ifdef Debug  
        cout<<name<<"    pop        "<<*(top-1)<<endl;  
        #endif  
        return *(--top);  
    }  
};  
  
  
template<typename T>  
void Stack<T>::Expansion()/*扩容函数*/  
{  
    if(top-base>=size) {  
            T *newbase= new T[size<<=1];/*成倍增加减少均摊复杂度,均摊O(1)*/  
            int i=0;  
            while(base+i!=top)*(newbase+i)=*(base+i);/*复制到新开辟的空间*/  
            delete base;/*释放旧的空间*/  
            base=newbase;  
        }  
}  
void readnum(char *&S,Stack<double>&f)/*从S中读取数字并将S指向数字后的第一个操作符*/  
{  
    double tmp=0,c=1;  
    int found=0;  
    while(isdigit(*S)||*S=='.') {  
        if(*S=='.'){  
            found=1;  
            S++;  
            continue;  
        }  
        if(found)c*=10;  
        tmp=tmp*10+(*S)-'0';  
        S++;  
    }  
    f.push(tmp/c);  
}  
double calcu(double a,char op,double b)/*计算a op b*/  
{  
    switch(op){  
        case '+':return a+b;  
        case '-':return a-b;  
        case '*':return a*b;  
        case '/':return a/b;  
    }  
}  
int optoi(const char op)/*将操作符转成数字*/  
{  
    switch(op) {  
        case '+':return 0;  
        case '-':return 1;  
        case '*':return 2;  
        case '/':return 3;  
        case '(':return 4;  
        case ')':return 5;  
        case '\0':return 6;  
    }  
}  
char oderbetween(const char a,const char b)/*判断操作符优先级*/  
{  
    const int op_kind=10;  
    const char pri[op_kind][op_kind]=  
    {  
        ">><<<>>",  
        ">><<<>>",  
        ">>>><>>",  
        ">>>><>>",  
        "<<<<<= ",  
        "       ",  
        "<<<<< ="  
    };  
    return pri[optoi(a)][optoi(b)];  
}  
double evaluate(char *S)/*算法主过程*/  
{  
    Stack<double>opnd("opnd");/*操作数栈*/  
    Stack<char>optr("optr");/*操作符栈*/  
    optr.push('\0');  
    while(!optr.empty()){  
        if(isdigit(*S)||*S=='.')readnum(S,opnd);/*读取数字*/  
        else{  
            if(*S==' ') {  
                S++;  
                continue;  
            }  
            switch(oderbetween(optr.Top(),*S)) {/*根据优先级进行计算*/  
                case '<':optr.push(*S);S++;break;  
                case '=':optr.pop();S++;break;  
                case '>': {  
                    char op=optr.pop();  
                    double opnd2=opnd.pop(),opnd1=opnd.pop();  
                    opnd.push(calcu(opnd1,op,opnd2));  
                    break;  
                }  
  
            }  
        }  
    }  
    return opnd.pop();  
}  
char exptr[maxn];/*表达式数组*/  
int main(int argc, char const *argv[])  
{  
    while(cin>>exptr) {  
        cout<<evaluate(exptr)<<endl;  
    }  
    return 0;  
}  

评分

参与人数 1技术分 +1 黑马币 +3 收起 理由
Micro + 1 + 3 很给力!继续加油

查看全部评分

8 个回复

正序浏览
Chenli 中级黑马 2015-3-10 14:25:29
9#
学习了,分析有想法
回复 使用道具 举报
代码怎么是C++?
回复 使用道具 举报
多谢各位捧场,随后我把自己对指针哪里的理解贴出来,跟大家分享下
回复 使用道具 举报
楼猪好厉害。。
回复 使用道具 举报
ljymm 来自手机 中级黑马 2015-3-7 15:54:04
报纸
点赞,点赞,点赞
回复 使用道具 举报
谢谢分享    。。。 。。。{:2_31:}
回复 使用道具 举报
不错,说的有点意思,继续加油 看好你
回复 使用道具 举报
雨漪 来自手机 中级黑马 2015-3-7 14:17:34
沙发
楼主好厉害啊
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马