4

** Updated 26/10 -> First of all thank you all for you help, I am getting closer now, I need more work and studying but I really appreciate you are helping me a lot :-)

Still don't know why the first "rain" word in the input.txt file is not getting the positive output from strcmp, and from the cmd I can see the "<" bracket don't appear except for the LAST line which is the line that works.

Also checked the highlighted response from Removing trailing newline character from fgets() input

and even if I change the code to the following:

while( fgets (line, sizeof line, fp)!=NULL ) {

  /* remove \n from at the end of the str buffer*/   
  char * pos;
  /*
  if ((pos = strchr(line, '\n')) != NULL)
     *pos = '\0';
  */
  line[strcspn(line, "\n")] = 0;

I get the same result as if I use the if block instead. Maybe I'm getting extra \0 which might be the case. Anyone has a link where I can read about the delimiters I just used, or a nice reference of a debugger, etc. ... which I will have a look as soon as I come here? Thank you so much in advance!

read5.c version: Now from that input.txt file, it had an extra space on the last "rain" word, I removed the space, and it was able to find and get that last word compare as a true result, running in the strcmp if block. but that was the only string that was a true positive result from that if block.

on the cmd I can see:

$./read5 input.txt rain output.txt sun
>Maria
>rain
>manel
>Bla bla
<rain>
Found it! rain

On the output.txt it becomes:

Maria
rain
manel
Bla bla
sun

read5.c

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

/**
* Compile program:
*    gcc read3.c -o read3
*
*/
int main (int argc, char **argv) {
   FILE *fp, *fo;
   char *compare, *replace;
   char line[246];

   if (argc <= 4){
      printf(">Missing arguments on the command line.\n");
      printf(">Be sure you run the program as\n\"./read3 input.txt compare outout.txt replace\"\n\n");
   }

   /* opening file for reading */
   fp = fopen(argv[1] , "r");
   if(fp == NULL){
      perror("Error opening input file");
      return 1;
   }
   compare = argv[2];

   fo = fopen(argv[3], "w");
   if(fo == NULL){
      perror("Error opening output file");
      return 1;  //TODO check if: return 1 because it was expected, right?
   }
   replace = argv[4];

   /*
   printf(); made to test version 2
   //printf("We are going to compare %s\n", compare);
   //printf("We are going to replace it with %s\n", replace);
   */


   while( fgets (line, sizeof line, fp)!=NULL ) {

      /* remove \n from at the end of the str buffer*/   
      char * pos;
      if ((pos = strchr(line, '\n')) != NULL)
         *pos = '\0';

      /* print str enclosed in <> so we can see what str actually contains */
      //printf("Inside the loop, got the string: %s\n", line);

      //printing the strings with defined delimiters
      printf("<%s>\n", line);

      if(strcmp(compare, line) == 0){
         printf("Found it! %s \n", line);
         fprintf(fo, "%s\n", replace);
      }
      else{
         fprintf(fo, "%s\n", line);
      }

   }
   fclose(fp);
   fclose(fo);

   return 0;
}

First question with no edits: 25/10

I need to make a program that is run like this:

./read2 input.txt rain output.txt sun 

It reads the input.txt, searches for rain string and if finds it, replaces it with sun string and outputs all the text from input.txt with the replacements to the output.txt.

But with the code that I have so far, the strcmp is not comparing the strings I want, maybe it has the extra space that I get on the command line, I don't know... for now what is doing is copying everything from input.txt to output.txt... It's running the else block always...

Read2.c:

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

int main(int argc, char **argv) {
    FILE *fp, *fo;
    char str[60];

    //char* token;
    /* opening file for reading */
    fp = fopen(argv[1], "r");
    char *compare = argv[2];

    fo = fopen(argv[3], "w+");
    char *replace = argv[4];

    if (fp == NULL) {
        perror("Error opening file");
        return(-1);
    }

    //printf("We are going to compare %s\n", compare);

    //printf("We are going to replace it with %s\n", replace);

    while (fgets(str, 60, fp) != NULL) {
        /* writing content to stdout */
        //Take the \n out 
        //token = strtok(str, "\n");

        printf("Inside the loop, got the string: %s\n", str);
        if (strcmp(compare, str) == 0) {
            //puts(str);
            printf("Found it! %s \n", str);

            fprintf(fo, "%s", replace);
        } else {
            fprintf(fo, "%s", str);
        }
    }
    fclose(fp);

    return(0);
}

input.txt:

Maria
rain
manel
Bla bla
rain 

Ouput.txt becomes exactly as input.txt and before it was empty, so the code is working, except the if block that tests with strcmp.

Jess
  • 85
  • 12
  • 1
    You don't check if `fo` is NULL. And you don't check if `argc` is < 5. And please provide a minimal `input.txt` file so the problem can be reproduced. – Jabberwocky Oct 25 '17 at 06:48
  • you are reading 60 character once form the file. `while( fgets (str, 60, fp)!=NULL )`. You should read file word-by-word then compare. – Anshuman Oct 25 '17 at 06:49
  • 5
    This approach will only work if there is one word per text line in the input file. But you are overlooking that `fgets` retains the newline at the end of the input string. Please see [Removing trailing newline character from `fgets()` input](https://stackoverflow.com/questions/2693776/removing-trailing-newline-character-from-fgets-input/28462221#28462221) – Weather Vane Oct 25 '17 at 06:50
  • The way I'm testing it, argc is never <5 and fo is never null, that's not the problem... – Jess Oct 25 '17 at 06:50
  • 1
    A note on the title: You should find a better one. You make it sound like `strcmp()` wouldn't work correctly, which definitely is not the case ... Furthermore, to be a [mcve], you need to provide a sample file and a sample input, as well as the expected and the actual output of your program. –  Oct 25 '17 at 06:51
  • 1
    Says you. How do you know if you don't verify it? – M Oehm Oct 25 '17 at 06:51
  • 1
    Start as you mean to continue: check them anyway, particularly with user input - even if you are the user. – Weather Vane Oct 25 '17 at 06:51
  • 2
    @JessicaPereira maybe that's not the problem here, but you should check anyway. The user could invoke your program with invalid arguments and the output file may not be able to be created for whatever reason. – Jabberwocky Oct 25 '17 at 06:52
  • 2
    "maybe it has the extra space that I get on the command line, I don't know" -- Why not print the strings with defined delimiters to find out, e.g. `printf("<%s>\n", str)`? Or use a debugger that will give you the C representation of the strigs you compare? Such things are easy to find out. – M Oehm Oct 25 '17 at 06:54
  • @MichaelWalz thank you, updated it, the way I test it , fo is never null and argc is never less than 5. That's not the issue... – Jess Oct 25 '17 at 06:56
  • Note: having removed the newline before using `strcmp` you will need to output a newline too by including `\n` in both of the `fprintf` statements. But I guess you don't like taking advice. – Weather Vane Oct 25 '17 at 06:57
  • @MOehm that's the type of answers I was hoping to get, thank you! Also I tried with strtok, but no joy, and I found something about getopt() but I need to read more about it and I don't know if it will fix the issue or not. But I'm hoping it will. Thank you once again, I'll test it like that to see :-) – Jess Oct 25 '17 at 07:00
  • @JessicaPereira `getopt()` is totally unrelated to your problem. You need to remove the `\n` at the end of the line you've read from the input file. Several comments already say so. – Jabberwocky Oct 25 '17 at 07:02
  • 1
    If you wonder why `strcmp(a, b)` evaluates to false, then examine the content of `a` and `b`. – klutt Oct 25 '17 at 07:06
  • @MichaelWalz I will check all that, thank you for all the responses, and yes and I'm the user, and this is just a simple code to test on my own, nothing extraordinary, what I need to know is why strcmp is always saying the words are not equal when before it was saying they were equal when I had only 1 string in the file, and I think it has to do with the way strings and strings in files are handled by the compiler. Maybe the \n or and extra space, I don't know, and thank you all for the answers, I'll sure have a look and test it and read all, but for now I'm worried about it not replacing it – Jess Oct 25 '17 at 07:07
  • @WeatherVane lol? I know I have to put \n on the fprintf IF I want the output to have the strings separated with \n, that was not my question but thank you anyway for informing me of that, and I DO like to that advise, but I also like to not be misunderstood or misinterpreted, like I think I was just now by you... and I have to apoligise for that because that is not what I want you to say, I DO like to that advise. Thank you. – Jess Oct 25 '17 at 07:19
  • @WeatherVane I'll sure have a look at that as well! Thank you :-) – Jess Oct 25 '17 at 07:21
  • 1
    Presumably the program was creating a new output file just like the input file - but the code does not specifically write any newline: there is no `\n` in your `fprintf` statements. So where does the newline come from that is in the output file? Answer: it was read by `fgets` from the input file, and also prevented the string comparison test. – Weather Vane Oct 25 '17 at 07:23

3 Answers3

1

The problem is the \n at the end of the str buffer. fgets adds the \n at end end of the line it reads, you need to get rid of it before comparing.

This is what you need:

  while (fgets(str, 60, fp) != NULL) {

    /* remove \n from at the end of the str buffer*/    
    char *pos;
    if ((pos = strchr(str, '\n')) != NULL)
      *pos = '\0';

    /* print str enclosed in <> so we can see what str actually contains */
    printf("Inside the loop, got the string: <%s>\n", str);

    if (strcmp(compare, str) == 0) {
      printf("Found it! %s\n", str);
      fprintf(fo, "%s\n", replace);
    }
    else {
      fprintf(fo, "%s\n", str);
    }
  }

Look at the comments in the code for explanations.

Jabberwocky
  • 48,281
  • 17
  • 65
  • 115
1

read.c

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

/**
* How to compile program:
*    gcc read.c -o read
*
* How to run the program: 
*      .> ./read input.txt rainy output.txt sunny
* (On Windows MinGW compiler, simply: 
*      .> read input.txt rainy output.txt sunny - without ./)
*
*/
int main (int argc, char **argv) {
   FILE *fp, *fo;
   char *compare, *replace;
   char line[246];

   if (argc <= 4){
      printf(">Missing arguments on the command line.\n");
      printf(">Be sure you run the program as\n\"./read input.txt compare outout.txt replace\"\n\n");
   }

   /* Opening files for reading */
   fp = fopen(argv[1] , "r");
   if(fp == NULL){
      perror("Error opening input file");
      return 1;
   }
   compare = argv[2];

   fo = fopen(argv[3], "w");
   if(fo == NULL){
      perror("Error opening output file");
      return 1; 
   }
   replace = argv[4];

   while( fgets (line, (sizeof line), fp)!=NULL ) {
      line[strcspn(line, "\n")] = 0;
       if(strcmp(compare, line) == 0){
         printf("Found it! %s \n", line);
         fprintf(fo, "%s\n", replace);
      }
      else{
         fprintf(fo, "%s\n", line);
      } 
   }
   fclose(fp);
   fclose(fo);
   return 0;
}

/* 
Important info

strcspn :: 
Locate first occurrence of character in string, 
after locating the first occurrence of \n, replaces it by 0.


Sources::
https://stackoverflow.com/questions/2693776/removing-trailing-newline-character-from-fgets-input/28462221#28462221

Used to debug:
.>printf("1st: Reads input.txt, removes '\\n' from fgets, and prints it \n");
.>printf("2nd: Compares each line with 'rainy' \n");


.>printf("<%s>\n", line);

*/

input.txt

cloudy
rainy
chilly
rainy
rainy
Jess
  • 85
  • 12
0

Your approach fails because the lines read from the input file contain a trailing newline '\n' that makes the comparison return non zero.

You can strip the newline before comparing with the search string.

Note that there are other problems:

  • you should verify that enough command line arguments have been passed by testing argc > 4.
  • there is no need to open the output file in update mode "w+", "w" is simpler and better.
  • 60 bytes is a bit small for the line array, limiting the longest line handled correctly to 58 bytes.

Here is an improved version:

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

int main(int argc, char **argv) {
    FILE *fp, *fo;
    char *compare, *replace;
    char line[256];

    if (argc <= 4) {
        printf("missing command line arguments\n");
        return 1;
    }
    fp = fopen(argv[1], "r");
    if (fp == NULL) {
        perror("Error opening input file");
        return 1;
    }
    compare = argv[2];
    fo = fopen(argv[3], "w");
    if (fo == NULL) {
        perror("Error opening output file");
        return 1;
    }
    replace = argv[4];

    while (fgets(line, sizeof line, fp) != NULL) {
        line[strcspn(line, "\n")] = '\0';
        if (strcmp(line, compare) == 0) {
            printf("fount it!);
            fprintf(fo, "%s\n", replace);
        } else {
            fprintf(fo, "%s\n", line);
        }
    }
    fclose(fp);
    fclose(fo);

    return 0;
}

Note that long lines will be broken into chunks that fit in the line array, so there may be false positives with the above naive approach.

You can remove this limitation completely with this inner loop:

int c;
int pos = 0;
int cmplen = strlen(compare);
for (;;) {
    c = getc(fp);
    if (c == '\n' || c == EOF) {
        if (pos == cmplen) {
            fprintf(fo, "%s", replace);
        } else
        if (pos > 0) {
            fprintf(fo, "%*s", pos, compare);
        }
        pos = 0;
        if (c == EOF)
            break;
    } else {
        if (pos >= 0) {
            if (compare[pos] == (char)c) {
                pos++;
                continue;
            }
            if (pos > 0) {
                fprintf(fo, "%*s", pos, compare);
            }
            pos = -1;
        }
    }
    putc(c, fo);
}
chqrlie
  • 131,814
  • 10
  • 121
  • 189