-2

I am new to C and trying to learn about strings, I/O and files. I am trying to read strings from a file with multiple strings per line, as shown below:

str1 str2 str3
str4 str5 str6
str7 str8 str9

So far I have tried with :

scanf("%s %s %s", &str1, &str2, &str3);

but it reads the strings in a weird manner. Why is the scanf function not working? I have also seen that an alternative would be to use fgets to read the entire line in a buffer, but I am not very confident of my buffer management skills, so is there any way to do this using scanf ?

rares985
  • 341
  • 3
  • 15

2 Answers2

1

The best way to read lines in C is first reading with fgets() then you can parse the line with sscanf() or with strtok() to get the words.

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

int main(){
    char line[1024];
    char str1[1024], str2[1024], str3[1024];
    while (fgets(line, sizeof(line), stdin) != NULL){
        if (strlen(line) > 0 && line[strlen(line) - 1] != '\n') {
            // or line[0] instead of strlen(line) > 0
            // like chux suggested (line[0] is more efficient)
            puts("The line is longer than expected");
            return 1;
        }
        if (sscanf(line, "%s %s %s", str1, str2, str3) != 3){
            // notice it wont fail if the input have more than 3 columns
            puts("Error parsing, not enough columns");
            return 2;
        }
    }
    return EXIT_SUCCESS;
}
Fernando
  • 1,382
  • 8
  • 17
  • 1
    Why the downvote? Is harder to read the line with `scanf()` correctly than to learn how to use `fgets()`. – Fernando Jan 08 '15 at 01:34
  • @Jasen what do you mean? Read: http://stackoverflow.com/questions/2430303/disadvantages-of-scanf or http://stackoverflow.com/questions/2565727/what-are-the-c-functions-from-the-standard-library-that-must-should-be-avoided – Fernando Jan 08 '15 at 01:48
  • 1
    2 minor bits: 1) Consider `fgets(line, sizeof line, stdin)` 2) In rare situations with embedded `'\0'`, `[strlen(line)` may be 0. Better to use insure `strlen(line) > 0` before using `line[strlen(line) - 1]`. Maybe with `if (line[0] && line[strlen(line) - 1] != '\n')` – chux - Reinstate Monica Jan 08 '15 at 02:10
  • Thanks @chux I've added your suggestions to my answer. – Fernando Jan 08 '15 at 02:17
1

I have a text file:

ho hello blah hi dsdf hihi hiho hih bleh

The following is the code I'd use to read it.

#include <stdio.h>

int main()
{
    char string1[11];   
    char string2[11];
    char string3[11];
    char string4[11];
    char string5[11];
    char string6[11];
    char string7[11];
    char string8[11];
    char string9[11];

    FILE * fileReader = fopen("text.txt", "r"); 
    if(fileReader)
    {
        fscanf(fileReader, "%10s %10s %10s %10s %10s %10s %10s %10s %10s", string1, string2, string3, string4, string5, string6, string7, string8, string9);
        printf("Found: %s %s %s %s %s %s %s %s %s\n", string1, string2, string3, string4, string5, string6, string7, string8, string9);
        fclose(fileReader);
    }
    else
    {
        puts("Error opening filestream!");
    }
 return 0;
}

FILE *, aka streams are used for input/output in C. scanf() uses the default input stream (stdin) and so cannot be used for reading files. fscanf() allows you to specify the filestream as a parameter.

Also, using %10s prevents fscanf() from reading more than ten characters for each string. Without %10s, scanf() could cause your program to have a buffer overflow. This is basically when it reads more data than the char [] variables can hold, corrupting program memory.

if(fileReader) checks to see if fileReader was successfully opened (non-zero values = true, 0 (aka NULL) = false). I could have done it as if(fileReader != NULL), but it's the same effect.

Also, you don't use the & operator when dealing with arrays. Arrays deteriorate into pointers when passed to functions like scanf(), so by using &, you're passing scanf() the address of the pointer, which isn't what you want.

This is what I get when I compile the above code(the text file used is saved as "text.txt"):

sky@sky-Lenovo-3000-N500:~$ gcc stringReader.c -o string && ./string
Found: ho hello blah hi dsdf hihi hiho hih bleh
chenshuiluke
  • 319
  • 1
  • 16