1、编写程序expr,以计算从命令行输入的逆波兰表达式的值,其中每个运算符或操作数用一个单独的参数表示。例如,命令expr 2 3 4 + * 将计算表达式2×(3+4) 的值。

#include <stdio.h>
#include <stdlib.h> // for atof() #define MAXOP 100 // max size of operand or operator
#define NUMBER '0' // signal that a number was found int getop(char []);
void ungets(char []);
void push(double);
double pop(void); // reverse Polish calculator; uses command line
int main(int argc, char *argv[])
{
char s[MAXOP];
double op2; while(--argc > 0)
{
ungets(" "); // push end of argument
ungets(*++argv); // push an argument switch(getop(s))
{
case NUMBER:
push(atof(s));
break;
case '+':
push(pop() + pop());
break;
case '*':
push(pop() * pop());
break;
case '-':
op2 = pop();
push(pop() - op2);
break;
case '/':
op2 = pop();
if(op2 != 0.0)
push(pop() / op2);
else
printf("error: zero divisor");
default:
printf("error: unknown command %s\n", s);
argc = 1;
break;
}
}
printf("\t%.8g\n", pop());
return 0;
}

这里给出的解决方案是在TCPL Reading Notes 中的逆波兰计算器的基础上得到的。它使用了push 和pop 函数。我们先利用ungets 函数把一个参数结束标记(' ',一个空格字符)和一个参数依次压入输入缓冲区。这样,我们就可以不加修改地使用getop 函数了。getop 将调用getch 读取字符并分离出下一个运算符或操作数。如果在读取参数的过程中遇到了错误,argc 将被设置为1,主函数中的while 循环while(--argc > 0) 将因条件表达式的求值结构为假而终止程序运行。如果来自命令行的是一个合法的表达式,它的计算结果就将被放在堆栈的最顶部,这个结果将在我们把输入参数全部处理完毕后被打印。

2、在TCPL Reading Notes 中第76 条复杂声明中,dcl 程序有很多限制(该程序的目的意在说明问题,并不想做的尽善尽美),它只能处理类似于char 或int 这样的简单数据类型,而无法处理函数中的参数类型或类似于const 这样的限定符。它不能处理带有不必要的空格的情况。由于没有完备的出错处理,因此它也无法处理无效的声明。这里,我们对它进行一定程度上的修改,使它能够处理输入中的错误。

#include <stdio.h>
#include <string.h>
#include <ctype.h> enum { NAME, PARENS, BRACKETS };
enum { NO, YES }; void dcl(void);
void dirdcl(void);
void errmsg(char *);
int gettoken(void); extern int tokentype; // type of last token
extern char token[MAXTOKEN]; // last token string
extern char name[MAXTOKEN]; // identifier name
extern char out[1000];
extern int prevtoken; // dcl: parse a declarator
void dcl(void)
{
int ns; for(ns = 0; gettoken() == '*'; ) // count *'s
ns++;
dirdcl();
while(ns-- > 0)
strcat(out, " pointer to");
} // dirdcl: parse a direct declarstor
void dirdcl(void)
{
int type; if(tokentype == '(') // (dcl)
{
dcl();
if(tokentype != ')')
errmsg("error: missing )\n");
}
else if(tokentype == NAME) // variable name
strcpy(name, token);
else
errmsg("error: expected name or (dcl)\n");
while((type=gettoken()) == PARENS || type == BRACKETS)
if(type == PARENS)
strcat(out, " function returning");
else
{
strcat(out, " array");
strcat(out, token);
strcat(out, " of");
}
} // gettoken.c 源文件
#include <ctype.h>
#include <string.h> enum { NAME, PARENS, BRACKETS };
enum { NO, YES }; extern int tokentype; // type of last token
extern char token[]; // last token string
int prevtoken = NO; // there is no previous token // gettoken: return next token
int gettoken(void) // return next token
{
int c, getch(void);
void ungetch(int);
char *p = token; if(prevtoken == YES)
{
prevtoken = NO;
return tokentype;
}
while((c = getch()) == ' ' || c == '\t')
;
if(c == '(')
{
if((c = getch()) == ')')
{
strcpy(token, "()");
return tokentype = PARENS;
}
else
{
ungetch(c);
return tokentype = '(';
}
}
else if(c == '[')
{
for(*p++ = c; (*p++ = getch()) != ']'; )
;
*p = '\0';
return tokentype = BRACKETS;
}
else if(isalpha(c))
{
for(*p++ = c; isalnum(c = getch()); )
*p++ = c;
*p = '\0';
ungetch(c);
return tokentype = NAME;
}
else
return tokentype = c;
}

