Нарушение доступа при использовании fscanf_s

#c #scanf

#c #scanf

Вопрос:

Я хочу прочитать файл в определенном формате, поэтому я использую fscanf_s и цикл while. Но как только fscanf_s обрабатывается, программа завершает работу с нарушением доступа (0xC0000005).

Вот код:

 FILE *fp;
errno_t err = fopen_s(amp;fp, "C:\data.txt", "r");

if (err != 0)
    return 0;

int minSpeed = 0;
int maxSpeed = 0;
char axis = '@';

while(!feof(fp)) 
{
    int result = fscanf_s(fp, "%c;%d-%dn", amp;axis, amp;minSpeed, amp;maxSpeed);

    if (result != 3)
        continue;
}

fclose(fp);
  

Содержимое файла основано на строках, например:

 -;10000-20000
X;500-1000
S;2000-2400
  

Кто-нибудь может мне помочь?

Комментарии:

1. Что? нет feof_s() или fclose_s() ? Действительно, *_s функции хуже, чем функции с простыми именами: они требуют тех же проверок и позволяют вам чувствовать себя в безопасности, когда вы этого не делаете. Я предлагаю вам не использовать их из-за ложного чувства безопасности и того факта, что они недоступны во многих реализациях, из-за чего ваши программы работают только на ограниченном подмножестве возможных компьютеров.

2. @pmg Я не использую feof_s amp; fclose_s, потому что они не определены. Но удаление этого _s из fscanf_s сделало свое дело. Теперь это работает! 🙂 Спасибо!

3. Да, у меня возникла та же проблема, когда я попробовал небольшую тестовую программу. Странные это маленькие функции!

4. feof_s() и fclose_s() были шуткой (смехотворно); по-видимому, правильный вызов fscanf_s() был бы fscanf_s(fp, "%c;%d-%dn", amp;axis, 1, amp;minSpeed, amp;maxSpeed); с дополнительным значением 1 для размера axis «массива». Не используйте *_s функции!

5. @pmg: вы должны указать это в качестве ответа 🙂

Ответ №1:

По-видимому, fscanf_s() требуется параметр размера после адреса переменной

 fscanf_s(fp, "%c;%d-%dn", amp;axis, 1, amp;minSpeed, amp;maxSpeed);
/* extra 1 for the size of the   ^^^ axis array */
  

Но я предлагаю вам не использовать *_s функции: они хуже, чем функции с простыми именами — они требуют тех же проверок и позволяют вам чувствовать себя в безопасности, когда вы этого не делаете. Я предлагаю вам не использовать их из-за ложного чувства безопасности и того факта, что они недоступны во многих реализациях, из-за чего ваши программы работают только на ограниченном подмножестве возможных компьютеров.

Используйте обычный fscanf()

 fscanf(fp, "%c;%d-%dn", amp;axis, amp;minSpeed, amp;maxSpeed);
/* fscanf(fp, ";%d-%dn", amp;axis, amp;minSpeed, amp;maxSpeed); */
/* default 1   ^^^    same as for fscanf_s                 */
  

И ваше использование feof() неверно.
fscanf() Возвращает EOF при возникновении ошибки (ошибка конца файла или сопоставления или ошибка чтения …).

Вы можете использовать, feof() чтобы определить причину fscanf() сбоя, а не проверять, произойдет ли сбой при следующем вызове.

 /* pseudo-code */
while (1) {
    chk = fscanf();
    if (chk == EOF) break;
    if (chk < NUMBER_OF_EXPECTED_CONVERSIONS) {
        /* ... conversion failures */
    } else {
        /* ... all ok */
    }
}
if (feof()) /* failed because end-of-file reached */;
if (ferror()) /* failed because of stream error */;
  

Ответ №2:

Если вы считаете, что файл (data.txt ) существует, ваше приложение, вероятно, не запущено с текущим каталогом, установленным в том месте, где находится файл. Это привело бы к сбою функции fopen_s().

Комментарии:

1. Верно, но fopen_s выполняется успешно, я проверил это в отладчике Visual studio.