2

I have a school assignment where I am supposed to create three functions. The functions are printFirstWord(), skipWords() and printWord().

Albeit not perfectly written, I have managed to make the printFirstWord function work and the other two functions mostly work fine.

However, in skipWords() I am supposed to return a pointer value of NULL if the amount of words that you wish to skip is greater than the amount of words in the string you input. This is my code:

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

//Call the functions
void printFirstWord(char inputString[]);
char* skipWords(char sentence[], int words);
void printWord(char sentence[], int wordNumber);

int main()
{
    printWord("I like to eat bunnies", 0); //Prints I
    printWord("I like to eat bunnies", 1); //Prints like
    printWord("I like to eat bunnies", 2); //etc
    printWord("I like to eat bunnies", 3);
    printWord("I like to eat bunnies", 4);
    printWord("I like to eat bunnies", 5); //This should return NULL
    printWord("I like to eat bunnies", 6); //This should return NULL

    return 0;
}

//Function that prints only the first word of a string
void printFirstWord(char inputString[])
{
    int i = 0;

    //Removes initial non-alpha characters, if any are present
    while (!isalpha(inputString[i]))
        i++;

    //Checks if the next input is alphabetical or is the character '-'
    while (inputString[i] != ' ')
    {
        printf("%c", inputString[i]);
        i++;
    }

}

char* skipWords(char sentence[], int words)
{
    int i = 0, wordCount = 0;

    for(i = 0; wordCount < words; i++)
    {
        if(sentence[i] == ' ')
        {
            wordCount++;
        }
    }

    //Can't get this to work, not sure how to return NULL in a function
    if (words >= wordCount)
        return NULL;
    else
        return &sentence[i];
}

void printWord(char sentence[], int wordNumber)
{
    char *sentencePointer;
    sentencePointer = skipWords(sentence, wordNumber);

    if (sentencePointer != NULL)
        printFirstWord(sentencePointer);
    else if (sentencePointer == NULL)
        printf("\nError. Couldn't print the word.\n");
}

Initially my problem was that the program constantly crashed but I added the last part of the printWord function and it stopped crashing. I expect this output:

Iliketoeatbunnies

Error. Couldn't print the word.

Error. Couldn't print the word.

This is the output I am receiving:

Error. Couldn't print the word.

Error. Couldn't print the word.

Error. Couldn't print the word.

Error. Couldn't print the word.

Error. Couldn't print the word.

Error. Couldn't print the word.

Pointers are my weak side and I feel like I have missed something crucial, I have been looking online and I haven't found any solution that fits me yet or atleast that I feel doesn't fit me.

Assignment Description

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
lemonslayer
  • 171
  • 10
  • The input will be single space separated string? – user2736738 Dec 13 '17 at 18:03
  • 1
    What is a word ? Why post image instead of good Unicode text ? – Stargateur Dec 13 '17 at 18:04
  • @coderredoc The input will be a sentence with several words and the function is supposed to point to the word the user chooses (int words). Basically what I did was that for every single space occuring then the program knows another word has started. It's very simple but it does what it needs to do for now. – lemonslayer Dec 13 '17 at 18:05
  • 1
    Hint: Some of your loops need to exit when the end of string is reached. – Jim Rhodes Dec 13 '17 at 18:07
  • @Stargateur Sorry, I tried to add it however for some reason the text doesn't want to properly C+P, the text is from a PowerPoint presentation. – lemonslayer Dec 13 '17 at 18:07
  • @ArunAS Well, the loop counts the amount of words in the string (i.e. how many single space occurs). It's very primitive but it works for what I need it to do. However what I was thinking with the loop was that the loop would continue counting until it reaches the amount of words that you wished to skip (int words). I might have been thinking wrong but writing i – lemonslayer Dec 13 '17 at 18:12
  • 1
    @lemonslayer when copying formatted text, I sometimes find it easier to first paste it into a plain text editor, then copy/paste from there, finally adding any formatting needed by the destination. – Weather Vane Dec 13 '17 at 18:14
  • @WeatherVane Thank you! I'll think about this for future posts! – lemonslayer Dec 13 '17 at 18:21
  • @lemonslayer The function printWord returns nothing. So a question arises what the function should do in this call printWord("I like to eat bunnies", 5);? – Vlad from Moscow Dec 13 '17 at 18:22
  • @VladfromMoscow The function is printWord(char sentence[], int wordNumber). So calling printWord("I like to eat bunnies", 5); would set the string and the word number which you want to display. For example, setting wordNumber to 3 would display the 4th word of the string and print it out. A part of the assignment was not returning anything in the function and merely printing out the results. – lemonslayer Dec 13 '17 at 18:25
  • @lemonslayer One more what the function should do in this call printWord("I like to eat bunnies", 5);? – Vlad from Moscow Dec 13 '17 at 18:26
  • @VladfromMoscow It should return a an error since the amount of words you want to skip (5) is higher or equal to the amount of words in the string. I.e. it should print out "Error. Could not print the word." – lemonslayer Dec 13 '17 at 18:29

4 Answers4

1

There are few bugs in your code. Corrections would be

for(i = 0; sentence[i] && wordCount < words; i++)

Another is

while (inputString[i] !=' ' && inputString[i]!='\0')

And the last

if (words > wordCount)

Explanation for first one would be - you wont check past the end of the string. Otherwise you had undefined behavior.

There maybe cases when you reach the end of the string but still won't get a space. To avoid that case you need to consider the \0 case too.

If the words > wordCount then only you should throw the error. If they are equal then it should print the value.

