Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > C/C++ программирование > Visual C++
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 07.08.2009, 03:37   #1
JOFRIF
Форумчанин
 
Регистрация: 21.04.2008
Сообщений: 164
По умолчанию Помогите найти ошибку (Visual c++)

Есть задача - Напишите программу, которая использует генерацию случайных чисел для сохдания предложений. Программа должна использовать 4 массива указателей на char (см. ниже код).
Программа должна создавать предложения, случайно выбирая слова из каждого массива в следующем порядке(порядок см. ниже в коде).
Как только слово выбрано, оно должно быть подсоединено к предыдущему слову в массиве, который достаточно велик для того,
чтобы вместить все предложение. Слова должны быть разделены пробелами. При выводе окончательного предложения(готового) оно должно начинаться с заглавной буквы и заканчиваться точкой.
Программа должна генерировать 20 таких предложений.

То что я написал не работает, помогите пожалуйста найти ошибки.

Код:
Код:
//ñîçäàíèå ñëó÷àéíûõ ïðåäëîæåíèé
#include <iostream.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <ctype.h>

int random();

void main()
{  
           srand(time(NULL));

           int rnd_word;    
	const SIZE = 5;
	char *article[SIZE]={"the ", "a ", "one ","some ", "any "},
		  *noun[SIZE]={"boy ", "girl ", "dog ","town ", "car "},
		  *verb[SIZE]={"drove ", "jumped ", "ran ","walked ",           "skipped "},
		  *preposition[SIZE]={"to ", "from ", "over ","under ", "on "};
	
            for(int i=1;i<=20;i++)//Ïðåäëîæåíèå íîìåð 1
            	{
		char sentence[600];
		char a[15],n[15],v[15],p[15];

            	for(int j=1;j<=6;j++)//7 ðàç âûçâàòü ðàíäîì
	         	{
		      int s=0;

                            rnd_word = random();
 
                        	if (j==1)//òîëüêî â ïåðâîì ñëîâå
		           {
                       	    	a[s] = toupper(*article[rnd_word]);
				while(*article[rnd_word]++!=0)
				{
		            	          a[s++]=*article[rnd_word]++;
    		                                 strcpy(sentence, a);
		  		}
			}

			s=0;

    	                   	if(j==2)
			{
				while(*noun[rnd_word]++!=0)
				{
				        n[s++]=*noun[rnd_word]++;
    	                       	        strcat(sentence, n);
				}
			}

			s=0;

             	           	if(j==3)
			{
				while(*verb[rnd_word]++!=0)
				{
					v[s++]=*verb[rnd_word]++;
                 		            	strcat(sentence, v);
				}
			}

           			s=0;
      
                       	if(j==4)
			{
				while(*preposition[rnd_word]++!=0)
				{
					p[s++]=*preposition[rnd_word]++;
                           	    		strcat(sentence, p);
				}
			}

			s=0;

            		if(j==5)
			{
				while(*article[rnd_word]++!=0)
				{
					a[s++]=*article[rnd_word]++;
        	                             	      strcat(sentence,a);
                                             }
			}

			s=0;

             		if(j==6)
			{
				while(*noun[rnd_word]++!=0)
				{
					n[s++]=*noun[rnd_word]++;
        		                       	strcat(sentence, n);
				}
    		            	strcat(sentence, ". ");
			}
		}
		cout<<"Sentence number "<<i<<endl;
             	cout<<sentence<<endl;
	}

    	
	
}

int random()
{
	int r;

	r=rand() % 5;
	return r;
}
JOFRIF вне форума Ответить с цитированием
Старый 07.08.2009, 08:59   #2
pu4koff
Старожил
 
Аватар для pu4koff
 
Регистрация: 22.05.2007
Сообщений: 9,065
По умолчанию

Так пойдёт?
Код:
...
int main()
{
	srand(time(NULL));

	const int SIZE = 5;
	char *article[SIZE]={"the", "a", "one","some", "any"},
		 *noun[SIZE]={"boy", "girl", "dog","town", "car"},
		 *verb[SIZE]={"drove", "jumped", "ran","walked", "skipped"},
		 *preposition[SIZE]={"to", "from", "over","under", "on"};
	char sentence[600];
	char a[15];

	for(int i=1; i <= 20; ++i)
	{
		strcpy(a, article[random()]);
        a[0] = toupper(a[0]);
		strcpy(sentence, a);
		strcat(sentence, " ");
		strcat(sentence, noun[random()]);
		strcat(sentence, " ");
		strcat(sentence, verb[random()]);
		strcat(sentence, " ");
		strcat(sentence, preposition[random()]);
		strcat(sentence, " ");
		strcat(sentence, article[random()]);
		strcat(sentence, " ");
		strcat(sentence, noun[random()]);
		strcat(sentence, ".");

		cout << "Sentence number " << i << endl;
		cout << sentence << endl;
	}
}
ЗЫ. С циклами у вас вообще беда. Не в тему используете все эти while и for.
pu4koff вне форума Ответить с цитированием
Старый 07.08.2009, 11:17   #3
JOFRIF
Форумчанин
 
