-1

I have a problem which i cant fix i need to check last three words of frist sentence with last three words of fourth sentence

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


int main() {

char firstRow[256];
char secondRow[256];
char thirdRow[256];
char fourthRow[256];

printf("Enter four row of lyrcis:\n");
gets(firstRow);
gets(secondRow);
gets(thirdRow);
gets(fourthRow);

if ( strcmp(a1+strlen(a1)-1, a4+strlen(a4)-1) &&
     strcmp(a1+strlen(a1)-2, a4+strlen(a4)-2) &&
     strcmp(a1+strlen(a1)-3, a4+strlen(a4)-3)  == 0 ){

    printf("Good job last three words of first and fourth sentence are same");

}
else {

    printf("nothing");

}

return 0;
}

This is something i tried but obviously problem is that i cant use if like that with only one strcmp it works. Maybe i need strcpy command? Help!

jovkm
  • 27
  • 6
  • 1
    Don't ever use `gets`. It's a dangerous functions and for that reason have been removed from the C standard. – Some programmer dude Nov 12 '17 at 19:25
  • Your comparison also don't work, on many different levels. First of all your code says that if the first and second `strcmp` *fails* and the third `strcmp` succeeds, then you say that all is matching. And you're not comparing "words". – Some programmer dude Nov 12 '17 at 19:27
  • Perhaps you should take a step back. Your problem is "How to read a single sentence and split it into words" – Antti Haapala -- Слава Україні Nov 12 '17 at 19:52
  • See [`gets()` is too dangerous to be used — ever](https://stackoverflow.com/questions/1694036/why-is-the-gets-function-dangerous-why-should-it-not-be-used) for details of the problems with `gets()` and the alternatives that are available. – Jonathan Leffler Nov 12 '17 at 23:08

1 Answers1

0

First -- Do not use 'gets'. It is horribly insecure. There is no limitation on the number of characters it will read or whether the size of the buffer you provide has adequate storage. That allows for buffer overrun exploits and is the primary reason it has been dropped from the C library. If your professor insists on using it -- find a new professor.

The other problem you have is failing to validate each step in your process. You fail to check if gets actually read anything before passing the pointers to strcmp or strlen.

Further, your indexing is nonsense. strlen(x) - n doesn't index the end - n word in the buffer. For that you have to tokenize the string (split it into words). There are a number of ways to do it.

One method that works no matter what is simply finding the end of the string (e.g. strlen(line) - 1) and using a pointer to iterate from the end of the string towards the start until your first whitespace is found (or you reach the beginning).

The C library (in string.h) provides strrchr which automates that process for you. It will start at the end of a string and iterate backwards until it finds the first occurrence of the character you tell it to find returning a pointer to that character (or returning NULL it that character is not found). The only downside here is you are limited to search for a single character.

The C library (in string.h) provides strtok, which does not provide for a reverse search, but does provide the ability to split a string based on a set of delimiters you provide (e.g. it could handle splitting on any one of space, tab, '.', etc..). Here you simply store the pointers to each of the words (or a copy of the words) and take the last 3 indexes for comparison.

The following provides an example that uses strrchr presuming your words or separated by one (or more) spaces. Both the method used below and strtok modify the original string, so make a copy of a string before parsing if the string is originally stored in read-only memory (e.g. a string literal).

The program expects the filename to read to be provided as the first argument (or it will read from stdin if no argument is provided). Additional comments are provided in the code, in-line, below:

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

#ifndef BUF_SIZ         /* if you need constants... define them */
#define BUF_SIZ 8192    /* don't put 'magic' numbers in code   */
#endif

#define NLAST 3

int main (int argc, char **argv) {

    size_t len = 0;
    char line1[BUF_SIZ] = "",
         line4[BUF_SIZ] = "",
         *last[NLAST] = { NULL };
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

    if (!fp) {  /* validate file open for reading */
        fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
        return 1;
    }

    if (fgets (line1, BUF_SIZ, fp) == NULL) {   /* read 1st line */
        fprintf (stderr, "error: failed to read line1.\n");
        return 1;
    }

    for (int i = 0; i < NLAST; i++) /* read/discard lines 2,3 read line 4 */
        if (fgets (line4, BUF_SIZ, fp) == NULL) {
            fprintf (stderr, "error: failed to read line4.\n");
            return 1;
        }

    if (fp != stdin) fclose (fp);       /* close file if not stdin */

    len = strlen (line1);               /* get length of line1 */
    if (len && line1[len-1] == '\n')    /* validate last is '\n' */
        line1[--len] = 0;               /* overwrite with nul-character */
    else {              /* error: handle line too long or no POSIX EOL */
        fprintf (stderr, "error: line1 too long or no POSIX EOL.\n");
        return 1;
    }

    len = strlen (line4);               /* same thing for line4 */
    if (len && line4[len-1] == '\n')
        line4[--len] = 0;
    else {
        fprintf (stderr, "error: line4 too long or no POSIX EOL.\n");
        return 1;
    }

    if (!*line1 || !*line4) {   /* test if either is empty-string */
        fprintf (stderr, "error: one or both line(s) empty.\n");
        return 1;
    }

    for (int i = 0; i < NLAST; i++) {       /* loop NLAST times */
        char *p1 = strrchr (line1, ' '),    /* get pointer to last ' ' */
             *p4 = strrchr (line4, ' ');

        if (!p1) {                  /* validate result of strrchr */
            if (i < NLAST - 1) {    /* if not last iteration - handle error */
                fprintf (stderr, "error: only '%d' words in line1.\n", i+1);
                return 1;
            }
            else    /* if last iteration, assign line to pointer */
                p1 = line1;
        }
        if (!p4) {                  /* same for line4 */
            if (i < NLAST - 1) {
                fprintf (stderr, "error: only '%d' words in line4.\n", i+1);
                return 1;
            }
            else
                p4 = line1;
        }
        /* copy to last array in order - checking if p1 is beginning of line */
        last[NLAST - 1 - i] = p1 == line1 ? p1 : p1 + 1;   

        while (p1 > line1 && *p1 == ' ')    /* nul-terminate at space */
            *p1-- = 0;
        while (p4 > line4 && *p4 == ' ')
            *p4-- = 0;
    }

    printf ("\nthe last %d words in lines 1 & 4 are the same:\n", NLAST);
    for (int i = 0; i < NLAST; i++)
        printf ("  %s\n", last[i]);

    return 0;
}

Example Input File

$ cat dat/last14-3.txt
My dog has fleas
My snake has none
The cats have none
Cats are lucky because the dog has fleas

Example Use/Output

$ ./bin/lines1_4_last3 < dat/last14-3.txt

the last 3 words in lines 1 & 4 are the same:
  dog
  has
  fleas

Regardless which method you choose to tokenize the lines, you must validate each step along the way. Look things over and make sure you understand why each validation was necessary, if not, just ask and I'm happy to help further.

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85