How to test if a string is a number in the C language?

Asked

Viewed 189 times

0

I’m a beginner in programming.

I am performing an exercise in which I must determine whether a character string is a number, considering that the user can write anything as input. So I created the function below. I can only use the default library. I’m trying to use as few variables as possible.

Someone could evaluate?

int isNumber(char input[], int input_size){

int i;

//Elimina cadeia com caracteres não numéricos
for(i = 1; i < input_size; i++)
{
    if(input[i-1] != '0' && input[i-1] != '1' &&
       input[i-1] != '2' && input[i-1] != '3' &&
       input[i-1] != '4' && input[i-1] != '5' &&
       input[i-1] != '6' && input[i-1] != '7' &&
       input[i-1] != '8' && input[i-1] != '9' &&
       input[i-1] != '.' && input[i-1] != ',' &&
       input[i-1] != ' ' && input[i-1] != '-' &&
       input[i-1] != '\0'){
        return 0;
    }
}

//Elimina cadeia que só possui espaços e caracteres nulos
for(i = 1; i < input_size; i++){
    if(input[i-1] != ' ' && input[i-1] != '\0'){
        break;
    }
}
if(i >= input_size){
    return 0;
}

//Elimina cadeia com mais de um ponto ou vírgula
for(i = 1; i < input_size; i++){
    if(input[i-1] == '.' || input[i-1] == ','){
        for(i++; i < input_size; i++){
            if(input[i-1] == '.' || input[i-1] == ','){
                return 0;
            }
        }
        break;
    }
}

//Elimina cadeia com mais de um sinal de menos
for(i = 1; i < input_size; i++){
    if(input[i-1] == '-'){
        for(i++; i < input_size; i++){
            if(input[i-1] == '-'){
                return 0;
            }
        }
        break;
    }
}

//Elimina cadeia com dois números separados por espaço
for(i = 2; i < input_size; i++){
    if(input[i-2] != ' ' &&
       input[i-2] != '\0' &&
       input[i-1] == ' ' &&
       input[i] != ' ' &&
       input[i] != '\0'){
        return 0;
    }
}

//Elimina cadeia com dois números separados por sinal de menos
for(i = 2; i < input_size; i++){
    if(input[i-2] != ' ' &&
       input[i-2] != '\0' &&
       input[i-1] == '-' &&
       input[i] != ' ' &&
       input[i] != '\0'){
        return 0;
    }
}

//Elimina cadeia terminada em sinal de menos
for(i = input_size; i > 0; i--){
    if(input[i-0] != '\0' && input[i-0] != ' ' && input[i-0] == '-'){
        return 0;
    }
}

//Elimina cadeia que somente tem ponto, vírgula ou sinal de menos
if((input[0] == '.' || input[0] == ',' || input[0] == '-') && (input[1] == ' ' || input[1] == '\0')){
    return 0;
}
for(i = 2; i < input_size; i++){
    if((input[i-2] == ' ' || input[i-2] == '\0') &&
       (input[i-1] == '.' || input[i-1] == ',' || input[i-1] == '-') &&
       (input[i] == ' ' || input[i] == '\0')){
        return 0;
    }
}

return 1;
}

2 answers

1

See if that’s what you wanted.

#include <stdio.h>

int IsNumber( char input[] )
{
    register int i;
    int flagVirgula = 0;

    for(i = 0; input[i]; i++)
    {
        if( !i && !(input[i] - '-') )//Numero negativo
            continue;

        if( (!(input[i] - ',') || !(input[i] - '.')) && !flagVirgula )//só pode posuir uma virgula ou ponto
        {
            flagVirgula = 1;
            continue;
        }

        if( (!(input[i] - ',') || !(input[i] - '.')) )//segunda virgula
            return 0;

        if( (input[i] - '0') < 0 || (input[i] - '0') > 9 )
            return 0;
    }

    return 1;
}