我们对函数dirdcl 做了一些修改,它现在能够分析出两种记号——跟在dcl 调用后的一个右括号(')')或一个变量名。如果不是这两种记号,我们将调用函数errmsg 而不是printf。errmsg 会先打印一条出错信息,然后把变量prevtoken 设置为YES 以通知gettoken 说已经读入了一个记号。gettoken 开头部分有一个新的if 语句:

if(prevtoken == YES){
prevtoken = NO;
return tokentype;
}

它的意思是:如果已经有了一个记号,就不要再读入一个新记号了。这个改进版本并不是十全十美的,但它已经具备一定的出错处理能力了。

3、修改TCPL Reading Notes 中第76 条复杂声明中的undcl 程序,使它在把文字描述转换为声明的过程中不会生产多余的圆括号。

#include <stdio.h>
#include <string.h>
#include <ctype.h> #define MAXTOKEN 100 enum { NAME, PARENS, BRACKETS }; void dcl(void);
void dirdcl(void);
int gettoken(void);
int nexttoken(void); int tokentype; // type of last token
char token[MAXTOKEN]; // last token string
char out[1000]; // undcl: convert word description to declation
int main(void)
{
int type;
char temp[MAXTOKEN]; while(gettoken() != EOF)
{
strcpy(out, token);
while((type = gettoken()) != '\n')
if(type == PARENS || type == BRACKETS)
strcat(out, token);
else if(type == '*')
{
if((type = nexttoken()) == PARENS || type == BRACKETS)
sprintf(temp, "(*%s)", out);
else
sprintf(temp, "*%s", out);
}
else if(type == NAME)
{
sprintf(temp, "%s %s", token, out);
strcpy(out, temp);
}
else
printf("invalid input at %s\n", token);
printf("%s\n", out);
}
return 0;
} enum { NO, YES }; int gettoken(void); // nexttoken: get the next token and push it back
int nexttoken(void)
{
int type;
extern int prevtoken; type = gettoken();
prevtoken = YES;
return type;
}

如果"x 是一个指向char 的指针",undcl 程序的输入将是:x * char。改进前的undcl 程序的输出结果是:char (*x)。这里,输出结果中的括号是多余的。事实上,只有当下一个记号是() 或[] 时,undcl 程序才有必要在自己的输出结果中使用括号。

再比如,如果"daytab 是一个指针,它指向一个有[13] 个int 元素的数组",undcl 程序的输入将会是:daytab * [13] int。改进前的程序的输出结果:int (*daytab)[13] 就是正确的。但是,如果"daytab 是一个有[13] 个元素的指针数组,数组中的每个元素分别指向一个int",undcl 程序的输入将是:daytab [13] * int,改进前的undcl 程序的输出结果:int (*daytab[13]) 中就会有多余的圆括号。

我们对undcl 进行了修改,让它检查下一个记号是不是() 或[]。如果下一个记号是() 或[],undcl 程序就必须给它加上括号;否则,输出结果中的括号就将是多余的。也就是说,我们必须根据undcl 中程序输入中的下一个记号来决定是否需要添加括号。

我们编写了一个简单的nexttoken 函数,它将调用gettoken,记录已经读入一个记号的事实并返回该记号的类型。gettoken 是我们在上一个练习中编写的一个函数,它在读入下一个记号前会先检查是否已经有一个可用的记号了。改进后的undcl 程序将不再产生多余的括号。