Регистрация: 21.04.2008
Сообщений: 164
По умолчанию

Цитата:
Так пойдёт?
Да, думаю так пойдет, если имя массива указателей, например char *name[0], является адресом первого элемента строки, то все ок, потому что функции strcpy и strcat принимают константные адреса.

Цитата:
ЗЫ. С циклами у вас вообще беда. Не в тему используете все эти while и for.
Да я знаю, я не знал что можно вот так strcpy(a, article[random()]);
Я думал что надо строку, перекинуть в массив, а потом уже передавать адрес 1 элемента (константный адрес - имя массива).

вот так я и сделал

Код:
while(*article[rnd_word]++!=0)
				{
		            	          a[s++]=*article[rnd_word]++;
    		                                 strcpy(sentence, a);
		  		}
кстати вопрос на счет этой строчки

Код:
*article[rnd_word]++
Таким образом что я повышаю(инкрементирую)?


Код:
*article[rnd_word++]
а в таком случае?

ЗЫ Ваш код пока не тестировал (проблемы с компом)но думаю он рабочий.
JOFRIF вне форума Ответить с цитированием
Старый 07.08.2009, 11:39   #4
pu4koff
Старожил
 
Аватар для pu4koff
 
Регистрация: 22.05.2007
Сообщений: 9,065
По умолчанию

Цитата:
Сообщение от JOFRIF Посмотреть сообщение
Код:
*article[rnd_word]++
Таким образом что я повышаю(инкрементирую)?
Увеличивается указатель на строку article[rnd_word], т.е. по факту вы "забываете" про первый символ, а звёздочка разыменовывает указатель, т.е. результатом будет первый символ строки article[rnd_word]
Код:
// article[0] == "the"

a = *article[0]++;
// a == 't'
// article[0] == "he"

a = *article[0]++;
// a == 'h'
// article[0] == "e"
Цитата:
Сообщение от JOFRIF Посмотреть сообщение
Код:
*article[rnd_word++]
а в таком случае?
Тут вы увеличиваете номер слова, но используете предыдущее его значение, т.е.
Код:
// rnd_word == 2;
*article[rnd_word++] // эту строчку можно заменить на:
// *article[rnd_word] или *article[2]
// ++rnd_word
ну и на будущее:
Код:
i = 1;
a = i++; // a == 1, i == 2 
a = ++i; // a == 3, i == 3
pu4koff вне форума Ответить с цитированием
Старый 08.08.2009, 14:28   #5
JOFRIF
Форумчанин
 
Регистрация: 21.04.2008
Сообщений: 164
По умолчанию

Спасибо pu4koff ! Ваш код работает...лол...там такой бред сгенерировался


Цитата:
Цитата:Сообщение от JOFRIF
Код:

*article[rnd_word]++

Таким образом что я повышаю(инкрементирую)?

Увеличивается указатель на строку article[rnd_word], т.е. по факту вы "забываете" про первый символ, а звёздочка разыменовывает указатель, т.е. результатом будет первый символ строки article[rnd_word]
Код:

// article[0] == "the"

a = *article[0]++;
// a == 't'
// article[0] == "he"

a = *article[0]++;
// a == 'h'
// article[0] == "e"
Чего то я не совсем понял что это значит "т.е. по факту вы "забываете" про первый символ"?

И я не понял, в вашем примере, куда исчезают буквы из 1 элемента (1 строки)
// article[0] == "the"

// article[0] == "he"

// article[0] == "e"

Насколько я понял, таким образом *article[rnd_word]++ при каждом увеличении я разыменовываю следующею букву.

А в втором случае, из вашего объяснения и примера я понял что эта строка*article[rnd_word++] указывает (с каждым увеличением)) на другую строку.(Поправте если я не прав).
JOFRIF вне форума Ответить с цитированием
Старый 08.08.2009, 14:40   #6
pu4koff
Старожил
 
Аватар для pu4koff
 
Регистрация: 22.05.2007
Сообщений: 9,065
По умолчанию

Цитата:
Сообщение от JOFRIF Посмотреть сообщение
Насколько я понял, таким образом *article[rnd_word]++ при каждом увеличении я разыменовываю следующею букву.
Ну это разыменование первой буквы. Сколько раз это вызовете, такую букву по счету и получите. Только вот при генерации второго предложения в article не будет никаких the, one,... будут пустые строки.
Для такой реализации надо заводить временную переменную:
Код:
char *str = article[rnd_word];
while (*str != '\0')
{
  a = *str++;
}
Цитата:
Сообщение от JOFRIF Посмотреть сообщение
А в втором случае, из вашего объяснения и примера я понял что эта строка*article[rnd_word++] указывает (с каждым увеличением)) на другую строку.(Поправте если я не прав).
Тут всё правильно
pu4koff вне форума Ответить с цитированием
Старый 08.08.2009, 14:59   #7
JOFRIF
Форумчанин
 
