1

I have a program that reads student names and grades line by line from a .txt file using fgets and a buffer declared as:

char buffer[1024];

Now the file should end with the string "end" on a line all by itself.

How do I tell a while loop to terminate when buffer == "end"?

I tried using strcmp but it segfaults for some reason.

10
  • 2
    strcmp is the right function to use, it must be something else. Commented May 17, 2012 at 2:57
  • Is this homework? Can we see your code? Commented May 17, 2012 at 2:57
  • 2
    You should figure out why strcmp segfaults rather than avoiding the issue. Commented May 17, 2012 at 2:58
  • The code is very involved, as the assignment is complete. It's just that I can't put "end" at the end of the file because that will cause a segfault. I just need a way to use "end" as a means of stopping reading, because as of now I'm using "fgets(buffer, 1024, file) != NULL" to kick out of reading. Commented May 17, 2012 at 2:59
  • 7
    If your code still segfaults, you haven't "got it". Commented May 17, 2012 at 3:06

4 Answers 4

4

To simply answer your question, strcmp actually is the function you're looking for:

#include <string.h>

if(!strcmp(line, "end\n") || !strcmp(line, "end\r\n"))
    break;

or similar should do the trick. Note the ! in front of strcmp as strcmp returns 0 (i.e. false) if the strings match. But I guess you already know that since you've already mentioned strcmp in your question.

On the segfault issue: Are you sure none of the pointers you pass to strcmp are NULL? Most C standard libraries don't do any error checking here and will run into segfaults when trying to read the memory at *(0).

Another possible issue that pops into my mind is that using strcmp will of course only work if you've already split your buffer into an array of single strings. strtok_r is probably most suited for this task (Altough quite tricky to use).

Sign up to request clarification or add additional context in comments.

5 Comments

The second test with \r is unnecessary; if you read in text mode, then OS-specific line endings are translated to '\n'.
@KeithThompson: I don't think that's safe to assume. On any POSIX system there is only one way to open a file using the C standard library (fopen) and it specifically says in the standard that r and rb are identical modes.
Yes, because POSIX text files use only '\n' to terminate lines. On Windows, for example, "r" and "rb" are distinct; "r" translates \r\n to \n, and "rb" doesn't. Things get tricky when you're reading files in a foreign text format, but I don't think the OP needs to worry about that.
@KeithThompson: If the file was given to him as part of an assignment then it's not safe to assume either line ending. Having a .txt extension smells like Windows since its rare for text files to have any sort of extension on POSIX systems, which may be what the OP is using. Without knowing the file format or the host environment it is safer to search for both \n and \r\n.
@dreamlax: It's hardly likely that an introductory-level assignment like this would require the student to worry about line endings, and we have no indication that the assignment mentioned the issue at all.
0

Why not just use formatted IO when the format of the text in the file is fixed and use !EOF for looping?

For example:

while(fp!=EOF)
{    fscanf(fp,"%s %s %d",name,grades, &marks);
     printf("Name: %s\tGrade: %s\t Marks: %d\n",name,grade,marks);
}

This would automatically detect the end of file, which would also remove the condition of having a string 'end' in the text file.

1 Comment

This is terrible, why is it upvoted? Who told you that fp != EOF is correct? Also, read the manual or documentation for fscanf().
0

char *fgets(char *restrict s, int n, FILE *restrict stream);

The fgets() function shall read bytes from stream into the array pointed to by s, until n-1 bytes are read, or a is read and transferred to s, or an end-of-file condition is encountered. The string is then terminated with a null byte.

so, when you read string "end", the element in buffer should be {'e', 'n', 'd', '\n', '\0'}, you can using strcmp as follows:

size_t len = strlen(buffer);
if (buffer[len - 1] == '\n')
{
    buffer[len - 1] == '\0';
}

if (strcmp(buffer, "end") == 0)
{
    //end
}

or

if (strncmp(buffer, "end", 3) == 0)
{
    //end
}

Comments

0

Using strncmp(buffer, "end", 3) to compare the first three characters along with if(3 == strlen(buffer) to make sure end does not start the line, should solve the problem.

3 Comments

If that helps, it's because he's forgetting about the '\n'. It's better to deal with the '\n' directly. Using strncmp(line, "end", 3") also creates false positive results for lines starting with \"end"\.
@KeithThompson I'm confused about the original post, then, because it looks like end is to appear on a line all by itself.
@octopusgrabbus: The point is that strncmp(buffer, "end", 3) will incorrectly indicate a match on a line consisting of "endurance".

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.