int main()
{   
    char nome[50];

    while(1)
    {
        gets(nome);

        printf("%s\n", IsNumber(nome) ? "E um numero." : "Nao e um numero.");
    }

    return (0);
}
  • 1

    You’re not giving me the exact exit I wanted. But it made me realize that by forcing me to use as few variables as possible, I’m making the logic of my code too complicated and making it difficult to read. Thank you.

  • @CL27 Don’t worry about the number of variables in your code: The compiler will simplify many things to improve the performance of your program, anyway. Try using the number of variables you find necessary, and be descriptive when creating a variable.

  • but worry about simplifying yes - this code is much better than the one presented in the question - in particular pro only go through the sequence once, and not with a loop for each.

  • 1

    and the essential of the answer,q I’m right here, is qeu in C if you can compare characters directly by the code - then the expression ( (input[i] - '0') < 0 || (input[i] - '0') > 9 ) is what really makes all the difference instead of comparing the character with each hard-coded digit.

0


Instead of going through the string several times looking for specific properties, it is best to examine once, considering the properties of a well-formed number:

#include <stdio.h>
#define FLAG_DIGITO_ENCONTRADO 1

int
eh_numero(const char * entrada) {
    unsigned int flags = 0;
    // um número pode ter uma quantidade arbitrária de espaços antes dele
    while (*entrada == ' ') entrada ++;
    // seguido, opcionalmente, de um único sinal de menos
    if (*entrada == '-') entrada ++;
    // seguido de zero ou mais dígitos
    while (*entrada >= '0' && *entrada <= '9') {
        flags |= FLAG_DIGITO_ENCONTRADO;
        entrada ++;
    }
    // se encontrou pelo menos um dígito, o número pode terminar aqui
    if ((flags & FLAG_DIGITO_ENCONTRADO) && *entrada == '\0')
        return 1;
    // senão, vai ter que encontrar um separador decimal
    if (*entrada == '.' || *entrada == ',') entrada ++;
    // Se não houver dígitos antes da vírgula/ponto, precisa de
    // pelo menos um depois do ponto
    if (!(flags & FLAG_DIGITO_ENCONTRADO) && (*entrada < '0' || *entrada > '9'))
        return 0;
    // se houver, pode haver mais zero ou mais dígitos depois do ponto
    while (*entrada >= '0' && *entrada <= '9') entrada ++;

    // finalmente, temos que ter chegado ao fim da sequência, ou
    // ela não é um número
    return (*entrada == '\0');
}

// main para efetuar alguns testes
#define VERIFIQUE(N) printf("A sequência " N " %sé um numero válido\n",\
    eh_numero(N) ? "" : "não ")
int
main(int argc, char ** argv) {
    VERIFIQUE("0");
    VERIFIQUE("         -2.5");
    VERIFIQUE("1.");
    VERIFIQUE(",25");
    VERIFIQUE("3..");
    VERIFIQUE("+1");
    VERIFIQUE("--8");
    VERIFIQUE(",");
    VERIFIQUE("3A");

    return 0;
}

Note that I used a unsigned int to store binary flags. In this case, I only needed one (to save against the case of no digits before or after the comma), but there could be more if we wanted to convert the number into float, for example. In this case, the second flag would be 2, the third 4, the fourth 8, and so on. Bit-to-bit disjunction is used (|) to turn on the flag, and bit-to-bit conjunction (&) to test if it’s on. I could replace it with a simple variable in this case, but I think it’s worth it just to remind people of this possibility.

The result of the tests:

$ cc -o so201793 so201793.c -Wall

$ ./so201793
A sequência 0 é um numero válido
A sequência          -2.5 é um numero válido
A sequência 1. é um numero válido
A sequência ,25 é um numero válido
A sequência 3.. não é um numero válido
A sequência +1 não é um numero válido
A sequência --8 não é um numero válido
A sequência , não é um numero válido
A sequência 3A não é um numero válido

$
  • Impeccable answer. Unfortunately, there are some commands/concepts that I haven’t seen in the C programming classes. So I made a different code, but with this same approach of going through the chain once. Thank you anyway.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.