Форум по Delphi программированию

Delphi Sources



Вернуться   Форум по Delphi программированию > C/C++ > C/C++
Ник
Пароль
Регистрация <<         Правила форума         >> FAQ Пользователи Календарь Поиск Сообщения за сегодня Все разделы прочитаны

Ответ
 
Опции темы Поиск в этой теме Опции просмотра
  #1  
Старый 25.06.2013, 12:41
MahovIV MahovIV вне форума
Новичок
 
Регистрация: 30.12.2012
Сообщения: 77
Репутация: 10
По умолчанию Количество слов в предложении

Мне нужно решить задачу, в которой нужно подсчитать количество слов в предложении. Я решил это сделать при помощи функции strtok. Я не понимаю, почему программа не работает корректно?
Код:
#include <stdio.h>
#include <string.h>
#include <conio.h>

int main() {

	char s[250], *tokenPtr;
	int pr = 0;
	scanf("%s", s);
	tokenPtr = strtok(s, " ");
	while(tokenPtr!=NULL) {
		printf("%s\n", tokenPtr);
		tokenPtr = strtok(NULL, " ");
		pr++;
	}
	printf("%d\n", pr);
	getch();
	return 0;
}
В других примерах программа работала только при присваивании строке значения без ввода строки.
Ответить с цитированием
  #2  
Старый 25.06.2013, 12:48
Аватар для Страдалецъ
Страдалецъ Страдалецъ вне форума
Гуру
 
Регистрация: 09.03.2009
Адрес: На курорте, из окна вижу теплое Баренцево море. Бррр.
Сообщения: 4,721
Репутация: 52347
По умолчанию

Ну вопервых tokenPtr = strtok(NULL, " "); ничего вам не даст. Икать пробел надо в строке, так как вы это делали выше tokenPtr = strtok(s, " ");
Во вторых, вы ничего не делаете со строкой в цикле и будет цикл у вас поэтому крутится до бесконечности.
__________________
Жизнь такова какова она есть и больше никакова.
Помогаю за спасибо.
Ответить с цитированием
  #3  
Старый 25.06.2013, 14:12
ChinYan ChinYan вне форума
Тыкаю клавиши
 
Регистрация: 13.07.2009
Сообщения: 804
Версия Delphi:
Репутация: 48633
По умолчанию

Вместо scanf("%s", s); используйте
Код:
fgets(s, 250, stdin);
Потому что scanf не предназначен для чтения строк с пробелами.


Цитата:
Ну вопервых tokenPtr = strtok(NULL, " "); ничего вам не даст. Икать пробел надо в строке, так как вы это делали выше tokenPtr = strtok(s, " ");
Во вторых, вы ничего не делаете со строкой в цикле и будет цикл у вас поэтому крутится до бесконечности.
Это C, так и должно быть
Ответить с цитированием
  #4  
Старый 25.06.2013, 14:15
MahovIV MahovIV вне форума
Новичок
 
Регистрация: 30.12.2012
Сообщения: 77
Репутация: 10
По умолчанию

