Voici une question du premier examen «Introduction à la programmation» de l'année dernière à mon université:

En utilisant la fonction getchar(), lisez une séquence d'entrée composée de nombres, signes + et -. La sortie doit être le résultat de ces opérations arithmétiques.

Par exemple, si l'entrée est 10+13-12+25-5+100, la sortie doit être 131.

Maintenant que j'ai un peu d'expérience en C avant d'aller à l'université, ce problème semble facile à résoudre en utilisant des pointeurs, des tableaux, etc.

Mais voici le hic: sur l'examen, vous ne pouvez utiliser que des choses que les élèves ont appris jusqu'à présent. Et étant donné que cet examen n'a lieu qu'un mois après le début de l'année scolaire, vos options sont assez limité.

Vous ne pouvez utiliser que des variables, des éléments d'entrée / sortie de base, des opérateurs (logiques et au niveau du bit), des instructions conditionnelles et des boucles, des fonctions .

Cela signifie non: tableaux, chaînes, pointeurs, récursion, structures ou tout autre élément qui facilite les choses.

Comment diable est-ce que je fais ça? Aujourd'hui, c'est la deuxième fois que je passe 3 heures à essayer de résoudre ce problème. Je l'ai résolu avec succès, mais seulement après avoir "triché" et utilisé des tableaux, des fonctions de chaîne (strtol) et des pointeurs. Il est important pour moi de savoir comment le résoudre selon les règles, car j'aurai des choses similaires sur l'examen à venir.

Edit: mes tentatives jusqu'à présent ont consisté à utiliser la boucle while combinée avec getchar() pour l'entrée, après quoi je reste bloqué. Je n'ai pas la moindre idée de ce que je devrais faire sans utiliser plus "d'outils".

4
David Ilic 29 oct. 2020 à 20:32

3 réponses

#include <string.h>
#include <stdio.h>

void operate(int * sum, int * n, char todo) {
    if (todo == 1)        *sum += *n;
    else if (todo == -1)  *sum -= *n;
    printf("%s %d\n", todo == 1 ? "ADD :" : "SUB :", *n); 
    *n = 0; 
}

int main()
{
    char * problem = "10+13-12+25-5+100";
    int len = strlen(problem);
    int i=0;
    char c;
    int n = 0;
    int sum = 0;
    char todo = 1;
    while(i < len)
    {
        c = problem[i++];
        if (c < 48 || c >= 58) 
        {
            // Adds or subtracts previous and prepare next
            operate(&sum, &n, todo);
            if (c == '+') todo = 1; 
            else if  (c == '-') todo = -1; 
        } 
        else
        {
            // Collects an integer
            if (n) n *= 10;
            n += c - 48;
        } 
    }
    operate(&sum, &n, todo); // Last pass

    printf("SUM => %d\n", sum); // => 131
    return 0;
}
1
dspr 29 oct. 2020 à 18:07
#include <stdio.h>

void do_operation(char next_operation, int * result, int * number){
    if (next_operation == '+'){
        *result += *number;
        *number = 0;
    } else if (next_operation == '-'){
        *result -= *number;
        *number = 0;
    } else {
        printf("Unknown operation error.");   
    }
}

int main(int argc, char *argv[]){

    char c;
    int number = 0;
    int result = 0;
    char next_operation = '+';

    do {
        c = getchar();
        if( c >= '0' && c <= '9' ){
            number = number * 10 + c - 48;
        } else if (c == '+'){
            do_operation(next_operation, &result, &number);
            next_operation = '+';
        } else if (c == '-'){
            do_operation(next_operation, &result, &number);
            next_operation = '-';
        } else {
            do_operation(next_operation, &result, &number);
        }
    } while (c != '\n');

    printf("%d", result);
}
1
Najiva 29 oct. 2020 à 19:08

Lors de l'écriture d'un analyseur, je me trouve généralement que je "tamponne" la prochaine opération qui "sera effectuée". Lorsque l'entrée change d'état - vous lisez des chiffres, mais ensuite vous lisez une opération - alors vous exécutez l'action "tamponnée" et mettez en mémoire tampon l'opération suivante qui sera effectuée dans le futur.

Exemple:

10+13-12
^^        - we read 10
  ^       - result=10  - we buffer that we *will* have to do + in the future
   ^^     - reading 13
     ^    - och we stopped reading numbers!
            we execute _buffered_ operation `+` , so we do result += 13
            and buffer `-` to be done in the future
      ^^  - we read 12
        ^ - och, EOF! we execute buffered operation `-` , so we do result -= 12
          - etc.

Le code:

#include <stdio.h>
int main() {
    int result = 0; // represents current result
    int temp = 0; // the temporary number that we read into
    int op = 0; // represents the _next_ operation that _will_ be done
    while (1) {
        int c = getchar();
        switch (c) {
        // we read an operation, so we should calculate _the previous_ operation
        // or this is end of our string
        case '+': case '-': case EOF:
            if (op == 0) {
                // we have nothing so far, so start with first number
                result = temp;
            } else if (op == '+') {
                result += temp;
            } else if (op == '-') { 
                result -= temp;
            }
            // the next operation we will do in future is stored in op
            op = c;
            // current number starts from 0
            temp = 0;
            break;
        case '0': case '1': case '2': case '3': case '4':
        case '5': case '6': case '7': case '8': case '9':
            // read a digit - increment temporary number
            temp *= 10;
            temp += c - '0';
            break;
        }
        // we quit here, the result for last operation is calculated above
        if (c == EOF) {
            break;
        }
    }
    printf("%d\n", result);
   
    // As I see it was mentioned that "%d\n" is a string,
    // here's the simplest algorithm for printing digits in a number.
    // Extract one digit from the greatest position and continue up
    // to the last digit in a number.

    // Take negative numbers and throw them out the window.
    if (result < 0) {
         putchar('-');
         result = -result;
    }
    // Our program currently supports printing numbers up to 10000.
    int divisor = 10000;
    // 000100 should print as 100 - we need to remember we printed non-zero
    int was_not_zero = 0;
    while (divisor != 0) {
        // extract one digit at position from divisor
        int digit = result / divisor % 10;
        // if the digit is not zero, or
        // we already printed anything
        if (digit != 0 || was_not_zero) {
            // print the digit
            putchar(digit + '0');
            was_not_zero = 1;
        }
        // the next digit will be to the right
        divisor /= 10;
    }
    putchar('\n');
}
2
KamilCuk 29 oct. 2020 à 18:14