Регистрация: 21.04.2008
Сообщений: 164
По умолчанию

Цитата:
Ну это разыменование первой буквы. Сколько раз это вызовете, такую букву по счету и получите. Только вот при генерации второго предложения в article не будет никаких the, one,... будут пустые строки.
Для такой реализации надо заводить временную переменную:
Код:
Код:

char *str = article[rnd_word];
while (*str != '\0')
{
  a = *str++;
}
А без временной переменной, куда исчезают строки?

Может я чего то недопонял в самом процессе разыменования...
JOFRIF вне форума Ответить с цитированием
Старый 08.08.2009, 20:35   #8
pu4koff
Старожил
 
Аватар для pu4koff
 
Регистрация: 22.05.2007
Сообщений: 9,065
По умолчанию

Никуда не деваются. Просто фишка в следующем. Строка - есть массив символов. Массив - это кусок памяти и имеется у нас для доступа только указатель на первый элемент. Когда пишете инкремент ++, то переходите на следующий символ, т.е. указатель на наш массив символов смещается на 1 байт и тем самым теряем первый символ. Он никуда не пропадает, но указатель на него мы теряем.
Ну это как если пришли за квартиру платить, а там очередь. Вы спрашиваете: кто первый? У первого потом спрашиваете: кто за тобой? И запоминаете этого человека уже как первого. Так проходите всю очередь и в итоге первым запомнили последнего, а кто первый уже забыли. Для поиска первого уже придется последнего спрашивать: кто перед тобой? и так до первого дойдем
Если без временной переменной, которая будет хранить указатель на n-й символ строки, то либо работать со строкой как с массивом символов:
Код:
for (int i = 0; i < strlen(str); ++i)
{
  a = str[i];
}
Но тут всплывает временная переменная i
или так:
Код:
int i = 0;
while (*str != '\0')
{
  a = *str++;
  i++;
}
str -= i;
Сколько инкрементов вызвали, столько же вызываем декрементов, но и тут счетчик длины строки нужен. Да и корявый способ. В общем лучше предыдущий мой вариант или строковые функции сишные использовать, типа strcpy, strcat,...

Разыменование в принципе ничего не делает. Просто компилятору говорим, что нужен не адрес, а то что по этому адресу записано.
pu4koff вне форума Ответить с цитированием
Старый 08.08.2009, 22:02   #9
JOFRIF
Форумчанин
 
Регистрация: 21.04.2008
Сообщений: 164
По умолчанию

Цитата:
Никуда не деваются. Просто фишка в следующем. Строка - есть массив символов. Массив - это кусок памяти и имеется у нас для доступа только указатель на первый элемент. Когда пишете инкремент ++, то переходите на следующий символ, т.е. указатель на наш массив символов смещается на 1 байт и тем самым теряем первый символ. Он никуда не пропадает, но указатель на него мы теряем.
Ну это как если пришли за квартиру платить, а там очередь. Вы спрашиваете: кто первый? У первого потом спрашиваете: кто за тобой? И запоминаете этого человека уже как первого. Так проходите всю очередь и в итоге первым запомнили последнего, а кто первый уже забыли. Для поиска первого уже придется последнего спрашивать: кто перед тобой? и так до первого дойдем
Если без временной переменной, которая будет хранить указатель на n-й символ строки, то либо работать со строкой как с массивом символов:
Код:

for (int i = 0; i < strlen(str); ++i)
{
a = str[i];
}

Но тут всплывает временная переменная i
или так:
Код:

int i = 0;
while (*str != '\0')
{
a = *str++;
i++;
}
str -= i;
Сколько инкрементов вызвали, столько же вызываем декрементов, но и тут счетчик длины строки нужен. Да и корявый способ. В общем лучше предыдущий мой вариант или строковые функции сишные использовать, типа strcpy, strcat,...

Разыменование в принципе ничего не делает. Просто компилятору говорим, что нужен не адрес, а то что по этому адресу записано.
Теперь понятно! Спасибо.


Если подвести итог получается:

1)*article[rnd_word]++ - Эта строка инкрементирует указатель на первый элемент, n-ой строки.
2)*article[rnd_word++] - Это строка инкрементирует указатель на строку(с каждым увеличением указатель указывает на 1 символ следующей строки).
JOFRIF вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Помогите найти ошибку! junkie Паскаль, Turbo Pascal, PascalABC.NET 2 03.05.2009 14:22
Помогите найти ошибку (С++) Alex1991 Помощь студентам 1 11.04.2009 15:19
Помогите найти ошибку (С++). TheWanderer Помощь студентам 1 19.03.2009 15:00
помогите найти ошибку! Picaso18 Паскаль, Turbo Pascal, PascalABC.NET 3 24.01.2009 15:32