Home > other >  How to print a line from its beginning?
How to print a line from its beginning?

Time:01-17

I've been coding a program to write data into a text file and practice data processes in c, and find data from there, every data is stored as lines. There are lines, and data is stored line by line, such as:

student name student surname student phone etc.

When i take an input of "student name" it starts to print without printing the name itself, prints what comes after it, same happens if i search for surname, only phone will be printed out.

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

int main(){
    FILE *filePtr;
    filePtr=fopen("std.txt","r");
    char char_input[50];
    char string[500];


    printf("%s","Please give an input of the phone number\n");
        scanf("%s",char_input);

        while(!feof(filePtr)){
            fscanf(filePtr,"%s",string);
                if(strcmp(string, char_input)== 0){
                    fgets(string,500,filePtr);
                    puts(string);
            }
        }
    fclose(filePtr);
}

Text file:

Andrew Brooks 865 965 55

Input:

Andrew

Output:

Brooks 865 965 55

Desired output:

Andrew Brooks 865 965 55

CodePudding user response:

Instead of incorrectly using feof() and fscanf(filePtr,"%s", ... to incorrectly read a line. Use fgets() to read a line of the file and convert to a string.

  • Test the return value of fgets() to see if input occurred.

  • Use strstr() to look for a matching sub-string within string.

Example:

    while (fgets(string, sizeof string, filePtr)) {
      if (strstr(string, char_input)){
        fputs(string, stdout);
      }
    }

CodePudding user response:

The function feof will only tell you whether a previous input operation has already encountered end-of-file. It won't tell you whether you have now reached the end of file, so that the next input operation will fail. That function function is unable to predict whether the next input operation to fscanf or fgets will fail. Therefore, it should generally not be used as a loop condition. See this question for further information: Why is “while ( !feof (file) )” always wrong?

In your case, feof may return false and the subsequent function call to fscanf may return EOF due to encountering end-of-file. In that case, your posted code will ignore the return value of fscanf and behave as if fscanf had succeeded, and your posted code will attempt to process the non-existant input. This is likely to result in a bug.

Therefore, instead of using the function feof to determine whether the loop should be continued, you should check the return value of the input function.

You could rewrite your loop like this:

while ( fscanf(filePtr,"%s",string) == 1 ) {
    if ( strcmp(string, char_input ) == 0 ) {
        fgets( string, 500, filePtr );
        puts( string );
    }
}

This will solve the problem mentioned above of not checking the return value of fscanf. However, depending on the exact input, it may also be possible that the function fgets will fail due to encountering end-of-file. Therefore, it would be better if your program also checked the return value of the function fgets, instead of simply assuming that the function succeeded.

Another problem is that the line

puts(string);

will only print the contents of string, which is " Brooks 865 965 55". However, you also want to print "Andrew", which was read by the fscanf function call but has been meanwhile overwritten by the fgets function call. The simplest solution would be to print it before it gets overwritten. However, this will not work if the user searches for "Brooks" instead of "Andrew", because the word "Andrew" will already have been discarded in the previous loop iteration. This is because calling fscanf(filePtr,"%s",string) in a loop will not read one line of input per loop iteration, but will instead read a single word per loop iteration (which is not very meaningful).

Another consequence of reading in the input file word by word using fscanf(filePtr,"%s",string) is that your won't be able to find a match for the phone number "865 965 55". This is because your program will first read "865" from the input file and determine that this "word" is not identical to the search string. It will then read "965" and determine the same thing. It will do the same for "55".

The best solution would probably be to redesign your loop so that it always reads exactly one line of input per loop iteration, instead of only one word per loop iteration. After reading in one line of input, you can then parse the line by splitting it into "first name", "last name" and "phone number" using the function sscanf.

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

int main()
{
    FILE *filePtr;
    char search_string[50];
    char line[200];

    //open input file
    filePtr = fopen( "std.txt", "r" );
    if ( filePtr == NULL )
    {
        fprintf( stderr, "unable to open input file!\n" );
        exit( EXIT_FAILURE );
    }

    //prompt user for input
    printf( "Please enter search string: " );

    //Note that the following code now uses "fgets" instead
    //of "fscanf", because fscanf will only read a single
    //word, when using the "%s" format specifier. This means
    //that it would be unable to read the phone number
    //"865 965 55" as an input string, because that line
    //consists of three "words".

    //read exactly one line of input from user
    if ( fgets( search_string, sizeof search_string, stdin ) == NULL )
    {
        fprintf( stderr, "input failure!\n" );
        exit( EXIT_FAILURE );
    }

    //remove newline character from input line by
    //replacing it with terminating null character
    search_string[strcspn(search_string,"\n")] = '\0';

    //read exactly one line of input from the input file
    //per loop iteration
    while ( fgets( line, sizeof line, filePtr ) != NULL )
    {
        char first_name[50];
        char last_name[50];
        char phone_number[50];

        //attempt to parse input
        if (
            sscanf(
                line,
                "Is Is I[^\n]",
                first_name,
                last_name,
                phone_number
            )
            != 3
        )
        {
            fprintf(
                stderr,
                "warning: skipping line due to parse error!\n"
            );

            continue;
        }

        //parsing was successful, so we can now search the
        //3 individual fields for the search string
        if (
            strcmp( search_string, first_name   ) == 0
            ||
            strcmp( search_string, last_name    ) == 0
            ||
            strcmp( search_string, phone_number ) == 0
        )
        {
            //remove newline character from input line by
            //replacing it with terminating null character
            line[strcspn(line,"\n")] = '\0';

            //print entire input line of file for user
            printf( "%s\n", line );
        }
    }

    fclose(filePtr);
}

This program has the following behavior:

Please enter search string: Andrew
Andrew Brooks 865 965 55
Please enter search string: Brooks
Andrew Brooks 865 965 55
Please enter search string: 865 965 55
Andrew Brooks 865 965 55

Note that the code above is not perfect, as it has the following issues:

  1. When using fgets, if the input line is too long to fit in the buffer, then the program will not detect this, although it should probably print an error message and quit, in such a situation.
  2. If any of the fields "first name", "last name" or "phone number" is larger than 49 characters, the code does prevent a buffer overflow (which would possibly cause your program to crash), but it still doesn't handle this situation properly, for example by checking for such a situation and by printing an appropriate error message.

However, for your purposes, the code should probably be sufficient.

  •  Tags:  
  • Related