То есть как это в строке? Вот так
Код:
while(strtok(s, " ") != NULL
? Что нужно делать со строкой в цикле?
Ответить с цитированием
  #5  
Старый 25.06.2013, 14:19
ChinYan ChinYan вне форума
Тыкаю клавиши
 
Регистрация: 13.07.2009
Сообщения: 804
Версия Delphi:
Репутация: 48633
По умолчанию

Ничего не делайте, просто замените
Код:
scanf("%s", s);
на
Код:
fgets(s, 250, stdin);
Ответить с цитированием
  #6  
Старый 25.06.2013, 14:27
Аватар для Bargest
Bargest Bargest вне форума
Профессионал
 
Регистрация: 19.10.2010
Адрес: Москва
Сообщения: 2,390
Версия Delphi: XE3/VS12/FASM
Репутация: 14665
По умолчанию

Код:
int len = strlen(s);
int count = 0;
for (int i = 0; i < len; ++i)
  if (s[i] == ' ')
  {
     ++count;
     do
       ++i;
     while (i < len && s[i] == ' ');
  }
if (s[len-1] != ' ')
  ++count;
__________________
jmp $ ; Happy End!
The Cake Is A Lie.

Последний раз редактировалось Bargest, 25.06.2013 в 14:31.
Ответить с цитированием
  #7  
Старый 25.06.2013, 17:55
MahovIV MahovIV вне форума
Новичок
 
Регистрация: 30.12.2012
Сообщения: 77
Репутация: 10
По умолчанию

Ваша программа выполняется не для всех значений.
Ответить с цитированием
  #8  
Старый 25.06.2013, 19:33
Аватар для Bargest
Bargest Bargest вне форума
Профессионал
 
Регистрация: 19.10.2010
Адрес: Москва
Сообщения: 2,390
Версия Delphi: XE3/VS12/FASM
Репутация: 14665
По умолчанию

Например, для каких не выполняется?
<слово><пробел>(<пробел>)*<слово> - выполняется.
<слово><конец строки> - выполняется.
<слово><пробел><конец строки> - выполняется.
Все комбинации описанных правил тоже выполняются.
Однобуквенные слова обрабатываются верно.

Тестил на строках
Код:
"hello world";
"hello g world";
"hello g   world";
"hello g   world     shshs";
"hello g   world     shshs ";
Только забыл проверку на пробелы первым символом.
__________________
jmp $ ; Happy End!
The Cake Is A Lie.

Последний раз редактировалось Bargest, 25.06.2013 в 19:44.
Ответить с цитированием
  #9  
Старый 28.06.2013, 19:31
Аватар для orion_asm
orion_asm orion_asm вне форума
Прохожий
 
Регистрация: 23.06.2012
Адрес: Украина, Днепропетровск
Сообщения: 19
Версия Delphi: XE3
Репутация: 10
По умолчанию

Пардон если слишком толсто, зато работает, тестил, вроде ошибок нет.
Код:
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>

#define SIZE 255

/*	
    Подсчет слов. Словом считается минимум одна буква,
	которая окружена с обеих сторон как минимум одним
	пробелом
*/

int Words_Count(char *buff)
{
    int word = 0;
	int k = 0;
	// вычисляем длинну строки
	int len = strlen(buff);
	// последний символ не пробел?
	if (!isspace(buff[len]))
	// нет, вносим пробел
	buff[len] = ' ';
	// ввод начался с пробелов?
	if (isspace(buff[0]))
	{
		// считаем количество пробелов
		while (isspace(buff[k]))
		k++;
	}
	// счет от первого места, где закончились пробелы
	for (int i = k; i < SIZE; i++)
	{
		// встретили пробел?
		if (isspace(buff[i]))
		// надо же, еще один!
		if (isspace(buff[i+1]))
		// ищем не пробелы
		continue;
		// нашли не пробел, значит слово
		else word++;
	}
	return word;
}

int main ()
{
	// Выделяем память и заполняем нулями
	char *buff = (char*)calloc(SIZE, sizeof(char));
	// считываем строку
	gets_s(buff,SIZE);
           printf("So, we have the %d words", Words_Count(buff));
	getchar();
    return 0;
}

Последний раз редактировалось orion_asm, 28.06.2013 в 22:36.
Ответить с цитированием
  #10  
Старый 19.07.2013, 13:34
MahovIV MahovIV вне форума
Новичок
 
Регистрация: 30.12.2012
Сообщения: 77
Репутация: 10
По умолчанию

Цитата:
Сообщение от Bargest
Например, для каких не выполняется?
<слово><пробел>(<пробел>)*<слово> - выполняется.
<слово><конец строки> - выполняется.
<слово><пробел><конец строки> - выполняется.
Все комбинации описанных правил тоже выполняются.
Однобуквенные слова обрабатываются верно.

Тестил на строках
Код:
"hello world";
"hello g world";
"hello g   world";
"hello g   world     shshs";
"hello g   world     shshs ";
Только забыл проверку на пробелы первым символом.
У меня не работает. А если попадутся два пробела подряд?
Ответить с цитированием
  #11  
Старый 30.07.2013, 04:05
Аватар для orion_asm
orion_asm orion_asm вне форума
Прохожий
 
Регистрация: 23.06.2012
Адрес: Украина, Днепропетровск
Сообщения: 19
Версия Delphi: XE3
Репутация: 10
По умолчанию

Более оптимизированный и правильный с точки зрения задачи код (слово все-таки это не символ, поэтому это минимум 2 символа).
Код:
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>

#define SIZE 255

int Words_Count(char *buff)
{
    int word = 0;   // количество слов
    int i = 0;      // итератор
	int c = 0;      // счетчик символов для определения слова

    /* нужно для правильной работы цикла */
    if (!isspace(strlen(buff)))      // последний символ не пробел?
        buff[strlen(buff)] = ' ';    // нет, вносим пробел

    for (i = 0; i < strlen(buff); i++)
    {
        // Если не пробел, считаем количество символов
        if (!isspace(buff[i]))
        	c++;
        // если пробел
        else if (isspace(buff[i]))
        {
            // более двух символов значит слово,
            // подсчитываем и сбрасываем счетчик
            if (c >= 2)
            word++;
            c = 0;
        }
    }
    return word;
}

main ()
{
    // Выделяем память и заполняем нулями
	char *buff = (char*)calloc(SIZE, sizeof(char));
	if (!buff)
		printf("Not enough memory");
    // считываем строку
    gets_s(buff,SIZE);
    printf("So, we have the %d words", Words_Count(buff));
    getchar();
    return 0;
}

Последний раз редактировалось orion_asm, 30.07.2013 в 04:42.
Ответить с цитированием
  #12  
Старый 08.08.2013, 22:46
Аватар для Bargest
Bargest Bargest вне форума
Профессионал
 
Регистрация: 19.10.2010
Адрес: Москва
Сообщения: 2,390
Версия Delphi: XE3/VS12/FASM
Репутация: 14665
По умолчанию

Цитата:
слово все-таки это не символ, поэтому это минимум 2 символа
А такие слова как "а", "и", "в", и другие предлоги и союзы - не интересно?
Цитата:
А если попадутся два пробела подряд?
"Обожаю" людей, которые даже не читают то, что им пишут. Почитай еще раз семплы, на которых я тестил. Там и по 10 пробелов есть.
Да, я некропостер. Ток все равно ветка форума полудохлая.
__________________
jmp $ ; Happy End!
The Cake Is A Lie.
Ответить с цитированием
  #13  
Старый 09.08.2013, 02:24
Аватар для orion_asm
orion_asm orion_asm вне форума
Прохожий
 
Регистрация: 23.06.2012
Адрес: Украина, Днепропетровск
Сообщения: 19
Версия Delphi: XE3
Репутация: 10
По умолчанию

Цитата:
Сообщение от Bargest
А такие слова как "а", "и", "в", и другие предлоги и союзы - не интересно?
Предложенные варианты не могут быть словами по определению. Пусть даже "____a___", "_и_______", "_а_и_в". Наличие двойных скобок олицетворяет тип - строка. А строка это контейнер для слов и символов. По крайней мере, если для задачи словом является как минимум 2 символа, это утверждение справедливо.
***
А, понял что вы имели в виду - если ввести "а" или "б". Ну да, можно "допилить" алго, если соответствующее условие будет в задаче. Исходил из того, что слово есть набор как минимум 2 любых символов.

Последний раз редактировалось orion_asm, 09.08.2013 в 02:35.
Ответить с цитированием
  #14  
Старый 09.08.2013, 11:04
Аватар для Bargest
Bargest Bargest вне форума
Профессионал
 
Регистрация: 19.10.2010
Адрес: Москва
Сообщения: 2,390
Версия Delphi: XE3/VS12/FASM
Репутация: 14665
По умолчанию

Я имел в виду, что по правилам русского языка в предложении "Книга лежит в шкафу" четыре слова. Поэтому дополнительно поставленное условие "минимум 2 символа" приведет к невыполнению условия изначального задания "подсчитать количество слов в предложении" (такой алгоритм не учтёт предлог "в").
Цитата:
if (!isspace(strlen(buff))) // последний символ не пробел?
Не понял. Сильно сомневаюсь, что длина строки часто будет пробелом.
Кстати сей код у меня регулярно падает. Дебажный gets_s забивает свободную часть строки байтами 0xFE, и естественно дописывание пробела на конце убивает строку.
И еще немного багии:
Цитата:
1234_1234
So, we have the 1 words
21431_234_1234_1234_
So, we have the 4 words
1234_1234_1_1234
So, we have the 3 words
1234_1234123_1234
So, we have the 3 words
1111 1111111 1111112 111212 1212
So, we have the 4 words
1111 1111111 1111112 111212 121
So, we have the 5 words
1111 1111111 1111112 111212 1212
So, we have the 4 words
1111 1111111 1111112 111212 12121
So, we have the 5 words
Стоит обратить внимание на первый тест и на 4 последних.
Все эти баги из-за приведенной выше строки.
И напоследок, мои любимые упоротые бенчмарки. Тот код, что я кидал раньше, с небольшой правкой в начале, и поправленный код orion_asm (добавление пробела на конец вынес отдельно, чтоб не править строку постоянно), миллион повторений, время в тиках (GetTickCount), релиз-сборка VS2012.
Цитата:
hello, world!
141 - 421
_____hello,____world dfdfdfdf dsfgsdfg wert ew rt__sd g d fgs df g sdfg sldfkgj sdkfg lskdf__sdflgksj dflkgjl kjlks___jj j j j l sdflgkj dfdf
1092 - 5304
(на месте _ стоят пробелы, просто форум много пробелов подряд сносит).
__________________
jmp $ ; Happy End!
The Cake Is A Lie.

Последний раз редактировалось Bargest, 09.08.2013 в 11:52.
Ответить с цитированием
  #15  
Старый 09.08.2013, 13:05
Аватар для orion_asm
orion_asm orion_asm вне форума
Прохожий
 
Регистрация: 23.06.2012
Адрес: Украина, Днепропетровск
Сообщения: 19
Версия Delphi: XE3
Репутация: 10
По умолчанию

Цитата:
Сообщение от Bargest
Не понял. Сильно сомневаюсь, что длина строки часто будет пробелом.
Это для правильной работы алгоритма в цикле for. Нужно чтобы в конце всегда был пробел. Из-за этого не считает случай 1234_1234. Смотрел в отладчике - почему-то если цифры, пробелы не вставляются. Если закончить строку пробелом - тогда все верно. Это касается и остальных 4. Если закончить строку пробелом, тогда 5 слов. Вот только почему пробел не вставляет... В отладчике показано что в конце строки нет пробела, при этом пробел не помещается в конец.
[/quote]
Ответить с цитированием
Ответ


Delphi Sources

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения

BB-коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход


Часовой пояс GMT +3, время: 16:04.


 

Сайт

Форум

FAQ

RSS лента

Прочее

 

Copyright © Форум "Delphi Sources" by BrokenByte Software, 2004-2023

ВКонтакте   Facebook   Twitter