fgetc() не может читать с плавающей точкой

У меня большая проблема с использованием fgetc(), и я не могу понять это... Я пытаюсь разобрать текстовый файл, все компилируется, но при выполнении я получил бесконечный цикл или segfault (Code::blocks), мой текстовый файл выглядит так: {"USD_EUR": "0.8631364", "EUR_USD": "1.3964719"} с 16 изменениями курса. Я стараюсь поставить все мои поплавки в курс [16]...

void read(float change[4][4], char* myFile)
{

    FILE* file = NULL;
    file = fopen(myFile, "r+");
    int value,i;
    float rate[16];
    char* str = "";
    if (file != NULL)
    {
        do
        {
            value = fgetc(file);
            printf("%c \n",value);
            while(value > 48 && value < 57)
            {
                value = fgetc(file);
                strcat(str, value);
                //printf("%s \n", str);
            }
            rate[i] = atof(str);
            i++;
            str = "";
        }while(value != EOF);// 125 = }  
        change[0][1] = rate[5];
        change[0][2] = rate[0];
        change[0][3] = rate[15];
        change[1][0] = rate[6];
        change[1][1] = rate[14];
        change[1][2] = rate[7];
        change[1][3] = rate[10];
        change[2][0] = rate[8];
        change[2][1] = rate[2];
        change[2][2] = rate[12];
        change[2][3] = rate[4];
        change[3][0] = rate[3];
        change[3][1] = rate[13];
        change[3][2] = rate[11];
        change[3][3] = rate[9];
        fclose(file);
    }
    else
    {
        printf("Unable to read the file!\n");
    }
}

