-2
#include <stdio.h>

struct my_struct {
    char text[100];
} e;

int main() {
    FILE *file;

    file = fopen("filename", "ab+");

    if (file == NULL) {
        file = fopen("filename", "wb+");
    }

    printf("Input text: ");

    fflush(stdin);
    gets(e.text);

    fwrite(&e, sizeof(e), 1, file);

    fclose(file);

    return 0;
}

What I'm trying to do here is create a binary file and write the file by text input from the user. The code works fine! The only problem is that the file contains spaces, which I believe is due to the array size of struct my_structure that fwrite passes while writing the file. I cannot find a good way to remove spaces or replace fwrite. Thank you! for answering this question.

Program Output:

Input text: holiday

File Output:

686f 6c69 6461 7900 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 
chqrlie
  • 131,814
  • 10
  • 121
  • 189
Lucky
  • 19
  • 3
  • 4
    Two (unrelated) things: First of all ***never ever*** use `gets`. It's a dangerous function and have even been removed from the C standard. Use e.g. [`fgets`](http://en.cppreference.com/w/c/io/fgets) instead. Secondly, passing an input-only stream like `stdin` to the [`fflush`](en.cppreference.com/w/c/io/fflush) function leads to *undefined behavior*. Some implementations might allow it as an extension of the C language, but try to avoid it anyway. – Some programmer dude Jan 21 '18 at 15:41
  • As for your problem, you write the *full* structure, no matter how many characters actually are in the array. It will however not be a problem if you read the (full) structure from the file using `fread`, as the array will be null terminated (unless `gets` overflows it). In short, the raw contents of the file after the terminator should be discared when you look at a hex-dump of it. – Some programmer dude Jan 21 '18 at 15:42
  • 2
    [Why is the gets function so dangerous that it should not be used?](https://stackoverflow.com/q/1694036/995714) – phuclv Jan 21 '18 at 15:43
  • 1
    Where do you see spaces? – melpomene Jan 21 '18 at 15:46
  • @Lucky Except the first zero byte, the rest of those are the indeterminate contents of the uninitialized array. – Some programmer dude Jan 21 '18 at 15:51
  • 2
    @Someprogrammerdude Nah, `e` is global (static storage). It's zero-initialized. – melpomene Jan 21 '18 at 15:52
  • @melpomene How do I remove those 0000? – Lucky Jan 21 '18 at 16:04
  • 1
    There are many ways to avoid writing the null bytes. For text data that's a string, `fputs(e.text, file)` is simple and effective. If you must use `fwrite()`, then `fwrite(e.text, 1, strlen(e.text), file)` is effective. If you must output the null terminator, add one to the result of `strlen()`. Etc. (Note that what were written were not spaces but null bytes, `'\0'`.) – Jonathan Leffler Jan 21 '18 at 16:08
  • So cool. Thank you! @JonathanLeffler I will keep that in mind. – Lucky Jan 21 '18 at 16:15
  • Do note that if you only write the string itself, with or without the terminator, then you can read it back like e.g. `fread(&e, sizeof e, 1, fp)`. In fact, if you don't store the terminator and write more data to the file, there is no way of telling when the string actually ends. And if you only want to store the string, and *more* strings or other data *as text*, then why open the file in binary mode and use `fwrite`? – Some programmer dude Jan 21 '18 at 17:01
  • @melpomene Ah yes you're correct. – Some programmer dude Jan 21 '18 at 17:01

1 Answers1

1

There are multiple problems in your code:

  • The size of the struct is fixed, which explains why you get more bytes in the output file than were typed by the used.

  • fflush(stdin); has undefined behavior, you should not use it. There is no standard way to flush character pending in the input stream, you could read them up to a newline, but this may prompt the user for extra input if none is pending.

  • The gets() function is deprecated. It cannot be called safely because the Standard library has no way to determine the maximum number of characters to store into the destination array, so it cannot prevent a possible buffer overflow.

Here is a corrected version:

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

struct my_struct {
    char text[100];
} e;

int main() {
    FILE *file = fopen("filename", "ab");
    if (file == NULL) {
        file = fopen("filename", "wb");
    }
    if (file == NULL) {
        printf("Cannot open filename\n");
        return 1;
    }
    printf("Input text: ");
    if (fgets(e.text, sizeof e.text, stdin)) {
        /* strip the trailing newline if any */
        e.text[strcspn(e.text, "\n")] = '\0';
        /* write the bytes to the binary file */
        fwrite(e.text, strlen(e.text), 1, file);
    }
    fclose(file);
    return 0;
}

Note that you could use a simple char array instead of the structure.

chqrlie
  • 131,814
  • 10
  • 121
  • 189