0

I am writing a program that have to reverse half of a file.

For example:

Input: abcdefgh

Output: abcdhgfe

So, here my program gets from user input and stores in a file. Using fseek I get the length of input and create an array of characters of that length plus 1. In another array I'm storing the second half of input in reversed order. The problem is, program writes some weird characters to file. After opening a file error shows up saying: There was a problem opening the file “filename”. The file you opened has some invalid characters.. How can I solve this problem?

#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;
}
chqrlie
  • 131,814
  • 10
  • 121
  • 189

2 Answers2

4

The first mistake is the line char data[fsize+1] because fsize has not been initialized. Also the size of the array is not known at compile time and thus you should use malloc/calloc as described in this post. This is also true for the line char data2[m].

Also you should generally try to avoid scanf because entering a filename longer than 14 characters would overflow your buffer fname and lead wrong behaviour, see this post.

Lukas Koestler
  • 328
  • 3
  • 10
2

As it what said by Lukas Koestler in his answer :

in

char data[fsize+1];

fsize is unknown, so the behavior is undefined, use a fixed size like you do for the fname.

Always protect your (f)scanf limiting the length read to stay in the buffer

But also :

Check fopen result.

Avoid the use of variable array dimension, and in fact you do not need data2.

To be frank I do not understand why you write in the file to know the size of the input data, it is a string, just use strlen

You missed to write the first half of the data in the file, and data2 is not null terminated so fprintf(fp,"%s",data2); has an undefined behavior

You do not manage properly empty data of data having only 1 char.

Your program can be :

#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;
}

Compilation and execution :

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

Execution under valgrind, always use it it when you can

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:~ $ 
bruno
  • 32,421
  • 7
  • 25
  • 37