-1

I need help completing this function so that it correctly returns the the number of words in the c-string. Maybe my logic is wrong ?

#include <iostream>
#include <string>
#include <cctype>
int countwords(char *, int);
using namespace std;

int main()
{
    char a[] = "Four score and seven";
    int size = sizeof(a)/sizeof(char);
    cout << countwords(a,size);

    return 0;
}

int countwords(char* a, int size){
    int j = 0;
    for(int i = 0; i < size; i++){
        if(isspace(i) and isalnum(i - 1) and isalnum(i + 1))
            j++;
    }

    return j;
}
Amber Roxanna
  • 1,665
  • 4
  • 24
  • 30
  • You're not using `a` anywhere in that loop? – ChiefTwoPencils Dec 01 '13 at 21:32
  • You should probably be using something like `std::find` instead of going through to make your intent clear. You'll also need to make sure you don't go out of bounds with the previous and next character checks. Finally, it should be `const char *a` if using a C string. You're not modifying it and it's really annoying using a function that takes a non-const parameter, but doesn't modify it. – chris Dec 01 '13 at 21:34
  • Also, once you fix `a[i...]`, as written you'll get an off by one error as there will be no space at the end to allow for the last word, which could actually fail the condition anyway due to `isalnum(i + 1)`. – ChiefTwoPencils Dec 01 '13 at 21:41
  • Googling the answer (which I bet exists more than a 100 times on the Internet), though a lot more efficient, doesn't get you to virtually meet us sexy male programmers, right? ;-) – Petr Skocik Dec 01 '13 at 21:54
  • Uh, really @ThorX89 ? o_O – Joe Z Dec 02 '13 at 02:10

4 Answers4

2

You are passing the value of i to these functions instead of a[i]. That means you're testing if your loop variable is a space (for example), rather than the character at that position in the a array.

Once you have fixed that, understand that you can't blindly reference a[i-1] in that loop (because of the possibility of accessing a[-1]. You will need to update your logic (note also you must use && for logical AND, not and).

I suggest using a flag to indicate whether you are currently "inside" a word. And reset that flag whenever you decide that you are no longer inside a word. eg

int inside = 0;
for (int i = 0; i < size; i++) {
    if (alnum(a[i])) {
        if (!inside) {
            inside = 1;
            j++;
        }
    } else {
        inside = 0;
    }
}

Also, please use strlen(a) instead of sizeof(a)/sizeof(char). If you continue that practice, you're bound to have an accident one day when you try it on a pointer.

paddy
  • 60,864
  • 6
  • 61
  • 103
0

This loop is invalid

for(int i = 0; i < size; i++){
    if(isspace(i) and isalnum(i - 1) and isalnum(i + 1))

First of all you does not check characters of the string whether they are spaces or alphanumeric. You check variable i whicj has nothing common with the content of the string. Moreover you have an intention to access memory beyond the array

As you are dealing with a string I would declare the function the following way

size_t countwords( const char *s );

It could be defined as

size_t countwords( const char *s )
{
    size_t count = 0;

    while ( *s )
    {
        while ( isspace( *s ) ++s;
        if ( *s ) ++count;
        wjile ( isalnum( *s ) ++s;
    }

    return ( count );
}

I do not take into account punctuation symbols. Otherwise you should substitute isspace for !isalnum.

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

A simpler version would be to repeatedly call strtok() on the string, and each time that an element is returned, you can increment a word count. This would take care of doubled spaces, and so on. You could even split two words with a comma but no space ("this,error") without difficulty.

something along the lines of:

do {
  s = strtok(s," ,.;");
  if (s) wordcount++;
 } while(s);

The only immediate disadvantage is that strtok is destructive, so make a copy before starting.

russellm
  • 155
  • 7
0

To count the number of words, you merely need to count the number of times you see a non-whitespace character after a whitespace character. To get things right at the start of the string, assume there is "whitespace" to the left of the string.

int countwords(char* a, int size) {
    bool prev_ws = true;  // pretend like there's whitespace to the left of a[]
    int words = 0;

    for (int i = 0; i < size; i++) {
        // Is the current character whitespace?
        bool curr_ws = isspace( (unsigned char)a[i] ); 

        // If the current character is not whitespace, 
        // but the previous was, it's the start of a word.
        if (prev_ws && !curr_ws) 
            words++;

        // Remember whether the current character was 
        // whitespace for the next iteration.
        prev_ws = curr_ws;
    }

    return words;
}

You might also notice I included a cast to unsigned char on the call to isspace(). On some platforms, char defaults to signed, but the classifier functions isspace and friends aren't guaranteed to work with negative values. The cast forces all the values to be positive. (More details: http://en.cppreference.com/w/cpp/string/byte/isspace )

Joe Z
  • 17,413
  • 3
  • 28
  • 39