Pointers and Arrays_4的更多相关文章

  1. Leetcode 笔记 117 - Populating Next Right Pointers in Each Node II

    题目链接:Populating Next Right Pointers in Each Node II | LeetCode OJ Follow up for problem "Popula ...

  2. Leetcode 笔记 116 - Populating Next Right Pointers in Each Node

    题目链接:Populating Next Right Pointers in Each Node | LeetCode OJ Given a binary tree struct TreeLinkNo ...

  3. [LeetCode] Populating Next Right Pointers in Each Node II 每个节点的右向指针之二

    Follow up for problem "Populating Next Right Pointers in Each Node". What if the given tre ...

  4. [LeetCode] Populating Next Right Pointers in Each Node 每个节点的右向指针

    Given a binary tree struct TreeLinkNode { TreeLinkNode *left; TreeLinkNode *right; TreeLinkNode *nex ...

  5. [c++] Smart Pointers

    内存管理方面的知识 基础实例: #include <iostream> #include <stack> #include <memory> using names ...

  6. LEETCODE —— Populating Next Right Pointers in Each Node

    Populating Next Right Pointers in Each Node Given a binary tree struct TreeLinkNode { TreeLinkNode * ...

  7. LeetCode OJ 116. Populating Next Right Pointers in Each Node

    Given a binary tree struct TreeLinkNode { TreeLinkNode *left; TreeLinkNode *right; TreeLinkNode *nex ...

  8. Pointers and Dynamic Allocation of Memory

    METHOD 1: Consider the case where we do not know the number of elements in each row at compile time, ...

  9. LeetCode - Populating Next Right Pointers in Each Node II

    题目: Follow up for problem "Populating Next Right Pointers in Each Node". What if the given ...

随机推荐

  1. Leetcode55. Jump Game跳跃游戏

    给定一个非负整数数组,你最初位于数组的第一个位置. 数组中的每个元素代表你在该位置可以跳跃的最大长度. 判断你是否能够到达最后一个位置. 示例 1: 输入: [2,3,1,1,4] 输出: true ...

  2. c++ 进制转换函数

    转自:https://blog.csdn.net/wangjunchengno2/article/details/78690248 strtol 函数: 它的功能是将一个任意1-36进制数转化为10进 ...

  3. C 语言中 #pragma 的使用

    在所有的预处理指令中,#Pragma指令可能是最复杂的了,它的作用是设定编译器的状态或者是指示编译器完成一些特定的动作.#pragma指令对每个编译器给出了一个方法,在保持与C和C++语言完全兼容的情 ...

  4. 初探 jQuery

    为什么要学习jQuery? 使用javascript开发过程中,有许多的缺点: 1. 查找元素的方法太少,麻烦. 2. 遍历伪数组很麻烦,通常要嵌套一大堆的for循环. 3. 有兼容性问题. 4. 想 ...

  5. python-null

    很早之前,遇到过一个面试官问的python中有没有null,当时有点紧张,想成了None,就脱口而出是有的.今天遇到了none问题,所以就正好说一下. python中是没有NULL的. Python中 ...

  6. Android——系统权限

    Android是一个特权分隔的操作系统,每一个应用程序运行在不同的系统身份中(Linux的user ID和group ID).系统部分和不同的身份被隔离开来.因此,Linux隔离了应用程序(与其它程序 ...

  7. 苹果审核不通过,程序/游戏不兼容IPV6网络

    最近苹果升级的IOS10,所以那边网络环境变成IPV6,如果你的程序不兼容IPV6,苹果的程序会以这个不兼容的原因驳回审核. 那么如何让自己的程序兼容这个?方法其实C#本来已经提供给你的,而且很简单, ...

  8. 使用SQLyog将Mysql中的表导出为Excel

    有时会有这样的需求:将MYSQL数据库中的某个表格导出,存为Excel文件.下面介绍步骤: 1.打开SQLyog,选中要导出的表 2.右键--备份/导出--导出表数据作为... 3.如图选择 Exce ...

  9. 【水滴石穿】ReactNativeDemo

    这个博主他的功底算是特别棒的了,能够把一些基础的例子,通过精巧的方式布局在一个小的demo里面 很值得我学习 放上博主的链接:https://github.com/jianiuqi/ReactNati ...

  10. MaxCompute 助力衣二三构建智能化运营工具

    摘要:本文由衣二三CTO程异丁为大家讲解了如何基于MaxCompute构建智能化运营工具.衣二三作为亚洲最大的共享时装平台,MaxCompute是如何帮助它解决数据提取速度慢.数据口径差异等问题呢?程 ...