Chapter 4– Functions and Program Structure of TCPL (Part 10)

Chapter 4 – Functions and Program Structure

Exercise 4-1

Write the function strrindex(s,t) , which returns the position of the rightmost occurrence of t in s , or -1 if there is none.

#include <stdio.h>

 

/* strrindex: which returns the position of the rightmost

occurrence of t in s , or -1 if there is none. */

int strrindex(char s[], char t);

 

int main() {   

    char testchar = 'n';

    char teststr[] = "goodmorning";

    printf("test string = %s/n", teststr);

    printf("  test char = %c/n", testchar);

    printf("result:/n");

    printf("   expected = 9/n");

    printf("       real = %d/n",strrindex(teststr, testchar));

    return 0;

}

 

int strrindex( char s[], char t ) {

    int i, count;

   

    for(i=0, count = -1; s[i] != '/0'; i++) {

        if(s[i] == t)

            count = i;      

    }   

    return count;

}

 

Exercise 4-2

Extend atof to handle scientific notation of the form 123.45e-6 where a floating-point number may be followed by e or E and an optionally signed exponent.

#include <ctype.h>

#include <math.h>

#include <stdio.h>

 

/* atof2: convert string s to double */

double atof2(char s[]);

 

char  *strings[] = {

    "1.0e43",

        "999.999",

        "123.456e-9",

        "-1.2e-3",

        "1.2e-3",

        "-1.2E3",

        "-1.2e03",

        "cat",

        "",

        0

};

int  main(void)

{

    int i = 0;

    for (; *strings[i]; i++)

        printf("atof(%s) = %g/n", strings[i], atof2(strings[i]));

    return 0;

}

 

double atof2(char s[]) {

    double val, power, epart;

    int i, sign, esign;

   

    for (i = 0; isspace(s[i]); i++); /* skip space */

    sign = (s[i] == '-' ? -1 : 1);

    if (s[i] == '+' || s[i] == '-')  /* skip the sign */

        i++;                               

    for (val = 0.0; isdigit(s[i]); i++)

        val = 10.0 * val + (s[i] - '0');

    if (s[i] == '.')                 /* skip the decimal part */

        i++;

    for (power = 1.0; isdigit(s[i]); i++) {

        val = 10.0 * val + (s[i] - '0');

        power *= 10.0;

    }

   

    if (s[i] == 'e' || s[i] == 'E') /* skip the e/E notation */

        i++;

    esign = (s[i] == '-' ? -1 : 1);

    if (s[i] == '+' || s[i] == '-')  /* skip the esign */

        i++;

   

    for (epart = 0.0; isdigit(s[i]); i++) {

        epart = 10.0 * epart + (s[i] - '0');

    }   

   

    return sign * val / power * pow(10, (esign * epart));

}

Exercise 4-3

Given the basic framework, it's straightforward to extend the calculator. Add the modulus ( % ) operator and provisions for negative numbers.

int main(void)

{

    int type;

    double op2;

    char s[MAXOP];

   

    while((type = getop(s)) != EOF)

    {

        switch(type)

        {

        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/n");

            break;

        case '%':

            op2 = pop();

            if (op2) {

                push(fmod(pop(), op2));

            }

            else

                printf("error: mod by zero/n");

            break;

        case '/n':

            printf("/t%.8g/n", pop());

            break;

        default:

            printf("error: unknown command %s/n", s);

            break;

        }

    }   

    return 0;

}

 

/* getop: get next operator or numeric operand */

int getop(char s[])

{

    int i = 0, c, next;

   

    while((s[0] = c = getch()) == ' ' || c == '/t')

        ;   

    s[1] = '/0';

 

    /* not a number but may contain a unary minus.*/

    if(!isdigit(c) && c != '.' && c != '-')

        return c;

 

    if (c == '-') {

        next = getch();

        if (!isdigit(next) && next != '.')

            return c;

        c = next;

    }

    else c = getch();

    /* collect integer part */

    while(isdigit(s[++i] = c))

        c = getch();

  

    if(c == '.') {

        while(isdigit(s[++i] = c = getch()))

            ;

    }

   

    s[i] = '/0';

    if(c != EOF)

        ungetch(c);

    return NUMBER;

}

 

Exercise 4-4

Add commands to print the top element of the stack without popping, to duplicate it, and to swap the top two elements. Add a command to clear the stack.

 

Exercise 4-5

Add access to library functions like sin , exp , and pow . See <math.h> in Appendix B, Section 4.

#include <stdio.h>

#include <stdlib.h>

#include <math.h>

#include <ctype.h>

#include <string.h>

 

#define MAXOP      100  /* max size of operand or operator */

#define NUMBER     '0'  /* signal that a number was found */

#define IDENTIFIER 1    /* signal that identifier like sin, cos was found */

 

/* getop: get next operator or numeric operand */

int getop(char []);

/* push: push a element from the stack */

void push(double);

/* pop: pop a element from the stack */

double pop(void);

 

/* added by exe4_4 */

 

/* showtop: print top element without pop it */

void showtop(void);

/* swapitems: swap the top twp elements of the stack */

void swapitems(void);

/* duplicate: duplicate the top element of the stack */

void duplicate(void);

/* clearstack: clear the stack */

void clearstack(void);

 

/* added by exe4_5 */

/* accesslib: access to lib func like sin, cos etc. */

void accesslib(char []);

 

/* reverse Polish calculator */

 

int main(void)