user2736738
  • 30,591
  • 5
  • 42
  • 56
  • Ah, the first correction was something I was thinking about because technically it wouldn't stop reading the last word and continue "outside of the string". Regarding the last correction, what exactly happened when I wrote >= instead of > ? I'm guessing that it would always be equal to eachother which is why it always returned NULL? – lemonslayer Dec 13 '17 at 18:19
  • @lemonslayer.: Yes – user2736738 Dec 13 '17 at 18:56
1

This loop in skipWords is the problem. It'll traverse through the string and beyond because you're not checking for the end of the string.

for(i = 0; wordCount < words; i++)
{
    if(sentence[i] == ' ')
    {
        wordCount++;
    }
}

Since the only way out of the loop is for it to find as many spaces as you've passed in as words, it will always return NULL.

Arguably wordCount should also start at 1 since if there are no spaces in the string, you'll always have at least one word...unless the string is empty.

Chris Turner
  • 8,082
  • 1
  • 14
  • 18
  • Yes I realized the loop was acting weird since it didnt rly stop after the last word. I agree the wordCount should start at 1 but the assignment was very clear that it should start at 0. So I guess I'll have to fidn a solution to this some way. – lemonslayer Dec 13 '17 at 18:27
1

Your algorithm in skipWords() is broken, I will implement your function by changing the algorithm and change int to size_t:

#include <stdio.h>
#include <stddef.h>
#include <ctype.h>

int printFirstWord(char const *inputString);
char const *skipWords(char const *sentence, size_t words);
int printWord(char const *sentence, size_t wordNumber);

int main(void) {
  printWord("I like to eat bunnies", 0); // Prints I
  printf("\n");
  printWord("I like to eat bunnies", 1); // Prints like
  printf("\n");
  printWord("I like to eat bunnies", 2); // etc
  printf("\n");
  printWord("I like to eat bunnies", 3);
  printf("\n");
  printWord("I like to eat bunnies", 4);
  printf("\n");
  printWord("I like to eat bunnies", 5); // This should return NULL
  printf("\n");
  printWord("I like to eat bunnies", 6); // This should return NULL
  printf("\n");
}

int printFirstWord(char const *inputString) {
  int ret = 0;
  while (isblank(*inputString)) {
    inputString++;
  }
  while (!isblank(*inputString) && *inputString) {
    int tmp = printf("%c", *inputString++);
    if (tmp < 0) {
      return -1;
    }
    ret += tmp;
  }
  return ret;
}

char const *skipWords(char const *inputString, size_t words) {
  while (isblank(*inputString)) {
    inputString++;
  }
  while (words > 0) {
    words--;
    while (!isblank(*inputString)) {
      if (!*inputString) {
        return NULL;
      }
      inputString++;
    }
    while (isblank(*inputString)) {
      inputString++;
    }
  }
  return *inputString ? inputString : NULL;
}

int printWord(char const *sentence, size_t wordNumber) {
  char const *sentencePointer = skipWords(sentence, wordNumber);
  if (sentencePointer != NULL) {
    return printFirstWord(sentencePointer);
  } else {
    fprintf(stderr, "Error. Couldn't print the word.\n");
    return -1;
  }
}
Stargateur
  • 24,473
  • 8
  • 65
  • 91
  • This is way too advanced for where I am in the course, however I will save this and look through it so I can better my coding! What does changing int to size_t do? – lemonslayer Dec 13 '17 at 18:38
  • @lemonslayer "This is way too advanced" => This is on purpose so you can't copy paste the code unless you understand it ;). "size_t" => https://stackoverflow.com/a/2550799/7076153, `int` is a signed integer with few guarantee, does it make sense for you to write `printWord("I like to eat bunnies", -1);` ? Well one could say it would be on possible value depend on the behavior wanted, but acording to your exercice, your integer is not expected to be negative so use an unsigned type make sense. Plus `size_t` is capable of handle any index size what make it very useful. – Stargateur Dec 13 '17 at 18:44
1

We beginners should help each other.:)

Here you are

#include <stdio.h>
#include <ctype.h>

char * skipWords( const char *s, size_t n )
{
    if ( n )
    {
        while ( isblank( ( unsigned char )*s ) ) ++s;

        do
        {
            while ( *s && !isblank( ( unsigned char )*s ) ) ++s;
            while ( isblank( ( unsigned char )*s ) ) ++s;
        } while ( *s && --n );
    }

    return ( char * ) ( *s ? s : NULL );
}

void printFirstWord( const char *s )
{
    while ( isblank( ( unsigned char )*s ) ) ++s;
    while ( *s && !isblank( ( unsigned char )*s ) ) putchar( *s++ );
}

void printWord( const char *s, size_t n )
{
    const char *word = skipWords( s, n );

    if ( word )
    {
        printFirstWord( word );
    }
    else
    {
        printf( "%s", "Error. Could not print the word." );
    }

    putchar( '\n' );
}

int main(void) 
{
    printWord("I like to eat bunnies", 0); //Prints I
    printWord("I like to eat bunnies", 1); //Prints like
    printWord("I like to eat bunnies", 2); //etc
    printWord("I like to eat bunnies", 3);
    printWord("I like to eat bunnies", 4);
    printWord("I like to eat bunnies", 5); //This should return NULL
    printWord("I like to eat bunnies", 6); 

    return 0;
}

The program output is

I
like
to
eat
bunnies
Error. Could not print the word.
Error. Could not print the word.

As for your code then you usually do not check the terminating zero as for example

while (inputString[i] != ' ')
{
    printf("%c", inputString[i]);
    i++;
}

and ignore cases when several spaces follow each other.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335