2013-12-01 4 views
-1

Мне нужна помощь в выполнении этой функции, чтобы она правильно вернула количество слов в c-строке. Может быть, моя логика ошибочна?Подсчет слов в строке c

#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; 
} 
+0

Вы не используете 'a' нигде в этом цикле? – ChiefTwoPencils

+0

Вы, вероятно, должны использовать что-то вроде 'std :: find' вместо того, чтобы проходить, чтобы ваше намерение было понятным. Вам также необходимо убедиться, что вы не выходите за пределы с предыдущими и последующими проверками символов. Наконец, это должно быть 'const char * a', если используется строка C. Вы не изменяете его, и это действительно раздражает использование функции, которая принимает неконстантный параметр, но не изменяет его. – chris

+0

Кроме того, как только вы исправите 'a [i ...]', как написано, вы получите одну ошибку, поскольку в конце не будет места, чтобы было возможно использовать последнее слово, что в любом случае могло бы привести к поломке из-за 'isalnum (i + 1)'. – ChiefTwoPencils

ответ

2

Вы передаете значение i этих функций вместо a[i]. Это означает, что вы проверяете, является ли ваша переменная цикла пространством (например), а не символом в этой позиции в массиве a.

После того, как вы зафиксировали, что понимаете, что вы не можете слепо ссылаться на a[i-1] в этом цикле (из-за возможности доступа к a[-1]. Вам нужно будет обновить свою логику (обратите внимание также необходимо использовать && для логического И, не and).

Я предлагаю использовать флаг, чтобы указать, являются ли вы в настоящее время «в» слово. И сбросить этот флаг всякий раз, когда вы решите, что вы больше не внутри слова. например

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

Также , используйте strlen(a) вместо sizeof(a)/sizeof(char). Если вы продолжите эту практику, у вас обязательно будет авария в один прекрасный день, когда вы попробуете ее по указателю.

+0

ну, я предлагаю использовать std :: count – 4pie0

+0

'и' является синонимом '&&'. –

+0

@ piotruś Подсчет слов - это механизм состояния. Я показал очень простой пример этого. 'std :: count' работает только в том случае, если вы делаете много предположений о словах, которые редко бывают истинными на практике. – paddy

0

Этот цикл является недействительным

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

Прежде всего, вы не проверяет символы строки, являются ли они пробелы или буквенно-цифровой. Вы проверяете переменную i, которая не имеет ничего общего с содержимым строки. Более того, вы собираетесь получить доступ к памяти за пределами массива

Как вы имеете дело со строкой я бы объявить функцию следующим образом

size_t countwords(const char *s); 

Это может быть определено как

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 не учитывайте знаки пунктуации. В противном случае вы должны заменить isspace на! Isalnum.

0

Простейшей версией является повторное вызов strtok() в строке, и каждый раз, когда возвращается элемент, вы можете увеличить количество слов. Это обеспечит удвоение пробелов и т. Д. Вы даже можете разделить два слова запятой, но без пробела («это, ошибка») без труда.

что-то вдоль линий:

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

Единственным непосредственным недостатком является то, что strtok разрушительно, поэтому сделайте копию перед началом работы.

0

Чтобы подсчитать количество слов, вам просто нужно подсчитать количество раз, когда вы видите символ без пробела после символа пробела. Чтобы все было в начале строки, предположим, что есть «пробел» слева от строки.

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; 
} 

Вы также можете заметить, я включил оттенок unsigned char на призыв к isspace().На некоторых платформах char по умолчанию подписан, но функции классификатора isspace и друзья не гарантированно работают с отрицательными значениями. Литой заставляет все значения быть положительными. (Подробнее: http://en.cppreference.com/w/cpp/string/byte/isspace)

Смежные вопросы