Страница 1 из 2

Самое длинное слово, содержащее минимум 3 буквы 'a'

Добавлено: 02 янв 2015, 16:20
vbn
Написать программу, печатающую самое длинное слово из заданного предложения, содержащее не менее трех букв а.
часть кода я написал по нахождению длинного слова, но ругаться на вот эту строчку

Код: Выделить всё

 if (strlen(mas[i])>strlen(mas[m])) m=i;
листинг программы

Код: Выделить всё

#include<stdio.h>
#include<string.h>
#include<conio.h>
int main()
{
char s[255];
int i,n,m;
 char   slovo;
char   mas [100];
printf("Vvedite text");
scanf("%c",&s);
n=0;
for (i=1; i<=strlen(s);i++)
if (s[i]!= ' ')
slovo=slovo+s[i];
else
{
n++;
mas[n]=slovo;
 }
m=1;
for (i=2; i<=n;i++)
if (strlen(mas[i])>strlen(mas[m])) m=i;
printf("Samoe dlinoe slovo :%c ",mas[m]);
getch();
}

Re: Работа со строками

Добавлено: 03 янв 2015, 00:29
Romeo
Указанная ошибка единственная, но единственная синтаксическая. Программа помимо синтаксической ошибки изобилует целым букетом логических, из-за которых она хоть и скомпилируется, но работать не будет.

Вот они:

1. Форматирующая строка %c в функциях scanf/printf обозначает считывание/печать одиночного символа. Для оперирования строками используй %s.

2. Кстати, при вызове функции scanf, функция должна получить адреса памяти, куда будут считываться данные. Амперсанд перед s не нужен, так как s уже сама по себе является указателем (не путать с обычными переменными, амперсанд перед которыми необходим, так как иначе в функцию уйдёт значение переменной, а не её адрес).

3. В C/C++ индексация элементов массива начинается с нуля. То есть, если массив объявлен, как, скажем, char mas[10], это обозначает, что массив имеет 10 символов с индексами от 0 до 9. Потому циклы принято писать так:

Код: Выделить всё

for (int i = 0; i < n; ++i)
4. Зачем выполнять следующее сложение? В чём его тайный смысл?

Код: Выделить всё

slovo=slovo+s[i];
Дело в том, что в таком случае мы получаем сложение аски кодов соответствующих символов. Такая сумму мало того, что не носит никакого практического смысла, так, ко всеми прочему, в случае длинного слова мы ещё и получим переполнение, что вообще кладёт на лопатки все попытки программиста выжать из этой переменной хоть какой-то смысл в будущем.

5. Ну и наконец сама синтаксическая ошибка из-за которой программа не скомпилировалась (кстати, и слава Богу, так как иначе бы она запустилась и скрашилась). Дело в том, что функция strlen должна получать на вход строку (то есть тип char*), в то время как выражение mas имеет тип char (то есть символ). Даже если бы мы как-то заставили это собраться, в чём смысл вычисления длины символа?

Re: Работа со строками

Добавлено: 03 янв 2015, 00:29
Romeo
Мне кажется, что налицо отсутствие базовых знаний языка. Устрою небольшой ликбез по строкам.

- Строка в C/C++ объявляется как массив символов (char str[N]).

- Переменная-строка имеет тип char* и, фактически, по совместительству является адресом первого элемента строки. Помнить это нужно хотя бы для того, чтобы не ставить амперсанд перед переменной, передавая её в scanf. Бывают и масса других случаев, когда это свойтсво очень полезно.

- Как и во всех массивах, элементы строки имеют индексы от 0 до N-1.

- Каждый элемент строки имеет тип char, иначе говоря символ. К нему можно обратиться через квадратные скобки (например, str[0]).

- С точки зрения языка символ - это просто некое численное значение от 0 до 255, называемое аски кодом (ASCII code). В привычный нам символ оно превращается только после того, как это значение распечатывается с помощью, например, printf cо строкой формата %c.

- Все функции для работы со строками, от множества функций, начинающихся на str (например strlen) до тех же printf/scanf, предполагают в конце строки терминирующий ноль (символ с аски кодом 0). Например scanf после прочтения с клавиатуры символов и размещения их в памяти, ставит в конце строки символ ноль. А функция strlen затем бежит по строке до тех пор, пока не встретит символ ноль и возвращает количество пройденных символов, как длину строки.

- Отсюда следует, что когда мы объявляем строку, то мы обязаны учесть, что в этой памяти помимо видимых символов будет ещё один терминирующий символ, так что строка должна быть выделена с запасом.

Re: Работа со строками

Добавлено: 03 янв 2015, 14:17
Romeo
Теперь, собственно, я бы перешёл в оговариванию самого задания. Потуги сделанные тобой выше можно смело выбросить хотя бы потому, что в них нет никакого смысла. Предлагаю следующий, на мой взгляд самый простой и логичный алгоритм решения задачи.

