0

I have these in my file:

JOS BUTTLER
JASON ROY
DAWID MALAN
JONNY BAISTROW
BEN STOKES

in different lines. And I want them to extract in my program to print them on the exact way they are in file. My imaginary output screen is:

JOS BUTTLER
JASON ROY
DAWID MALAN
JONNY BAISTROW
BEN STOKES

How would I do it using fscanf() and printf(). Moreover suggest me the way to change the delimiters of fscanf() to \n I have tried something like this:

char n[5][30];
    printf("Name of 5 cricketers read from the file:\n");
   for(i=0;i<5;i++)
   { 
            fscanf(fp,"%[^\n]s",&n[i]);
            printf("%s ",n[i]);         
    }
    fclose(fp);
}

But it works only for the first string and other string could not be displayed. There were garbage values.

  • 1
    Please don't SHOUT in your title - you can see the standard by looking at all the other questions on here. – Solar Mike Jul 12 '22 at 06:20
  • 4
    Why do you insist on using `fscanf` when the correct tool for this job is `fgets`? In fact, you barely even need that. You can read one character at a time and echo them to the console. – paddy Jul 12 '22 at 06:22
  • okay but can you suggest me the way to change the delimiter of `scanf()` with strings – Anup Adhikari Jul 12 '22 at 06:34
  • 1
    Change it to this: `fscanf(fp," %29[^\n]", n[i]);`. a) added space, b) length restriction, c) removed `s`, d) removed `&`. The leading space filters the previous newline left in the buffer. This is the way `fscanf` is intended to be used. It's horrible practice to kludge the newline away for at least 2 reasons: 1) there might be more then one whitespace in the input, and the leading space mentioned filters *any* amount of it, 2) the last line of a valid text file might not end with a newline. – Weather Vane Jul 12 '22 at 07:57
  • @WeatherVane what actually the added space does? I didn't get it. – Anup Adhikari Jul 12 '22 at 09:47
  • Some explanation: most of the format specifiers for `scanf` automatically filter leading whitespace, but `%c` and `%[]` and `%n` do not. Adding a space in front of the `%` instructs `scanf` to filter leading whitespace here too. The reason is that with those three specifiers allow you to read every character including whitespace, but a way is provided so they behave like `%d` and `%f` and `%s` where needed. – Weather Vane Jul 12 '22 at 10:11
  • @paddy "'correct tool for this job is fgets" --> except when the name is at the limit of `n[]`. Extra code needed to read a 29 character name into `n[]`. – chux - Reinstate Monica Jul 12 '22 at 10:54
  • @AnupAdhikari The reason we're recommending you use `fgets` is because `scanf` is a dead-end function. `scanf` is barely okay for really, really simple input, but once you're trying to do anything at all complicated, `scanf` either can't do the job, or it's more trouble than it's worth. Now, "reading a string with spaces" is one of the things that's, basically, too complicated for a reasonable use of `scanf`. It can be done, but it's unnecessarily confusing, as evidenced by your (perfectly reasonable) question about what the mysterious extra space is for. – Steve Summit Jul 12 '22 at 12:10
  • So please don't cling to `scanf` as if it's *the* way to do input. It's not: there are better ways. When you're ready, please read [What can I use for input conversion instead of scanf?](https://stackoverflow.com/questions/58403537) – Steve Summit Jul 12 '22 at 12:10

2 Answers2

1

Be protected from buffer overflows limiting the length of the input, use "%29[^\n]" instead of "%[^\n]s" (you don't need the s specifier)

Consume the trailing new line (your wildcard ^\n reads until a new line is found) using %*c, * means that a char will be read but won't be assigned:

fscanf(fp, "%29[^\n]%*c", n[i]);

or better yet (as pointed out by @WeatherVane), add a space before %, this will consume any blank space including tabs, spaces and new lines that may be left in the buffer from the previous read:

fscanf(fp, " %29[^\n]", n[i]);

Notice that you don't need an ampersand in &n[i], fscanf wants a pointer but n[i] is already (decays into) a pointer when passed as an argument.

Finally, as pointed out by @paddy, fgets does all that for you and is a safer function, always prefer fgets.

David Ranieri
  • 39,972
  • 7
  • 52
  • 94
0

How to get string terminated with new line in file handling using fscanf

Use fgets() to read a line of input into a string. It also reads and saves the line's '\n'.

Buffer size 30 may be too small, consider 60.

To detect if the line is too long and lop off the '\n', read in at least + 2 characters.

// char n[5][30];
#define NAME_N 5
#define NAME_SIZE 30
char n[NAME_N][NAME_SIZE]

char buf[NAME_SIZE + 2]
while (i < NAME_N && fgets(buf, sizeof buf, fp) != NULL) {
  size_t len = strlen(buf);

  // Lop off potential trailing '\n'
  if (len > 0 && buf[len - 1] == '\n') {
    buf[--len] = '\0';
  }

  // Handle unusual name length
  if (len >= NAME_SIZE || len == 0) {
    fprintf(stderr, "Unacceptable name <%s>.\n", buf);
    exit(EXIT_FAILURE);
  }

  // Success
  strcpy(n[i], buf);
  printf("%s\n", n[i]); 
  i++;
}
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256