Проблемы с чтением файла с помощью fgetc C

Итак, я пишу параллельную проверку решения судоку на C, но, похоже, столкнулся с проблемой чтения в простом старом файле .txt.

Вот код для чтения в файле:

FILE* fp = fopen(argv[1], "r");
if (fp == NULL) {
    printf("Cannot open file\n");
    return 1;
}

//Begin copying file using fgetc
int c;
while ((c = fgetc(fp)) != EOF) {
    for (int i = 0; i < PUZZLE_SIZE; ++i) {
        for (int j = 0; j < PUZZLE_SIZE; ++j) {
            if (c != -38) { //-38 is newline
                //puzzle is a global array of ints
                puzzle[i][j] = c - 48; //handles ASCII to int (1-9) conversion
            }
        }
    }
}
fclose(fp);

Файл .txt выглядит следующим образом:

534678912
672195348
198342567
859761423
426853791
713924856
961537284
287419635
345286179

Когда я печатаю c - 48, я получаю ожидаемые значения; когда я печатаю Puzzle[i][j] внутри циклов, я снова получаю нормальные значения. Однако, когда я потом смотрю на свой массив головоломок, каждое значение устанавливается равным 9; Я не могу, убей меня, понять, почему. Есть ли проблема с памятью/областью действия, о которой я не знаю?


person UnclosedParenthesis    schedule 26.03.2014    source источник
comment
if (c != -38) { //-38 is newline Я искренне сомневаюсь, что --› if (c != '\n') { ...} Также puzzle[i][j] = c - 48; --› puzzle[i][j] = c - '0'; Кстати, if (c == '\n) break; понятнее и надежнее и избегает вложенности.   -  person wildplasser    schedule 27.03.2014
comment
Из-за окружения, пока вы выполняете циклы for для каждого символа в файле, в каждой ячейке сетки, а последний символ в файле оказывается 9... Вам нужно будет просмотреть логику вашего цикла.   -  person fvu    schedule 27.03.2014
comment
Возвращаемое значение из fgetc() будет либо неотрицательным целым числом в диапазоне 0..UCHAR_MAX (обычно 255), либо EOF (обычно -1). Не будет -38 ни при каких известных обстоятельствах.   -  person Jonathan Leffler    schedule 27.03.2014
comment
@Jonathan Leffler: Ну, числа так не работают, либо вы используете char со знаком, поэтому вы можете иметь любое значение от -128 до 127, либо вы используете unsigned char, который может содержать числа только от 0 до 255.   -  person Taiki    schedule 27.03.2014
comment
@Pillsy Редактирование кода могло решить проблему и не должно было быть одобрено. Откат - правильное действие.   -  person Matthew Lundberg    schedule 27.03.2014
comment
@ Тайки Неправильно. В конкретном случае fgetc() страницы руководства явно говорят, что он возвращает значение символа, приведенного к unsigned char или EOF. Это работает именно так, потому что EOF всегда отрицательно; это позволяет реализациям, использующим отрицательные символы, справиться с этим - в противном случае EOF может быть неправильно интерпретирован как допустимый символ. Таким образом, fgetc() всегда возвращает положительное значение или отрицательную константу, обозначающую EOF.   -  person Filipe Gonçalves    schedule 27.03.2014
comment
@Taiki Избегайте редактирования кода. Возможно, вы исправляете ошибку, которая является причиной проблемы.   -  person Matthew Lundberg    schedule 27.03.2014
comment
@Taiki: наоборот. ISO/IEC 9899:2011 7.21.7.1 Функция fgetc гласит: [...] функция fgetc получает этот символ как unsigned char, преобразованный в int[...] (Реализация может законно использовать -38 в качестве EOF, но ни одна известная реализация этого не делает.)   -  person Jonathan Leffler    schedule 27.03.2014
comment
EOF (-1) представлен в двоичном виде следующим образом: 11111111, что является тем же представлением, что и 255. Попробуйте: ((char) -1 == (char) 255). Вы можете установить char на любое значение, 255, например -38, но результат будет зависеть от того, интерпретируете ли вы значение как знаковое или беззнаковое.   -  person Taiki    schedule 27.03.2014
comment
@Taiki c - это int, а не char. Тип возвращаемого значения из fgetc() также является типом int.   -  person wildplasser    schedule 27.03.2014
comment
@Taiki: в этом утверждении так много заблуждений и проблем, что это больно. Достаточно сказать, что я не согласен с вашим анализом.   -  person Jonathan Leffler    schedule 27.03.2014
comment
@Taiki Если вы предполагаете 2 дополнения, да. Но для 255 обратите внимание, что при повышении до int оно будет содержать ведущие нули, в отличие от того, что происходит с -1.   -  person Filipe Gonçalves    schedule 27.03.2014
comment
@FilipeGonçalves: c - это int, а не char. Тип возвращаемого значения из fgetc() также является типом int. Здесь ничего не рекламируется.   -  person wildplasser    schedule 27.03.2014
comment
@wildplasser Хем, неправильный выбор слова. Я не имел в виду продвижение в техническом смысле.   -  person Filipe Gonçalves    schedule 27.03.2014
comment
Не видел, что c было int... тогда неважно, я думал, что код частично сработал, потому что -38 уменьшилось до какого-то законного значения...   -  person Taiki    schedule 27.03.2014


Ответы (1)


По сути, ваша программа делает следующее: Для каждого символа в файле (while) установите ВСЕ (for, for) записи головоломки на этот символ. В результате все записи будут содержать последний символ файла.

Вы хотите поместить for петли снаружи и вместо этого читать по одному символу на каждую запись головоломки:

for (int i = 0; i < PUZZLE_SIZE; ++i)
    for (int j = 0; j < PUZZLE_SIZE; ++j) {
        c = fgetc(fp);
        if (c == '\n')
            c = fgetc(fp); // get a new char if we hit a newline
         puzzle[i][j] = c - `0`;
    }

Предполагается, что в файле достаточно символов для заполнения головоломки.

person Elmar Peise    schedule 26.03.2014
comment
Вы можете усилить тестирование. Во внутреннем цикле, если символ не является цифрой, это ошибка. После внутреннего цикла (но до конца внешнего цикла) можно было прочитать следующий символ; если это не новая строка, это ошибка. - person Jonathan Leffler; 27.03.2014
comment
Хорошие идеи. Однозначно рекомендую их реализовать. Однако для этого ответа я намерен решить только исходную проблему без добавления функциональности. - person Elmar Peise; 27.03.2014