Home > Software engineering >  How can I use strcmp function instead of strstr to find a specific substring in a string - C
How can I use strcmp function instead of strstr to find a specific substring in a string - C

Time:10-11

Being very new to C, I have encountered obstacles while attempting to use the strcmp function.

I need to search in the following txt type string for a specific substring that the user wishes to find in it. If the word searched by the user exists, a success message appears on the screen, if not, an error message is shown.

I have tried using an array and a for loop to read every word of the txt string, but I couldn't understand how to do it. This was my attempt:

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

#define SIZE 9910

int main(void) {
    char wordSearched[50];
    int index;
    int return;
    char txt[SIZE] = "1   In the beginning God created the heaven and the earth. 2   And the earth was without form and void, and darkness was upon the face of the deep. And the Spirit of God moved upon the face of the waters. 3   And God said, Let there be light: and there was light. 4   And God saw the light, that it was good: and God divided the light from the darkness. 5   And God called the light Day, and the darkness he called Night. And the evening and the morning were the first day. 6   And God said, Let there be a firmament in the midst of the waters, and let it divide the waters from the waters. 7   And God made the firmament, and divided the waters which were under the firmament from the waters which were above the firmament: and it was so. 8   And God called the firmament Heaven. And the evening and the morning were the second day. 9   And God said, Let the waters under the heaven be gathered together unto one place, and let the dry land appear: and it was so. 10   And God called the dry land Earth, and the gathering together of the waters called he Seas: and God saw that it was good. 11   And God said, Let the earth bring forth grass, the herb yielding seed, and the fruit tree yielding fruit after his kind, whose seed is in itself, upon the earth: and it was so. 12   And the earth brought forth grass, and herb yielding seed after his kind, and the tree yielding fruit, whose seed was in itself, after his kind: and God saw that it was good. 13   And the evening and the morning were the third day. 14   And God said, Let there be lights in the firmament of the heaven to divide the day from the night, and let them be for signs, and for seasons, and for days, and years. 15   And let them be for lights in the firmament of the heaven to give light upon the earth: and it was so. 16   And God made two great lights; the greater light to rule the day, and the lesser light to rule the night: he made the stars also. 17   And God set them in the firmament of the heaven to give light upon the earth, 18   And to rule over the day and over the night, and to divide the light from the darkness: and God saw that it was good. 19   And the evening and the morning were the fourth day. 20   And God said, Let the waters bring forth abundantly the moving creature that hath life, and fowl that may fly above the earth in the open firmament of heaven. 21   And God created great whales and every living creature that moveth, which the waters brought forth abundantly, after their kind, and every winged fowl after his kind: and God saw that it was good. 22   And God blessed them, saying, Be fruitful, and multiply, and fill the waters in the seas, and let fowl multiply in the earth. 23   And the evening and the morning were the fifth day. 24   And God said, Let the earth bring forth the living creature after his kind, cattle, and creeping thing, and beast of the earth after his kind: and it was so. 25   And God made the beast of the earth after his kind, and cattle after their kind, and everything that creepeth upon the earth after his kind: and God saw that it was good. 26   And God said, Let us make man in our image, after our likeness: and let them have dominion over the fish of the sea, and over the fowl of the air, and over the cattle, and over all the earth, and over every creeping thing that creepeth upon the earth. 27   So God created man in his own image, in the image of God created he him; male and female created he them. 28   And God blessed them, and God said unto them, Be fruitful, and multiply, and replenish the earth, and subdue it: and have dominion over the fish of the sea, and over the fowl of the air, and over every living thing that moveth upon the earth. 29   And God said, Behold, I have given you every herb bearing seed, which is upon the face of all the earth, and every tree, in the which is the fruit of a tree yielding seed; to you, it shall be for meat. 30   And to every beast of the earth, and to every fowl of the air, and to everything that creepeth upon the earth, wherein there is life, I have given every green herb for meat: and it was so. 31   And God saw every thing that he had made, and, behold, it was very good. And the evening and the morning were the sixth day.";

    printf("\n\n");

    printf("Insert the word you wish to find: ");
    scanf("\n%s", wordSearched);

    for (index = 0; index < SIZE; index  ) {
        return = strcmp(txt, wordSearched);
        index = index   1;
        // here I thought I could use index   to skip to the next set of characters
    }
    printf("Return: %i", return);
  
    return 0;
}

I also tried removing the for loop, but it still didn't work.

CodePudding user response:

Some problems I noticed are

  • The index was being incremented twice.
  • The index was never getting used to "skip to the next set of characters".
  • You need to use strncmp so that only the length of the wordSearched needs to be matched.
#include <stdio.h>
#include <string.h>
#define SIZE 9910

