something
something

Reputation: 19

How to get a user input to open a file in C?

So I'm trying to open a file based on a users input but I just keep getting what I typed in back.

This is what I have.

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

int main(void) 
{
  FILE* data;
  char a[144];
  printf("Enter a filename:\n");
  fscanf(stdin, "%143[^\t]", a);
  data = fopen(a, "r");
  printf("%s", a);
  fclose(data);
  return 0;
}

This is my text file.

larry snedden 123 mocking bird lane
sponge bob 321 bikini bottom beach
mary fleece 978 pasture road
hairy whodunit 456 get out of here now lane

Upvotes: 0

Views: 6554

Answers (3)

HenryLiu
HenryLiu

Reputation: 25

fscanf(stdin, "%143[^\t]", a) read input end with tab. You can try another method. And you didn't read from the file stream data.

#include <stdio.h>
#include <string.h>
int main(void) 
{
   FILE* data;
   char a[144];
   printf("Enter a filename:\n");
   fscanf(stdin, "%s", a);  //use %s not 143[^t]
   data = fopen(a, "r");

   //read from the file
   char read_from_file[100];
   while (!feof(data)) {
       fgets(read_from_file, 1024, data);
       printf("%s", read_from_file);
   }
   print("\n")

   printf("%s", a);
   fclose(data);
   return 0;
}

text file named file.txt:

larry snedden 123 mocking bird lane
sponge bob 321 bikini bottom beach
mary fleece 978 pasture road
hairy whodunit 456 get out of here now lane

input:

file.txt

output:

larry snedden 123 mocking bird lane
sponge bob 321 bikini bottom beach
mary fleece 978 pasture road
hairy whodunit 456 get out of here now lane
file.txt

Upvotes: 1

Swordfish
Swordfish

Reputation: 13134

Use fgets() to read a whole line of input:

#include <stddef.h>  // size_t
#include <stdlib.h>  // EXIT_FAILURE
#include <stdio.h>   // FILE, fprintf(), fputs(), fgets(), fopen(), fclose()
#include <string.h>  // strlen()

enum { MAX_FILENAME_LENGTH = 120 };

int main(void)
{
    char filename[MAX_FILENAME_LENGTH + 2]; // + '\n' + '\0'
    if (!fgets(filename, sizeof(filename), stdin)) {
        fputs("Input error :(\n\n", stderr);
        return EXIT_FAILURE;
    }

    size_t length = strlen(filename);  // get rid of the newline at the end:
    if (length && filename[length - 1] == '\n')
        filename[--length] = '\0';

    // When the length of the string is not needed, the above if-statement
    // can be replaced as suggested by Jonathan Leffler:
    filename[strcspn(filename, "\n")] = '\0'

    FILE *input = fopen(filename, "r");
    if(!input) {
        fprintf(stderr, "Couldn't open \"%s\" for reading :(\n\n", filename);
        return EXIT_FAILURE;
    }

    // do stuff with input

    fclose(input);
}

See this answer on how to read a whole file into memory line by line.

Upvotes: 2

David C. Rankin
David C. Rankin

Reputation: 84551

You face three primary issues: (1) you take a filename from the user with fscanf(stdin, "%143[^\t]", a); which will read all characters not a tab (including the trailing '\n' generated by pressing Enter), (2) after opening the file input by the user and assigning the return from fopen to data, you have no way to know whether the file is actually open (given the trailing '\n' included in the filename, I suspect it fails); and (3) you never actually read from the file-stream data (which is probably a good thing given you failed to VALIDATE it was actually open.

The key is to validate every critical step in your program especially every bit of user input. Each function provides a return -- use them to validate whether the function succeeded or failed.

A short example adding validation (and declaring a constant where needed -- don't use magic numbers in your code except where absolutely required -- like with the scanf field-width modifier), e.g.

#include <stdio.h>

#define MAXC 1024   /* if you need a constant, define one (or more)
                           ( don't SKIMP on buffer size ) */

int main (void) 
{
    FILE* data = NULL;  /* initialize all variables */
    size_t nlines = 0;
    char a[MAXC] = "";

    printf("Enter a filename: ");

    /* VALIDATE EVERY SINGLE BIT OF INPUT */
    if (fscanf (stdin, " %1023[^\n]", a) != 1) {
        fputs ("user canceled input.\n", stderr);
        return 1;
    }
    /* open/VALIDATE file open for reading */
    if ((data = fopen (a, "r")) == NULL) {
        perror ("fopen-a");
        return 1;
    }

    printf ("file opened: %s\n\n", a);

    /* reuse buffer to read each line */
    while (fgets (a, MAXC, data) != NULL)
        /* fgets include '\n' in buffer if buffer of sufficient size */
        printf ("line[%3zu]: %s", nlines++ + 1, a);
    fclose(data);

    return 0;
}

Example Input File

$ cat dat/file.txt
larry snedden 123 mocking bird lane
sponge bob 321 bikini bottom beach
mary fleece 978 pasture road
hairy whodunit 456 get out of here now lane

Example Use/Output

$ ./bin/fopen_file_from_user
Enter a filename: dat/file.txt
file opened: dat/file.txt

line[  1]: larry snedden 123 mocking bird lane
line[  2]: sponge bob 321 bikini bottom beach
line[  3]: mary fleece 978 pasture road
line[  4]: hairy whodunit 456 get out of here now lane

Upvotes: 4

Related Questions