0

This is my code:

char filename[30];
FILE *fp;
printf(" Enter the filename: ");
gets(filename);
strcat(filename,".txt");
fp=fopen("e:\\filename","a+");

So my problem is that I want the user to specify a file name then open that file and write on it. But every time I am running this code it opens a file named: filename instead of opening the value which is present on the string filename[30].

  • 3
    [Why gets() is so dangerous it should never be used!](https://stackoverflow.com/questions/1694036/why-is-the-gets-function-dangerous-why-should-it-not-be-used) Instead, `fgets (filename, sizeof filename, stdin);` – David C. Rankin Mar 21 '19 at 04:00

1 Answers1

3

You are "Tap Dancing on a Landmine" and flirting with Undefined Behavior by concatenating text without checking if there are sufficient character available in filename before calling strcat. What if the user enters a 26-character filename (or more)? (hint: undefined behavior)

This is compounded by the fact you are using gets for input. gets is so insecure and so prone to exploit by buffer overrun it has been completely removed in C11. If your professor is suggesting the use of gets -- go get another professor. See: Why gets() is so dangerous it should never be used!

Instead use fgets or POSIX getline to read the filename while protecting your arrays bounds with fgets or dynamically allocating as much storage as needed for filename in the case of getline.

All line-oriented input functions like fgets and getline read and include the trailing '\n' in the buffers they fill. You simply need to trim the '\n' from the end of the string. You can do so by getting the length with strlen and setting buffer[strlen(buffer) - 1] = '\0'; or by using the strcspn function which provides a bit more functionality in one call.

Putting it altogether, you could do something similar to the following (that just outputs the fopen call rather than actually opening the file):

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

#define MAXC 30         /* if you need a constant, #define one (or more) */
#define FEXT ".txt"     /* (including string constants) */

int main (void) {

    char filename[MAXC];
    size_t  available = MAXC - 1,   /* chars available in filename */
            length = 0,
            extlen = strlen (FEXT);
    FILE *fp;

    fputs (" Enter the filename: ", stdout);    /* no conversion needed */
    if (!fgets (filename, MAXC, stdin)) {
        fputs ("(user canceled input)\n", stderr);
        return 1;
    }

    /* trim '\n' from end of filename saving length using strcspn() */
    filename[(length = strcspn (filename, "\r\n"))] = 0;

    if (available - length < extlen) {
        fprintf (stderr, "error: insufficient space available for '%s'.\n", 
                FEXT);
        return 1;
    }

    strcat (filename, FEXT);
    /* just output what would be done */
    printf ("fp = fopen (\"e:\\%s\",\"a+\");\n", filename);
}

Example Use/Output

The example simply prints what it would open (rather than actuall opening the file), e.g.

$ ./bin/strcatext
 Enter the filename: my_file_to_open
fp = fopen ("e:\my_file_to_open.txt","a+");

And then check that your code will accept a 25-character filename plus 4-character extension, e.g.

$ ./bin/strcatext
 Enter the filename: 1234567890123456789012345
fp = fopen ("e:\1234567890123456789012345.txt","a+");

And rejects a 26-character filename, e.g.

$ ./bin/strcatext
 Enter the filename: 12345678901234567890123456
error: insufficient space available for '.txt'.

Look things over and let me know if you have further questions.

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
  • Hopefully this will help with the character accounting. The last big piece of advice -- *Don't Skimp on Buffer Size!* (so go back and change `#define MAXC 30` to at least `#define MAXC 512` (or if you are on Linux, `#include ` and use `char filename[PATH_MAX];` (which is `2048`). That way you are less likely to run out of room in `filename`. (I think windows had a `256` char limit on filenames, but I believe it is going to at least `512`) – David C. Rankin Mar 21 '19 at 04:45