1. Нам потребуются следующие вспомогательные переменные (помимо самого массива и счётчика для цикла). Все они числовые:
1.1. cur_len - Текущая длина слова. Изначально равна нулю.
1.2. max_len - Максимальная длина найденного слова. Изначально равна нулю.
1.3. start_max - Индекс начала найденного максимального слова. Изначально равен -1.
2. Читаем строку.
3. Организовываем цикл по всем символам прочитанной строки. Причём делаем лишнюю итерацию в конце, чтобы захватить ещё и терминирующий ноль. Это позволит учесть в вычислениях последнее слово в конце строки, после которого пользователь может не поставить пробел.
3.1. Если текущий символ равен пробелу или нулю (терминирующему), то:
3.1.1. Если текущая длина (cur_len) больше либо равна трём (по условию задачи, искомое слова должно содержать как минимум 3 символа) и текущая длина (cur_len) больше максимальной длины (max_len), то отнимаем от текущего индекса cur_len и запоминаем получившуюся разность в в переменной start_max, а значение max_len перетираем значением из переменной cur_len.
3.1.2. Сбрасываем текущую длину (cur_len) в ноль.
3.2. Иначе (относится к 3.1.) увеличиваем cur_len на 1 .
3.3. Конец цикла.
После окончания цикла у нас в переменной start_max будет храниться индекс начала максимального найденного слова, если такое слово было найдено, иначе -1.
4. Если start_max больше либо равно нолю, то:
4.1. Запускаем цикл от start_max до тех пор, пока текущий символ не будет пробелом или нулём (терминирующим) и в цикле выводим текущий символ.
5. Иначе (если start_max равен -1), то:
5.1. Выводим сообщение, что слов длиной от трёх символов и больше вообще не было найдено в исходной строке.
6. Конец программы.

Re: Работа со строками

Добавлено: 03 янв 2015, 14:26
vbn
спасибо за ваши рекомендации по написанию программы, я сделал как вы и сказали, но видимо сделал где-то что-то не так,вот в этом месте ругается, после ввода строки

Код: Выделить всё

printf("%c",s);
весь код

Код: Выделить всё

#include<stdio.h>
#include<string.h>
#include<conio.h>
int main()
{
char* s[255];
int i,cur_len=0,max_len=0,start_max;
printf("Vvedite text");
scanf("%c",s);
for(i=0; i<=s[i]+1;i++)
{
if ((s[i]=0) || (s[i]=" "))
{
if ((cur_len>=3) || (cur_len>max_len))
{
start_max=s[i];
max_len=cur_len;
cur_len=0;
}
}
else
cur_len++;
}
if (start_max>0)
{
for (i=start_max;i=s[i]=0;i++)
{
printf("%c",s);
}
}
else
if (start_max=0)
{
printf("Slovo  dlinnoy ot trex simvolov i boliche? ne bilo naydeno");
}
getch();
}

Re: Работа со строками

Добавлено: 03 янв 2015, 16:12
Romeo
Хорошо, что прочитал. А теперь прочитай ещё раз, но на этот раз вдумываясь.

Во-первых, ты забыл инициализировать start_max.

Далее, что это что такое?

Код: Выделить всё

char* s[255];
Ты только что объявил массив указателей на символ, а не массив символов. Прочти ещё раз вот это:
Romeo писал(а): - Строка в C/C++ объявляется как массив символов (char str[N]).
Далее идёт такое:

Код: Выделить всё

scanf("%c",s)]
По этому поводу читай выше вот этот текст:
[quote="Romeo"]
1. Форматирующая строка %c в функциях scanf/printf обозначает считывание/печать одиночного символа. Для оперирования строками используй %s.
[/quote]

Далее очень странные условие на продолжение цикла:
[code=cpp]
for(i=0]+1;i++)
Мы берём s, на первом шаге i равно 0, так что берём s[0] и интерпретируем его аски код, как число, затем добавляем 1 и сравниваем с нашим индексом. Понимаешь, что сравниваются вещи несравнимые с собой. Это как сравнивать количество звёзд на небе и рыб в море и пытаться сделать из этого какие-то далеко идущие выводы. Зачем так усложнять? Счётчик i должен меняться от 0 до LEN+1 (не включая), либо до LEN включая, где LEN вычисляется через вызов strlen(s).

Далее:

Код: Выделить всё

if ((s[i]=0) || (s[i]=" "))
В C/C++ оператор = обозначает присваивание. Если же нужно сравнить два значения, то используется оператор ==. Не путай их.

Код: Выделить всё

if ((cur_len>=3) || (cur_len>max_len))
Не "или", а "и". В алгоритме написано "и". Это оператор "&&".

Код: Выделить всё

start_max=s[i];
Я же написал "запоминаем индекс", а ты запоминаешь символ. Ты же ниже начинаешь от этого индекса бежать, хотя до этого помещаешь в него аски символ числа. Ну немножко подумай перед тем, как такое писать.

Код: Выделить всё

cur_len=0;
Это присваивание должно быть за границами условия, ещё раз прочти алгоритм.

Код: Выделить всё

if (start_max>0)
Должно быть больше либо равно.

Код: Выделить всё

