K&R 4章 演習問題4.1~4.6

#include <stdio.h>

int strindex(const char *, const char *);
int strrindex(const char *, const char *);

int main(void)
{
    const char s[] = "I am a boy. and you are a girl nobody calls us teenagers. So what?";
    const char t[] = "boy";

    int i1, i2;
    i1 = strindex(s, t);
    i2 = strrindex(s, t);

    printf("%d\n", i1);
    printf("%d\n", i2);
    return(0);
}

int strindex(const char * s, const char * t)
{
    int i, j, k;

    for (i = 0; s[i] != '\0'; i++){
        for (j = i, k = 0; t[k] != '\0' && s[j] == t[k]; j++, k++)
            ;
        if (k > 0 && t[k] == '\0')
            return(i);
    }
    return(-1);
}


int strrindex(const char * s, const char * t)
{
    int i, j, k;

    for (i = 0; s[i] != '\0'; i++){
        k = i;
        j = 0;
        while (s[k] == t[j])
            k++, j++;

        if (j > 0 && t[j] == '\0')
                return(k-1);
    }
    return(-1);
}


/* notice where j is initialized, which is wrong */ 
int strrindex2(const char * s, const char * t)
{
    int i, j, k;

    j = 0;
    for (i = 0; s[i] != '\0'; i++){
        k = i;

        while (s[k++] == t[j++])
            ;
        if (j > 0 && t[j] == '\0')
                return(k-1);
    }
    return(-1);
}

#include <stdio.h>
#include <ctype.h>

double atof(char *);
double atof2(char *);

int main(void)
{
    char s[] = "22.2e-2";
    double answer;
    answer = atof2(s);
    printf("answer is %f\n", answer);
    return(0);
}

double atof(char * s)
{
    double val, power;
    int i, sign;

    for (i = 0; isspace(s[i]); i++)
        ;
    sign = (s[i] == '-')? -1: 1;
    if (s[i] == '+' || s[i] == '-')
        i++;
    for (val = 0.0; isdigit(s[i]); i++)
        val = 10.0 * val + (s[i] - '0');
    if (s[i] == '.')
        i++;
    for (power = 1.0; isdigit(s[i]); i++){
        val = 10.0 * val + (s[i] - '0');
        power *= 10.0;
    }
    return(sign * val / power);
}


double power1(int, int);
/*expand the function which handles science notation
like 123.45e-6 */
double atof2(char * s)
{
    double val, power;
    int i, val2, sign1, sign2;

    for (i = 0; isspace(s[i]); i++)
        ;
    sign1 = (s[i] == '-')? -1: 1;
    if (s[i] == '+' || s[i] == '-')
        i++;
    for (val = 0.0; isdigit(s[i]); i++)
        val = 10.0 * val + (s[i] - '0');
    if (s[i] == '.')
        i++;
    for (power = 1.0; isdigit(s[i]); i++){
        val = 10.0 * val + (s[i] - '0');
        power *= 10.0;
    }
    if (s[i] == 'e')
        i++;
    sign2 = (s[i] == '-')? -1: 1;
    if (s[i] == '+' || s[i] == '-')
        i++;
    for (val2 = 0.0; s[i] != '\0'; i++)
        val2 = 10.0 * val2 + (s[i] - '0');

    return(sign1 * val / power) * power1(10, (sign2 * val2)) ;
}


double power1(int base, int n)
{
    int i;
    double p;

    p = 1.0;
    if (n >= 0){
        for (i = 1; i <= n; ++i)
            p = p * base;
        return p;
    }
    else
        for (i = 1; i <= -n; i++)
            p = p / base;
        return p;
}

逆ポーランド記法の電卓を実装する一連の問題。 4-3, モジュロ演算子オペランドは2つともint型しかとらない。

負数を表す単項演算子-はそれを読み込んだ時に、スタックから2つめをポップせずして判断したい。なぜなら2つめをポップした時点で‘stack empty‘ のエラーメッセージが出てしまう。

4-4, 引数にdoubleのポインタをとるprint_copy_exchange関数を実装。

4-5,

4-6

ここではI/Oプログラミングにおいてとても大切なことが示唆されている気がするので抜粋。

プログラムでは入力を読み過ぎてみないと、じゅうぶんに入力を読んだかどうかが決められない場合が多い。一例は数値を作り上げる文字を集めるときである。数値は、最初の非数字があらわれるまでは、完結しない。このため、本来数字ではない文字をひとつ余計にプログラムで読む必要がある。

この必要性にかられて、バッファの配列が用意される。ストリームから次の1文字をとってくるのは関数getchで、そのときに最初にバッファ配列をチェックして、そこに文字が存在するならそれを返す、なければストリームからとってきてそれを返す。文字をバッファ配列にしまっておくのは関数ungetchである。

f:id:agongji:20200621234240p:plain

これができたらふつうの電卓実装にもチャレンジしてみる。

/*implement a reverse poland calculator*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define MAXOP 100
#define NUMBER '0'

int getop(char []);
void push(double);
double pop(void);

int main(void)
{
    int type;
    double op1, 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;

        /*dont want to represent stack emptyerror
       when uniry operator */
        case '-':
            op2 = pop();
            if(op1 = pop())
                push(op1 - op2);
            else
                push(-op2);
            break;

        case '/':
            op2 = pop();
            if (op2 != 0.0)
                push(pop() / op2);
            else
                printf("error: zero divisor\n");
            break;
        case '%':
            op2 = pop();
            if (op2 != 0.0)
                push((int)pop() % (int)op2);
            else
                printf("error: zero divisor\n");
            break;

        case '\n':
            printf("\t%.8g\n", pop());
            break;
        default:
            printf("error: unknown command %s\n", s);
            break;
        }
    }
    return(0);
}

#define MAXVAL 100

int sp = 0;
double bufcopy;
double val[MAXVAL];

/*push f to stack*/
void push(double f)
{
    if (sp < MAXVAL)
        val[sp++] = f;
    else
        printf("error: stack full, can not push %g\n", f);
}

/*pop the top value from stack*/
double pop(void)
{
    if (sp > 0)
        return val[--sp];
    else {
        printf("error: stack empty\n");
        return(0.0);
    }
}

void print_copy_exchange(double * buf)
{
    printf("top is %f\n", val[sp]);
    *buf = val[sp];
    val[sp] = val[sp-1];
    val[sp-1] = *buf;
}



#include <stdio.h>
#include <ctype.h>

int getch(void);
void ungetch(int);

int getop(char s[])
{
    int i, c;

    while ((s[0] = c = getch()) == ' ' || c == '\t')
        ;
    s[1] = '\0';
    if (!isdigit(c) && c != '.')
        return(c);
    i = 0;
    if (isdigit(c))
        while (isdigit(s[++i] = c = getch()))
            ;
    s[i] = '\0';
    if (c != EOF)
        ungetch(c);
    return(NUMBER);
}


#define BUFSIZE 100

char buf[BUFSIZE];
int bufp = 0;

int getch(void)
{
    return (bufp > 0)? buf[--bufp]: getchar();
}

void ungetch(int c)
{
    if (bufp >= BUFSIZE)
        printf("ungetch: too many characters\n");
    else
        buf[bufp++] = c;
}

いくつかの基本的な疑問点:

if(pop())

このときpopは実行されているのだろうか?