Как сделать проверку на то чтобы в веденной строке была лишь одна запятая/точка?

Имею вот подобный код, который запускает цикл чтобы проверить введенные в строку числа, в дальнейшем строка преобразуется в double через atof если числа в строке подойдут под условия. Я написал замену запятых на точку и выдачу ошибки если больше двух точек подряд, но столкнулся с непониманием того как мне написать адекватное условие для проверки есть ли в числе есть еще точки(кроме как написать одну длинную строку где будет провекра от stra[a]=='.' до stra[a+15]=='.') и если есть то уже выдать опять же ошибку. Помогите пожалуйста:(

#include < stdlib.h >
#include <math.h>

int main() {
    char stra[15];
    double numbera = 0;
    int a = 0;
    int error1=0;
        do {
            error1 = 0;
            printf("Enter a(maximum 15 - digit number) : \n");
            gets(stra);
            while (stra[a] != '\0') {
                
                if (stra[a] == ',' && a <= 15) {

                    stra[a] = '.';
                }
                else if (stra[a] == '.' && stra[a + 1] == '.' && stra[a+2] != '\0' ||) {
                    printf("Error, not correct number \n");
                    error1 = 1;
                    a1 = 0;
                    break;
                }
                else if (a > 15) {
                    printf("The number is too large(more than 15 digits) \n");
                    error1 = 1;
                    a = 0;
                    break;

                }
                ++a;
            }
            if (atof(stra) <= 0) {
                printf("The number is negative \n");
                error1 = 1;
            }

        } while (error1 > 0);```
    numbera = atof(stra);
}

Ответы (1 шт):

Автор решения: Stanislav Volodarskiy

Интерактивный ввод, даже из консоли, не большое удовольствие. Задача разбита на части.

int read_double(FILE *f, double *d) читает вещественное число из файла. Она возвращает код ошибки:

  • RD_OK - всё в порядке, число в *d;
  • RD_ERROR_FILE_FAILURE - чтение из файла не удалось. Обычно это фатальная ошибка;
  • RD_ERROR_WORD_TOO_LONG - слишком длинный ввод. Его можно было бы объединить со следующим, но сделано так как было в вопросе;
  • RD_ERROR_INVALID_FORMAT - непонятный формат. Функция попыталась прочитать с точкой, с запятой, ничего не получилось.

read_double пропускает пробелы и читает слово длиной до 98 символов. Слова длиннее считаются ошибкой. Если слово слишком длинное, его хвост пропускается до следующего пробела. Иначе оставшийся мусор может вызвать ложное срабатывание следующего ввода.

Функция main запускает read_double в цикле до первого успеха. Кроме ошибок выше, она ещё проверяет что число ≥ 0. Это не та ошибка, которую следует тащить в read_double, которая занимается только чтением и форматами.

#include <ctype.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>


#define RD_OK                   0
#define RD_ERROR_FILE_FAILURE   1
#define RD_ERROR_WORD_TOO_LONG  2
#define RD_ERROR_INVALID_FORMAT 3

int read_double(FILE *f, double *d) {
    // read word from file
    char buffer[100];
    if (fscanf(f, "%99s", buffer) != 1) {
        return RD_ERROR_FILE_FAILURE;
    }

    // check word length
    if (strlen(buffer) == 99) {
        // word is too long to be actual double literal
        // skip until next whitespace
        while (true) {
            int c = fgetc(f);
            if (c == EOF) {
                break;
            }
            if (isspace(c)) {
                ungetc(c, f);
                break;
            }
        }
        return RD_ERROR_WORD_TOO_LONG;
    }

    double dd;
    int n;

    // try to scan as it is
    if (sscanf(buffer, "%lf%n", &dd, &n) == 1 && n == (int)strlen(buffer)) {
        *d = dd;
        return RD_OK;
    }

    // replace comma with point
    char *p = strchr(buffer, ',');
    if (p == NULL) {
        return RD_ERROR_INVALID_FORMAT;
    }
    *p = '.';

    // try to scan modified string
    if (sscanf(buffer, "%lf%n", &dd, &n) == 1 && n == (int)strlen(buffer)) {
        *d = dd;
        return RD_OK;
    }

    return RD_ERROR_INVALID_FORMAT;
}

int main() {
    bool ok = false;
    double d;
    while (!ok) {
        printf("enter double: ");
        switch (read_double(stdin, &d)) {
        case RD_OK:
            if (d < 0) {
                fprintf(stderr, "ERROR: negative value. Try again.\n");
            } else {
                ok = true;
            }
            break;
        case RD_ERROR_FILE_FAILURE:
            fprintf(stderr, "FATAL: input stream is broken.\n");
            exit(1);
            break;
        case RD_ERROR_WORD_TOO_LONG:
            fprintf(stderr, "ERROR: value is too long. Try again.\n");
            break;
        case RD_ERROR_INVALID_FORMAT:
            fprintf(stderr, "ERROR: invalid format. Try again.\n");
            break;
        default:
            fprintf(stderr, "ERROR: unknown error. Try again.\n");
            break;
        }
    }
    printf("entered %lf\n", d);
}

Компилируем:

$ gcc temp.c 

Запускаю и сразу закрываю входной поток чтобы получить ошибку файла:

$ ./a.out
enter double: FATAL: input stream is broken.

Все ошибки кроме ERROR: unknown error.:

$ ./a.out
enter double: 1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
ERROR: value is too long. Try again.
enter double: 1.2.3
ERROR: invalid format. Try again.
enter double: -123
ERROR: negative value. Try again.
enter double: 123
entered 123.000000

Разные запятые:

$ ./a.out
enter double: 12.3
entered 12.300000

$ ./a.out
enter double: 12,3
entered 12.300000
→ Ссылка