Я также пробую с EOF, но у меня есть только символ до чисел, который выходит из цикла, например: {"USD_EUR": "

4 ответа

Решение

Я предлагаю вам просто использовать fscanf,

Например

FILE *file;
int i = 0, status;
float value;
float rate[16];

file = fopen(myFile, "r");
if(file == NULL){
    printf("Unable to read the file!\n");
    return ;
}
while((status=fscanf(file, "%f", &value))!=EOF){
    if(status==1){
        rate[i++] = value;
        if(i==16)//full
            break;
    } else {
        fgetc(file);//one character drop
    }
}
fclose(file);

В дополнение к решениям, представленным в других ответах, при чтении грязной строки ввода для чтения может быть проще использовать функции ввода, ориентированные на строки, предоставляемые libc (например fgets или же getline). Чтение данных по одной строке в буфер, часто (не всегда) обеспечивает большую гибкость при анализе данных с помощью других инструментов, предоставляемых libc (например strtok, strsep, так далее..)

Для других данных лучше выбрать символьно-ориентированный ввод. В вашем случае, линии были переплетены с многочисленными '"', ':', ' ' а также ',' "S. Это затрудняло построение fscanf форматировать строку, чтобы прочитать оба обменных курса за один вызов или использовать любой из инструментов синтаксического анализа строки, таких как strtok, Так что это был действительно тяжелый вызов. Я согласен, решение BluePixyes для разбора одного float в fscanf Звонок это хорошее решение. Линейно-ориентированной альтернативой является чтение строки за раз, а затем использование strtof преобразовать значения с плавающей точкой, найденные в строке. Единственное преимущество, которое strtof обеспечивает проверку ошибок при конвертации, которая позволяет вам проверить хорошую конвертацию с плавающей запятой. Это один из подходов для линейно-ориентированного решения:

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>

int main () {

    FILE* file = NULL;              /* aways initialize variables   */
    float rate[16] = {0.0};         /* market rates 1st & 2nd       */
    char myFile[50] = {0};          /* input filename               */
    char line[128] = {0};           /* input line buffer            */
    char *p = NULL;                 /* pointer to parse line        */
    char *ep = NULL;                /* pointer to parse line        */
    size_t idx = 0;                 /* index for rate array values  */
    size_t it = 0;                  /* general index iterator       */

    /* prompt for filename  */
    printf ("\n Please enter filename to read rates from: ");
    scanf ("%[^\n]%*c", myFile);

    /* open & validate file */
    file = fopen (myFile, "r");
    if (!file) {
        fprintf(stderr, "error: Unable to read the file!\n");
        return 1;
    }

    /* using line-oriented input to read line, then parse */
    while (fgets (line, 127, file) != NULL)
    {
        if (idx == 16) {
            fprintf (stderr, "warning: array full.\n");
            break;
        }

        p = line;                           /* parse line for floats    */
        while (*p) {                        /* find first digit or end  */
            while (*p && (*p < 48 || *p > 57) ) p++;
            if (!*p) break;                 /* validate not null        */
            rate[idx++] = strtof (p, &ep);  /* get float, set end-ptr   */
            if (errno != 0 || p == ep)      /* validate conversion      */
                fprintf (stderr, "discarding: rate[%zd] invalid read\n", --idx);
            p = ep;                         /* set ptr to end-ptr       */
        }
    }

    fclose (file);

    printf ("\n The exchange rates read from file:\n\n");
    for (it = 0; it < idx; it++)
        printf ("  rate[%2zd]  =  %9.7f\n", it, rate[it]);

    printf ("\n");

    return 0;
}

образец ввода:

$ cat dat/rates.txt
"USD_EUR": "0.8631364", "EUR_USD": "1.3964719"
"USD_AGT": "0.9175622", "EUR_USD": "1.0975372"
"USD_BRZ": "0.8318743", "EUR_USD": "1.1713074"
"USD_COL": "0.9573478", "EUR_USD": "1.0537964"
"USD_GIA": "0.7904234", "EUR_USD": "1.5393454"

выход:

$ ./bin/read_xchgrates

 Please enter filename to read rates from: dat/rates.txt

 The exchange rates read from file:

  rate[ 0]  =  0.8631364
  rate[ 1]  =  1.3964719
  rate[ 2]  =  0.9175622
  rate[ 3]  =  1.0975372
  rate[ 4]  =  0.8318743
  rate[ 5]  =  1.1713074
  rate[ 6]  =  0.9573478
  rate[ 7]  =  1.0537964
  rate[ 8]  =  0.7904234
  rate[ 9]  =  1.5393454

Примечание: проверьте ваш strtof справочная страница для любых дополнительных #define Ваш компилятор может потребовать.

Проблема 1:

char* str = "";

Объявляет str как указатель на статическую строку. Это создает буквальный "" в памяти и очках str к этому, который не является чем-то, что вы можете безопасно изменить. Вы хотите что-то вроде

char str[30] = "";

Проблемы 2 и 3:

strcat(str, value);

Попытки добавить в str, который не является безопасным или правильным. Также, как отмечает гость, вы пытаетесь strcat(char *, int), который не является правильным использованием. strcat(char *, char *) верно. Примечание - это не значит, что вы должны strcat(str, (char *) &value); - вам нужно понять, как строки реализованы как char массивы в C, особенно в отношении нулевого завершения.

Проблема 4:

str = "";

Смотрите комментарий user3629249 выше. При условии правильного заявления,

str[0] = '\0';

Было бы правильно.

Проблема 5:

Опять же, с кредитом для пользователя 3629249,

в 'change' изменение позиции [0][0] пропускается.

Код имеет следующую последовательность:

Fgetc приводит к "U",

это не значение в диапазоне от 0 до 9 исключений, поэтому попытайтесь преобразовать str в rate [i]

(где 'i' не было инициализировано с известным значением)

Так как цифры не были сохранены в точках str, некоторое неизвестное смещение от rate[] устанавливается в 0 (это неопределенное поведение)

тогда неизвестное значение 'i' увеличивается и выполняется следующая строка: str = ""

который не влияет на строку (если каждый литерал не находится в другом месте в разделе.const)

и внешний цикл повторяется.

В конце концов, вводится символ в диапазоне 1...8

Затем во внутреннем цикле эта первая цифра пропускается, и читается другой символ.

из вашего примера, что следующий символ - это "." Что может привести к выходу из внутреннего цикла

Тем не менее, строка: strcat(str, значение); должно вызвать событие сбоя сегмента из-за попытки записи в раздел.const исполняемого файла

Другие вопросы по тегам