for (i=start_max;i=s[i]=0;i++)
Что ты хотел сказать условием i=s=0? Знаешь что на самом деле делает эта строка? Она присваивает i и s значение ноль. Даже если ты исправишь "=" на "==", это всё равно будет абракадабра. Верно в нём только s, так как это действительно текущий символ. Условие должно быть следующими "пока текущий символ неравен пробел и текущий символ неравен нулю". Справишься?

Код: Выделить всё

else
if (start_max=0)
В "иначе" не нужно писать обратное условие. "Иначе" и так выполняется, когда условие обратно.

Призываю тебя не просто пытать бездумно делать то, что я написал в алгоритме, а в первую очередь его понять. Без понимания не получится написать работающую программу. А когда понимание будет достигнуто, то и глупые ошибки исчезнут сами собой, потому как ты сам поймёшь, что ты делаешь и что они глупые.

Re: Самое длинное слово, как минимум из трёх символов

Добавлено: 03 янв 2015, 17:15
vbn
Опять я где-то напортачил, при выводе ничего не выводит(

Код: Выделить всё

#include<stdio.h>
#include<string.h>
#include<conio.h>
int main()
{
char s[255];
int i,cur_len=0,max_len=0,start_max=-1,len;
printf("Vvedite text");
scanf("%s",s);
len= strlen(s);
for(i=0; i<=len+1; i++)
{
if ((s[i]==0) || (s[i]==' '))
{
if ((cur_len>=3) && (cur_len>max_len))
{
start_max=i;
max_len=cur_len;
}
}
else
cur_len++;
}
cur_len=0;
if (start_max>=0)
{
while((s[i]!=' ') && (s[i]!=0))
printf("%s",s);
i++;
}
else
printf("slovo  dlinnoy ot trex simvolov i boliche, ne bilo naydeno");
getch();
}


Re: Самое длинное слово, как минимум из трёх символов

Добавлено: 03 янв 2015, 21:34
Romeo
Ну почти. Ещё пару оплошностей.

- В первом цикле лишнюю итерацию делаешь.
- Обнуление cur_len зачем из цикла вынес? Его только за пределы внутреннего if нужно было вынести. Ещё раз проштудируй алгоритм.
- В цикле вывода пытаешься выводить каждый раз всю строку, а нам нужно посимвольно выводить, иначе часть строки не получится вывести.
- Ты цикл вывода переделал с for на while, но забыл присвоить i инициализирующее значение, хотя когда у тебя через for было сделано, то инициализация была.
- В цикле вывода забыты фигурные скобки, в результате в цикле выполняется только printf, а инкрементация i уже к циклу не относится. Следует ли говорить, что такой цикл просто зависнет?

В общем, решил я запустить твою программу, и исправив твои ошибки, нашёл ещё два места, о которых я сам не подумал. Вот они:

1. В алгоритме неправильно запоминалось начало максимальной строки. Ведь если мы просто текущий индекс запомним в start_max, то start_max будет указывать на пробел в конце слова. А нам ведь нужно запомнить индекс начала слова. Так что я поправил алгоритм вот такими словами:
Romeo писал(а):то отнимаем от текущего индекса cur_len и запоминаем получившуюся разность в в переменной start_max
2. Ещё одна мелочь - чисто техническая. Если мы будем считывать строку через scanf, то прочитается строка до первого пробела - такая особенность этой функции. Для того, чтобы прочитать всю строку целиком до перевода каретки, следует вызывать функцию gets.

Ты проделал большую работу и не сдался. Ты заслужил это. Лови исправленную программу. Она сделана под Visual Studio, так что у неё несколько иная сигнатура мэйна, но в остальном всё один в один, так что ты разберёшься.

Код: Выделить всё

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

int _tmain(int argc, _TCHAR* argv[])
{
	char s[255]]==0) || (s[i]==' '))
		{
			if ((cur_len >= 3) && (cur_len > max_len))
			{
				start_max = i - cur_len;
				max_len = cur_len;
			}
			cur_len = 0;
		}
		else
		{
			cur_len++;
		}
	}
	
	if (start_max >= 0)
	{
		i = start_max;
		while ((s[i] != ' ') && (s[i] != 0))
		{
			printf("%c", s[i]);
			++i;
		}
	}
	else
	{
		printf("slovo dlinnoy ot trex simvolov i boliche, ne bilo naydeno");
	}

	getch();

	return 0;
}

Re: Самое длинное слово, как минимум из трёх символов

Добавлено: 03 янв 2015, 21:49
vbn
Спасибо огромное Вам, да, разобрался я с сигнатурой main и еще с парочкой мелочей, во общем все работает, спасибо ;)
хотел я еще с одно задачей разобраться, но там работа со структурами, мне лучше создать новую тему или можно в этой описать суть проблемы?

Re: Самое длинное слово, как минимум из трёх символов

Добавлено: 03 янв 2015, 21:54
Romeo
Не за что. По поводу новой задачки - давай в отдельную тему.

Кстати, я тут заметил, что в задании написано
vbn писал(а): содержащее не менее трех букв а.
Это не опечатка? Не менее трёх букв, или не менее трёх букв а? Если второе, то алгоритм следует доработать :)