1

I am unfortunately a complete novice when it comes to C. I am trying to read a text file which is formatted something like this

one two three
two one three
three one 

I need to read the first string on a line (so in case of first line that would be "one", then I do a comparison with a variable. If its a match then I need to use rest of the string, so if a match on string one I need to use "two" and "three" (separately as their own strings). If there is no match I move on to the next line and so on.

Here is the code I have so far, but it doesnt seem to work. In comments what I think the code is doing.

char temp[] = "three";
while(!feof(file)){ //Go until end of file is reached
    fgets(line, 100, file); //Grab the line
    string_token = strtok(line, " "); //Tokenize the line 
    strcpy (compare_to, string_token); //Copy first token into a string variable
    if (strcmp(compare_to, temp) == 0){ //Compare string with a predefined temp variable
        while (string_token != NULL) { //If it was a match then we go until tokens end (which would be end of the line from a file)
            printf("%s has the following: %s\n", temp,compare_to );   
            string_token = strtok(NULL, " ");
        }
    }
}
Ôrel
  • 7,044
  • 3
  • 27
  • 46
Duxa
  • 966
  • 2
  • 14
  • 27
  • 2
    https://stackoverflow.com/questions/5431941/why-is-while-feof-file-always-wrong – William Pursell Jan 10 '18 at 23:18
  • Thanks for the comment William, but I have no idea how to read files in C (I have never seen C until a few days ago), instructions were to use "EOF" to determine when file ends. Is there a different way to do this but still use EOF? Im not even sure what to google for to find an answer, thats why I came here to hopefully get pointed in the right direction. – Duxa Jan 10 '18 at 23:24
  • 2
    @Duxa the best way is `while(fgets(line, sizeof line, stdin)) { // code }` – Pablo Jan 10 '18 at 23:26
  • 1
    tip: just check the start of the line for 'one ' with strncmp - then you onyl need to tokenize it if it is a match – Martin Beckett Jan 10 '18 at 23:37
  • @MartinBeckett , yes I thought that too, but I am not sure how to go to next line if I do not need to tokenize it. – Duxa Jan 10 '18 at 23:40
  • @Pablo I tried this; however sizeof line leads to random chunks of the strings being read(each string is different length) – Duxa Jan 10 '18 at 23:41
  • @Duxa in that case you can make the buffer longer or you write a function `getline` that calls `fgets` until a newline is read or the end of file is reached. – Pablo Jan 10 '18 at 23:44
  • @Duxa Who or what text suggest using `!feof(file)`? – chux - Reinstate Monica Jan 10 '18 at 23:48
  • `sizeof line` will have different values for pointer to characters and character array. – alvits Jan 10 '18 at 23:48
  • @chux Professor at my University. He said to use "\n" to find end of line and EOF for end of file. When I googled those the above code is what I could come up with. Its much harder to find info for C than it is for C++ :( – Duxa Jan 10 '18 at 23:52
  • yes, I should add to my comment, that `sizeof line` only works when `line` is a `char[]`, not when line is pointer (like alvits says in his/her comment) – Pablo Jan 10 '18 at 23:53
  • @Pablo If I have allocated 100 bytes to the char to store the line that I read, is there any harm to just using 100 fgets(line, 100, file); and not use size of? Does sizeof give anything extra (other than obvious code modularity where modifying allocated size will automatically change the value in the fgets call? To clarify my quesstion. Does sizeof do anything other than plug in that number? – Duxa Jan 11 '18 at 00:00
  • 1
    @Duxa no, it doesn't do any harm using 100 in `fgets` However, let's say you later change your `malloc` to allocate 50 instead of 100 and you've forgotten to change the `fgets` line, then you *might* end up with a stack overflow. That's why I usually do `char line[1024]; fgets(line, sizeof line, stdin)`, so I change the dimension of `line`, I don't have to worry about `fgets`. – Pablo Jan 11 '18 at 00:06
  • Ok thanks for clarifying @Pablo :) Thats a very good reason to use it, I just wanted to make sure its not doing something else Im not aware of. I was able to make it work... so im reading the file with fgets... now to figure out the rest of it. – Duxa Jan 11 '18 at 00:08
  • @Duxa no problem. These are the kind of things you realize once you've got enough experience and you've spent hour hunting stupid bugs (like forgetting to change the size argument in `fgets`). – Pablo Jan 11 '18 at 00:13
  • @duxa, It might be interesting to offer [Why is “while ( !feof (file) )” always wrong?](https://stackoverflow.com/questions/5431941/why-is-while-feof-file-always-wrong) to your Professor. But to be fair, while `while(!feof(file)){` is weak, it is the lack of checking the return of `fgets()`in this code that is the great folly. – chux - Reinstate Monica Jan 11 '18 at 00:27

2 Answers2

2

Reading file line by line, read first string, if match then use rest of the line, otherwise move to next line

In all cases, code needs to reads the entire line - it is just a question of how input is used.

Do not use this problematic code

// while(!feof(file)){
//  fgets(line, 100, file);

Instead

while(fgets(line, sizeof line, file)) {

Now parse the string, add \n to the delimit list.

  int count = 0;
  string_token = strtok(line, " \n");
  // compare the the i'th `compare_to[i]` or 
  // what ever fulfills "then I do a comparison with a variable"
  if (string_token != NULL && strcmp(compare_to[i], string_token) == 0){
    printf("<%s>\n", string_token );   
    string_token = strtok(NULL, " \n");
    count++; 
  }
}
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • Once tokenized "line" char array can be repurposed? Or do tokens still rely on that variable staying intact? – Duxa Jan 11 '18 at 00:06
  • 1
    @Duxa you shouldn't touch the array, because `strtok` uses it for the next tokens. Unless of course you don't want to use `strtok` any more. But beware that `strtok` modifies the array. So if you later still need to access the whole line, it's best to do a copy first and then tokenize. – Pablo Jan 11 '18 at 00:10
  • 1
    Are you sure that the code should be considered [ill formed](https://en.wiktionary.org/wiki/ill-formed)? I believe that term has a rather more specific meaning, which does not apply here. – EOF Jan 11 '18 at 00:13
  • @eof OK - post amended. – chux - Reinstate Monica Jan 11 '18 at 00:24
  • @chux Well damn.... I just found out that I cant utilize nested strtok. The "temp" file I am comparing with comes from another file and I used strtok to read from that one. that one is easier because its just one line separated by whitespace. so Im reading one string from that file, then comparing that with this second file. I guess I cant use strstok in this case? Whats an alternative? – Duxa Jan 11 '18 at 01:11
  • @Duxa "I just found out that I cant utilize nested strtok" is a new requirement not in the question. If not using `strtok()` was important, 1) your sample code should not have used it 2) original question should have stated that restriction. [so] is a "you ask a question", folks answer it. Else we could be going round and round - with no end in sight. If you have a new question, learn from this one, review your code, search SO for fixes and employ a fix the best you can. If code still has a new issue, post another question. – chux - Reinstate Monica Jan 11 '18 at 02:49
  • @chux Thanks. I would have liked to use strtok, and I tried to make the question simple hence I didnt use nested strtok since i thought id be able to do that once you guys helped me with the simple problem. Thanks for your help. Ill keep your advice in mind next time. – Duxa Jan 11 '18 at 02:54
  • @Duza Consider a simple `p = line; while(*p && !issapce(*p)) p++;` to find the next space. Also research `strcspn()`. – chux - Reinstate Monica Jan 11 '18 at 02:57
1

You can do this:

char first_str[128];
while(fgets(line, 100, file) != NULL)
{
    sscanf(line, "%s", first_str);
    if(strcmp(first_str, "your_str") == 0)
    {
        // match
        // so use result of the line
    }
}

Basically, you are reading the whole line, then using sscanf to check the 1st string and then proceed depending on what your condition is.

EDIT: Make sure your array length is long enough to hold the string.