bekici
bekici

Reputation: 84

I want to read a certain part of a line in C

I want to read a specific part of a line. I don't want to add anything after "// " as shown in the example. I've defined a flag for it. But I'm having a hard time getting to the bottom line. How can I solve this ?

void read_file(char *filename) {
    int flag = 0;
    char line[MAX_LINE_LENGTH];

    FILE *f = fopen(filename, "r");

    while(fscanf(f, "%s", line) != EOF) {
        if(!strcmp(line, "//")) {
            flag = 1;
        }
        if(flag == 0) {
            printf("%s", line);
        }       
    }
}

enter image description here

Upvotes: 0

Views: 1071

Answers (3)

Craig Estey
Craig Estey

Reputation: 33631

Your fscanf is wrong. It won't return EOF. You want to compare against != 1 instead.

But, if you want to strip the comment, and just print the [preceding] data, you'll want strstr instead of strcmp

Also, I'd use fgets instead of fscanf ...

Here's your code refactored:

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

#define MAX_LINE_LENGTH     1000

void
read_file(char *filename)
{
    int flag = 0;
    char *cp;
    char line[MAX_LINE_LENGTH];

    FILE *f = fopen(filename, "r");

    while (1) {
        cp = fgets(line,sizeof(line),f);
        if (cp == NULL)
            break;

        cp = strstr(line,"//");

        if (cp != NULL) {
            *cp++ = '\n';
            *cp = 0;
        }

        printf("%s", line);
    }
}

You may want to clean this up a bit more to do better handling of the newline [which fgets retains].


UPDATE:

Yes, my code is fixed. Thank you so much. But I don't understand here : *c = 0

A string in C is a char array that just "happens" to have a zero byte as the string terminator.

fgets will guarantee that the buffer has a trailing 0

Likewise, printf expects line to be 0 terminated.

We're trying to clip out the // and everything else on the line that follows it.

It's not enough to just add back a newline there. We have to add [back] the 0 at the now shortened string as the new place for the string terminator.

If the original line was:

foo // bar<newline><0x00>

We want:

foo <newline><0x00>

If you want to see why, just comment out the *cp = 0;. You'll get "interesting" results ...


UPDATE #2:

In order to not change your code so much, I left the newline in the string.

But, normally, I always strip the newline out before doing any processing. I find that to be a bit cleaner [even if a bit slower].

Here's a version that does that and is closer to what I would have written from scratch:

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

#define MAX_LINE_LENGTH     1000

void
read_file(char *filename)
{
    int flag = 0;
    char *cp;
    char line[MAX_LINE_LENGTH];

    FILE *f = fopen(filename, "r");

    while (1) {
        cp = fgets(line,sizeof(line),f);
        if (cp == NULL)
            break;

        // strip newline
        cp = strchr(line,'\n');
        if (cp != NULL)
            *cp = 0;

        // find [and strip] the comment
        cp = strstr(line,"//");
        if (cp != NULL)
            *cp = 0;

        printf("%s\n", line);
    }
}

Note that because the newline has been pre-stripped [if it exists on the line], the printf has to be modified to add one when printing.


UPDATE #3:

Using strchr and strstr are the easy thing to do. But, this requires that line be scanned twice, which is a bit wasteful.

The str* functions in libc are a convenience, but we can write a custom function that does a single pass on the line and strips either the comment or the newline whichever comes first.

This may help explain what a "string" in C really is, since we're doing "all the magic" so to speak:

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

#define MAX_LINE_LENGTH     1000

void
fixline(char *line)
{
    int chr;

    for (chr = *line++;  chr != 0;  chr = *line++) {
        // strip newline
        if (chr == '\n') {
            line[-1] = 0;
            break;
        }

        // wait for first "/"
        if (chr != '/')
            continue;

        // peek at next char (is it '/' -- if so, we have "//")
        chr = *line;
        if (chr == '/') {
            line[-1] = 0;
            break;
        }
    }
}

void
read_file(char *filename)
{
    int flag = 0;
    char *cp;
    char line[MAX_LINE_LENGTH];

    FILE *f = fopen(filename, "r");

    while (1) {
        cp = fgets(line,sizeof(line),f);
        if (cp == NULL)
            break;

        // strip newline and/or comment
        fixline(line);

        printf("%s\n", line);
    }
}

UPDATE #4:

Thank you I got it. But when I try it this way, why can't I get the right result? if(!strcmp("data", line)) { printf("helloo"); } break; When you add this part to the end of the code, it doesn't work correctly.

If you've added this after the newline strip, it should work, because the data line has nothing else on it and it starts in the first position of the buffer.

But, indented this is:

if (!strcmp("data", line)) {
    printf("helloo");
}
break;

You probably want:

if (!strcmp("data", line)) {
    printf("helloo");
    break;
}

Both strchr and strstr scan the entire string looking for a matching character [strchr]. Or, the start of matching substring [strstr].

strcmp does not scan the string in that sense. It just loops through both strings, char-by-char and stops on EOS. It just checks for equal strings, both starting at the first char of each array.

Real strcmp will use special instructions to make it very fast [as will other libc functions], but here is what strcmp actually does:

int
strcmp(const char *s1,const char *s2)
{
    int c1;
    int c2;
    int cmp = 0;

    while (1) {
        c1 = *s1++;
        c2 = *s2++;

        if (c1 < c2) {
            cmp = -1;
            break;
        }

        if (c1 > c2) {
            cmp = +1;
            break;
        }

        // end of string -- both strings equal
        if (c1 == 0)
            break;
    }

    return cmp;
}

Upvotes: 1

bekici
bekici

Reputation: 84

@Craig Estey

    while (1)
    {

        cp = fgets(line, sizeof(line), f);
        if (cp == NULL)
            break;
        if(!strcmp("actions", cp)) {
            break;
        }
        cp = strstr(line, "//");

        if (cp != NULL)
        {
            *cp++ = '\n';
            *cp = 0;
        }

        printf("%s", line);
    }

Why is the strcmp function not working in this way?

Upvotes: 0

Stephan Lechner
Stephan Lechner

Reputation: 35164

Format %s reads words (i.e. everything until the next space, tab, newline, ...) but not lines; That's probably why you have a hard time.

For reading in complete lines (i.e. everything up to a new line), use function fgets;

For cutting the line off at a "//", use strstr as follows:

char *beginOfComment = strstr(line,"//");
if (beginOfComment) {
   *beginOfComment = 0x0;
}

Upvotes: 0

Related Questions