{

    int type;

    double op2;

    char s[MAXOP];

   

    while((type = getop(s)) != EOF)

    {

        switch(type)

        {

        case NUMBER:

            push(atof(s));

            break;

        case IDENTIFIER:

            accesslib(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/n");

            break;

        case '%':

            op2 = pop();

            if (op2) {

                push(fmod(pop(), op2));

            }

            else

                printf("error: mod by zero/n");

            break;

        case '~':      

            clearstack();

            break;      

        case '!':

            duplicate();

            break;

        case '@':    

            swapitems();

            break;      

        case '#':

            showtop();

            break;

        case '/n':

            printf("/t%.8g/n", pop());

            break;

        default:

            printf("error: unknown command %s/n", s);

            break;

        }

    }

   

    return 0;

}

 

#define MAXVAL  100 /* maximum depth of val stack */

 

int sp = 0; /* next free stack position */

double val[MAXVAL]; /* value stack */

 

/* push: push f onto value stack */

void push(double f)

{

    if(sp < MAXVAL)

        val[sp++] = f;

    else

        printf("error: stack full, can't push %g/n", f);

}

 

/* pop: pop and return top value from stack */

double pop(void)

{

    if(sp > 0)

        return val[--sp];

    else

    {

        printf("error: stack empty/n");

        return 0.0;

    }

}

 

/* print the top element without popping */

void showtop(void)

{

    if(sp > 0)

        printf("Top of stack contains: %8g/n", val[sp-1]);

    else

        printf("The stack is empty!/n");

}

 

/* duplicate the top element */

void duplicate(void)

{

    double temp = pop();

   

    push(temp);

    push(temp);

}

 

/* swap the top two element */

void swapitems(void)

{

    double item1 = pop();

    double item2 = pop();

   

    push(item1);

    push(item2);

}

 

/* pop only returns a value if sp is greater than zero. So setting the

stack pointer to zero will cause pop to return its error */

 

void clearstack(void)

{

    sp = 0;

}

 

void accesslib(char s[]) {

    double op2;

   

    if( 0 == strcmp(s, "sin"))

        push(sin(pop()));

    else if( 0 == strcmp(s, "cos"))

        push(cos(pop()));

    else if (0 == strcmp(s, "exp"))

        push(exp(pop()));

    else if(0 == strcmp(s, "pow"))

    {

        op2 = pop();

        push(pow(pop(), op2));

    }

    else

        printf("%s is not a supported function./n", s);

   

}

int getch(void);

void ungetch(int);

 

/* getop: get next operator or numeric operand */

int getop(char s[])

{

    int i = 0, c, next;

   

    while((s[0] = c = getch()) == ' ' || c == '/t')

        ;   

    s[1] = '/0';

   

    if(isalpha(c))

    {

        i = 0;

        while(isalpha(s[i++] = c ))

            c = getch();

        s[i - 1] = '/0';

        if(c != EOF)

            ungetch(c);

        return IDENTIFIER;

    }

   

    /* not a number but may contain a unary minus.*/

    if(!isdigit(c) && c != '.' && c != '-')

        return c;

   

    if (c == '-') {

        next = getch();

        if (!isdigit(next) && next != '.')

            return c;

        c = next;

    }

    else c = getch();

    /* collect integer part */

    while(isdigit(s[++i] = c))

        c = getch();

   

    if(c == '.') {

        while(isdigit(s[++i] = c = getch()))

            ;

    }

   

    s[i] = '/0';

    if(c != EOF)

        ungetch(c);

    return NUMBER;

}

 

#define BUFSIZE 100

 

char buf[BUFSIZE]; /* buffer for ungetch */

int bufp = 0; /* next free position in buf */

 

int getch(void) /* get a (possibly pushed back) character */

{

    return (bufp > 0) ? buf[--bufp] : getchar();

}

 

void ungetch(int c) /* push character back on input */

{

    if(bufp >= BUFSIZE)

        printf("ungetch: too many characters/n");

    else

        buf[bufp++] = c;

}

 

  Exercise 4-7

Write a routine ungets(s) that will push back an entire string onto the input. Should ungets know about buf and bufp , or should it just use ungetch ?

/* K&R Exercise 4-7 */

/* Solved by Steven Huang */

 

#include <string.h>

#include <stdio.h>

 

#define BUFSIZE 100

 

char buf[BUFSIZE];  /* buffer for ungetch */

int bufp = 0;       /* next free position in buf */

 

/* get a (possibly pushed back) character */

int getch(void);

/* push character back on input */

void ungetch(int c);

/* push s back on input */

void ungets(const char *s);

 

int main(void)

{

    char *s = "hello, world.  this is a test.";

    int c;

   

    ungets(s);

    while ((c = getch()) != EOF)

        putchar(c);

    return 0;

}

 

/* get a (possibly pushed back) character */

int getch(void) {

    return (bufp > 0) ? buf[--bufp] : getchar();

}

 

/* push character back on input */

void ungetch(int c) {

    if(bufp >= BUFSIZE)

        printf("ungetch: too many characters/n");

    else 

        buf[bufp++] = c; 

}

 

/*

ungets() actually takes a little bit of thought.  Should the

first character in "s" be sent to ungetch() first, or should

it be sent last?  I assumed that most code calling getch()

would be of this form:

 

  char array[...];

  int i;

  while (...) {

  array[i++] = getch();

  }

  In such cases, the same code might call ungets() as:

  ungets(array);

and expect to repeat the while loop to get the same string back.

This requires that the last character be sent first to ungetch()

first, because getch() and ungetch() work with a stack.

 

To answer K&R2's additional question for this problem, it's

usually preferable for something like ungets() to just build

itself on top of ungetch(). This allows us to change ungetch()

and getch() in the future, perhaps to use a linked list instead,

without affecting ungets().

*/

void ungets(const char *s) {   

    size_t i = strlen(s);   

    while (i > 0)

        ungetch(s[--i]);

}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值