После записи в файл из массива символов он говорит: «Была проблема с открытием файла» - PullRequest
0 голосов
/ 15 февраля 2019

Я пишу программу, которая должна перевернуть половину файла.

Например:

Ввод: abcdefgh

Выход: abcdhgfe

Итак, моя программа получает данные от пользователя и сохраняет их вфайл.Используя fseek, я получаю длину ввода и создаю массив символов этой длины плюс 1. В другом массиве я храню вторую половину ввода в обратном порядке.Проблема в том, что программа записывает некоторые странные символы в файл.После открытия файла появляется сообщение об ошибке: There was a problem opening the file “filename”. The file you opened has some invalid characters..Как я могу решить эту проблему?

#include <stdio.h>
#include <string.h>

int main() {
    int fsize; 
    char fname[15];
    char data[fsize+1];

    printf("Enter the name of file you want to create: ");
    scanf("%s", fname);

    FILE *fp;
    fp = fopen(fname, "w+");

    printf("Enter data for that file: ");
    scanf("%s", data);
    fprintf(fp, "%s", data);

    fseek(fp, 0L, SEEK_END); // get length of file
    fsize = ftell(fp);
    fseek(fp, 0L, SEEK_SET); // go back to the beginning of file

    int j = 0, m = (fsize / 2) + 1;
    char data2[m];

    for (int k = fsize - 1; j < k; j++, k--) {
        data2[j] = data[k];
    }
    for (int i = 0; i < fsize / 2; i++) {
        printf("%c", data2[i]);
    }
    printf("\n");
    fprintf(fp, "%s", data2);
    fclose(fp);
    return 0;
}

Ответы [ 2 ]

0 голосов
/ 15 февраля 2019

Как сказал Лукас Кестлер в своем ответе:

в

char data[fsize+1];

fsize неизвестно, поэтому поведение не определено, используйте фиксированный размеркак вы делаете для fname .

Всегда защищайте свой (f) скан, ограничивая считываемую длину, чтобы оставаться в буфере

Но также:

Проверьте fopen результат.

Избегайте использования переменных размеров массива, и на самом деле вам не нужно data2 .

Если честно, я не понимаю, почему вы пишете в файл, чтобы узнать размервходные данные, это строка, просто используйте strlen

Вы пропустили запись первой половины данных в файл, и data2 не завершено нулемпоэтому fprintf(fp,"%s",data2); имеет неопределенное поведение

Вы не управляете должным образом пустыми данными, содержащими только 1 символ.

Ваша программа может быть:

#include <stdio.h>
#include <string.h>

int main()
{
  char fname[15];
  char data[100];

  printf("Enter the name of file you want to create: ");
  scanf("%14s", fname);

  printf("Enter data for that file: ");
  scanf("%99s", data);

  size_t sz = strlen(data);

  if (sz < 2) {
    puts("data too small");
    return -1;
  }

  FILE *fp = fopen(fname, "w+");

  if (fp == NULL) {
    printf("cannot open %s\n", fname);
    return -1;
  }

  size_t m = sz/2;
  size_t i;

  for (i = 0; i != m; ++i) {
    putchar(data[i]);
    fputc(data[i], fp);
  }

  for (i = sz - 1; i >= m; --i) {
    putchar(data[i]);
    fputc(data[i], fp);
  }
  putchar('\n');
  fputc('\n', fp);

  fclose(fp);
  return 0;
}

Компиляция ивыполнение:

pi@raspberrypi:~ $ gcc -g -pedantic -Wextra f.c
pi@raspberrypi:~ $ ./a.out
Enter the name of file you want to create: aze
Enter data for that file: a
data too small
pi@raspberrypi:~ $ ./a.out
Enter the name of file you want to create: aze
Enter data for that file: az
az
pi@raspberrypi:~ $ cat aze
az
pi@raspberrypi:~ $ ./a.out
Enter the name of file you want to create: aze
Enter data for that file: aze
aez
pi@raspberrypi:~ $ cat aze
aez
pi@raspberrypi:~ $ ./a.out
Enter the name of file you want to create: aze
Enter data for that file: azerty
azeytr
pi@raspberrypi:~ $ cat aze
azeytr
pi@raspberrypi:~ $ ./a.out
Enter the name of file you want to create: aze
Enter data for that file: abcdefgh
abcdhgfe
pi@raspberrypi:~ $ cat aze
abcdhgfe

Выполнение под valgrind , всегда используйте его, когда можете

pi@raspberrypi:~ $ valgrind ./a.out
==5321== Memcheck, a memory error detector
==5321== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==5321== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==5321== Command: ./a.out
==5321== 
Enter the name of file you want to create: aze
Enter data for that file: az
az
==5321== 
==5321== HEAP SUMMARY:
==5321==     in use at exit: 0 bytes in 0 blocks
==5321==   total heap usage: 4 allocs, 4 frees, 6,496 bytes allocated
==5321== 
==5321== All heap blocks were freed -- no leaks are possible
==5321== 
==5321== For counts of detected and suppressed errors, rerun with: -v
==5321== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 3)
pi@raspberrypi:~ $ valgrind ./a.out
==5322== Memcheck, a memory error detector
==5322== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==5322== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==5322== Command: ./a.out
==5322== 
Enter the name of file you want to create: aze
Enter data for that file: azertyu
azeuytr
==5322== 
==5322== HEAP SUMMARY:
==5322==     in use at exit: 0 bytes in 0 blocks
==5322==   total heap usage: 4 allocs, 4 frees, 6,496 bytes allocated
==5322== 
==5322== All heap blocks were freed -- no leaks are possible
==5322== 
==5322== For counts of detected and suppressed errors, rerun with: -v
==5322== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 3)
pi@raspberrypi:~ $ 
0 голосов
/ 15 февраля 2019

Первая ошибка - строка char data[fsize+1], потому что fsize не был инициализирован.Также размер массива не известен во время компиляции, и поэтому вы должны использовать malloc / calloc, как описано в этом посте .Это также верно для строки char data2[m].

Также, как правило, следует стараться избегать scanf, поскольку ввод имени файла длиннее 14 символов приведет к переполнению буфера fname и приведет к неправильному поведению, см. этот пост .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...