int main(void) {
  char wordSearched[50];
  int index;
  int ret;
  char txt[SIZE] = "Long string of text";

  printf("\n\n");

  printf("Insert the word you wish to find: ");
  scanf("\n%s", wordSearched);

  for (index = 0; index < SIZE; index  ){
    ret = strncmp(txt index, wordSearched, strlen(wordSearched));
    if(ret == 0) {
      printf("%s found at index: %d\n", wordSearched, index);
      break; // remove this break if you want to find all matches
    }
  }
  
  if(ret != 0) {
    printf("%s was not found\n", wordSearched);
  }

  return 0;
}

There is some unnecessary code here, but I have left it as close to your original as possible so it is easier to spot the differences. I also renamed the return variable to ret.

edit: As chqrlie pointed out, this would run through the entire array of characters up to SIZE even if the actual text is shorter. It will be quicker and safer to only loop until the '\0' character is found indicating the end of your string.

Also, Craig Estey recommended doing the strlen before the loop since the length of the string is not going to change so there is no need to recalculate it every time.

With these changes the code would look like

#include <stdio.h>
#include <string.h>
#define SIZE 9910

int main(void) {
  char wordSearched[50];
  size_t wordlen;
  int index;
  int ret=-1;
  char txt[SIZE] = "Long string of text";

  printf("\n\n");

  printf("Insert the word you wish to find: ");
  scanf("\n%s", wordSearched);
  wordlen = strlen(wordSearched);

  for (index = 0; txt[index] != '\0'; index  ){
    ret = strncmp(txt index, wordSearched, wordlen);
    if(ret == 0) {
      printf("%s found at index: %d\n", wordSearched, index);
      break; // remove this break if you want to find all matches
    }
  }
  
  if(ret != 0) {
    printf("%s was not found\n", wordSearched);
  }

  return 0;
}

CodePudding user response:

SO SOP is that a critique of your code should come first. In short, if scanf() didn't fail, the OP code loops 4955 times (9910/2), comparing the input "word" with the beginning characters of the text. Heaven help us all.

Using a smaller and less controversial text, the following code finds the entered string (including embedded spaces, but not leading or trailing spaces) and prints out the entire 'line' containing that word. It then continues searching and will output subsequent occurrences, too. (The character index(es) have been found, but are not printed in this example.) This uses tolower() to achieve case-insensitivity.

#include <stdio.h>
#include <string.h> // just found out 'tolower' defined here, too!

int mmain() {
    char txt[] =
        "'Twas brillig, and the slithy toves\n"
        "Did gyre and gimble in the wabe:\n"
        "All mimsy were the borogoves,\n"
        "And the mome raths outgrabe.\n\n"
        "Beware the Jabberwock, my son!\n"
        "The jaws that bite, the claws that catch!\n"
        "Beware the Jubjub bird, and shun\n"
        "The frumious Bandersnatch!\n\n"
        "He took his vorpal sword in hand;\n"
        "Long time the manxome foe he sought\n"
        "So rested he by the Tumtum tree\n"
        "And stood awhile in thought.\n\n"
        "And, as in uffish thought he stood,\n"
        "The Jabberwock, with eyes of flame,\n"
        "Came whiffling through the tulgey wood,\n"
        "And burbled as it came!\n\n"
        "One, two! One, two! And through and through\n"
        "The vorpal blade went snicker-snack!\n"
        "He left it dead, and with its head\n"
        "He went galumphing back.\n\n"
        "And hast thou slain the Jabberwock?\n"
        "Come to my arms, my beamish boy!\n"
        "O frabjous day! Callooh! Callay!\n"
        "He chortled in his joy.\n\n"
        "'Twas brillig, and the slithy toves\n"
        "Did gyre and gimble in the wabe:\n"
        "All mimsy were the borogoves,\n"
        "And the mome raths outgrabe.\n";

    for( ;; ) {
        char word[ 32 ]; // big enough??
        printf( "\nFind: ");
        scanf( " 1[^\n]", word );
        if( stricmp( word, "quit" ) == 0 )
            break;

        // 3 index variables to have 'scope' in this block
        for( int i = 0, ii, iii; txt[i]; i   ) {
            while( txt[i] && txt[i] != word[0] ) i  ; // scan to match first letter of word
            for( ii = 1; txt[i ii] && tolower(txt[i ii]) == tolower(word[ii]); ii   )
                ; //try to match whole word
            if( word[ii] == '\0' ) {
                for( iii = i ii; iii > 0 && txt[iii-1] != '\n'; iii-- )
                    ; // scan to beginning of line
                while( txt[iii] && txt[iii] != '\n' )
                    putchar( txt[iii  ] ); // output the line
                putchar( '\n' );
            }
        }
    }

    return 0;
}
Find: vorpal
He took his vorpal sword in hand;
The vorpal blade went snicker-snack!

Find: frumious
The frumious Bandersnatch!

Find: quit
  • Related