20.01.2017, 17:05 [+3 UTC]
в нашей команде: 1 762 чел. | участники онлайн: 8 (рекорд: 21)

:: РЕГИСТРАЦИЯ

:: консультации

:: задать вопрос

:: все разделы

:: правила

:: новости

:: участники

:: доска почёта

:: форум

:: блоги

:: поиск

:: статистика

:: наш журнал

:: наши встречи

:: наша галерея

:: отзывы о нас

:: поддержка

:: руководство

Версия системы:
7.40 (02.09.2016)

Общие новости:
31.12.2016, 18:43

Форум:
18.01.2017, 11:36

Последний вопрос:
20.01.2017, 14:11

Последний ответ:
20.01.2017, 16:54

Последняя рассылка:
20.01.2017, 16:15

Писем в очереди:
0

Мы в соцсетях:

Наша кнопка:

RFpro.ru - здесь вам помогут!

Отзывы о нас:
25.02.2010, 16:39 »
Андрей Кузнецов aka Dr_Andrew
Спасибо за ценные замечания, которые позволили оптимизировать код! [вопрос № 176905, ответ № 259733]
14.03.2014, 18:32 »
Посетитель - 379404
отличная страница! всегда читаю с интересом! спасибо ведущим!Стрежекуров Эдуард

РАЗДЕЛ • С / С++

Создание программ на языках C и C++.

[администратор рассылки: Андрей Кузнецов aka Dr_Andrew (Старший модератор)]

Лучшие эксперты в этом разделе

Лысков Игорь Витальевич
Статус: Старший модератор
Рейтинг: 750
solowey
Статус: 5-й класс
Рейтинг: 220
Асмик Гаряка
Статус: Советник
Рейтинг: 182

Перейти к консультации №:
 

Консультация онлайн # 190338
Раздел: • С / С++
Автор вопроса: Usagisan (Посетитель)
Отправлена: 25.12.2016, 13:48
Поступило ответов: 1

Здравствуйте! Прошу помощи в следующем вопросе:

Подготовить текстовый файл, содержащий не менее 10 слов. Прочитать данные из этого файла и сформировать двусвязный список, элементы которого имеют тип STRING. Написать программу, подсчитывающую количество элементов списка, которые начинаются и оканчиваются одним и тем же символом.
После завершения работы со списками освободить занимаемую ими динамическую память.

Буду благодарна, если код будет написан на Си. Я смогла написать только основные функции работы с двусвязным и списком и не уверена, что и они верны. Заранее спасибо за помощь!

Приложение:

Состояние: Консультация закрыта

Ответ # 274488 от Лысков Игорь Витальевич (Старший модератор)

Здравствуйте, Usagisan!
1) Вы говорите о С, а сами используете элементы C++, такие как new, cin , cout smile
2) Полем данных должна быть строка, а не double
3) Должен быть двунаправленный список, т.е. должны быть и голова, и хвост
3) Надо читать с файла, а не с консоли
Посмотрите, как я сделал (на чистом С):

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <malloc.h>

typedef struct ListNode1 
{ 
	char*		info;	//указатель на строку
	ListNode1*	next;	//указатель на следующий элемент 
	ListNode1*	prev;	//указатель на предыдущий элемент 
}ListNode1; 

//указатели на голову и хвост определим в глобальной памяти
ListNode1* pHead = NULL;
ListNode1* pTail = NULL;

//параметром укажем только значение поля info
void AddToList(char * info) 
{ 
	ListNode1* q = (ListNode1*) malloc(sizeof(ListNode1));	//выделим память под узел
	q->info = (char*)malloc(strlen(info)+1);				//и под строку
	strcpy(q->info, info);									//копируем строку
	q->next = NULL;											//узел всегда будет последним
	if (pTail)							//указатель хвоста непуст?
	{ 
		q->prev = pTail;				//для нового предыдущим станет старый хвост
		pTail->next = q;				//для бывшего хвоста следующим - новый
	} 
	else 
	{									//новый - единственный, будет и головой, и хвостом
		q->prev = NULL;					//для головы предыдущего нет
		pHead = q;						//голова списка - новый узел
	} 
	pTail = q;							//новый становится новым хвостом
} 

//параметром укажем имя файла
int FormList1(char *fName)
{ 
	char string[1024];					//буфер для чтения

	FILE	*fp = fopen(fName, "r") ;	//открываем файл на чтение
	
	if (fp)								//открылся?
	{
		while (-1 != fscanf(fp, "%s", string))	//читаем, пока читается
		{
			AddToList(string);			//и включаем очередную строку в список
		}
		fclose(fp);						//закрываем файл
		return true;					//файл считан
	}
	return false;						//ошибка, скорее всего, файл не найден
} 

//подсчитываем слова, у которых одинаковые первая и последняя буквы
int GetCount(void)
{
	int count = 0;
	ListNode1 * node;

	for(node=pHead; node; node=node->next)	//по всем узлам
										//сравниваем буквы, если равны, получим 1, иначе 0
		count += (node->info[0] == node->info[strlen(node->info)-1]);

	return count;						//возвращаем счетчик
}

void DelList()							//освобождаем память списка
{										//воспользуемся указателями pHead и pTail, все равно они уже не нужны
	while(pHead)						//пока что-то есть
	{
		pTail = pHead->next;			//сохраним адрес следующего
		free(pHead->info);				//сначала освободим память строки
		free(pHead);					//потом память самого узла
		pHead = pTail;					//адрес следующего
	}
}

int main()
{
	if (FormList1("test.txt"))			//формируем список из файла
	{
		printf("Count = %d\n", GetCount());	//выводим количество слов с одинаковыми первой и последней буквой
		DelList();						//освобождаем память
	}
	else
		printf ("File 'test.txt' not found!\n");	//файл не найден
	return 0;
}

test.txt
asdasda 3123123 treter 456456 sdfsdf 45454544 
asdasdas gdfgdfgdfg tttttt 5555555 434343 5555556765


Консультировал: Лысков Игорь Витальевич (Старший модератор)
Дата отправки: 26.12.2016, 17:05

5
нет комментария
-----
Дата оценки: 26.12.2016, 18:52

Рейтинг ответа:

0

[подробно]

Сообщение
модераторам

Отправлять сообщения
модераторам могут
только участники портала.
ВОЙТИ НА ПОРТАЛ »
регистрация »

Мини-форум консультации № 190338
Usagisan
Посетитель

ID: 400314

# 1

= общий = | 26.12.2016, 18:52 | цитировать цитировать  | профиль профиль  |  отправить письмо в личную почту пейджер

Большое спасибо!
Да, я прекрасно знаю об этих косяках. Так уж вышло, что я просто скопировала функции из тетради, особо не разоравшись:С Больше не буду так

Usagisan
Посетитель

ID: 400314

# 2

= общий = | 26.12.2016, 19:05 | цитировать цитировать  | профиль профиль  |  отправить письмо в личную почту пейджер

Тут такая проблема: компилятор выдаёт ошибку в 9 и 10 строке, а так же в 51 и 53

Лысков Игорь Витальевич
Старший модератор

ID: 7438

# 3

= общий = | 26.12.2016, 19:27 | цитировать цитировать  | профиль профиль  |  отправить письмо в личную почту пейджер
Usagisan:

51 и 53 - не знает, что такое true и false
#define true 1
#define false 0
9 и 10 - попробуйте, как было у Вас
struct ListNode1
{
char * info; // значение
ListNode1 *next; //указатель на следующий элемент
ListNode1 *prev; //указатель на предыдущий элемент
};

=====
Каждый выбирает по себе -
Щит и латы, посох и заплаты.
Меру окончательной расплаты
Каждый выбирает для себя.

Usagisan
Посетитель

ID: 400314

# 4

= общий = | 27.12.2016, 18:35 | цитировать цитировать  | профиль профиль  |  отправить письмо в личную почту пейджер

Всё, заработало. Можете объяснить один момент? q - узел, а для чего он нам нужен?

Лысков Игорь Витальевич
Старший модератор

ID: 7438

# 5

= общий = | 27.12.2016, 18:42 | цитировать цитировать  | профиль профиль  |  отправить письмо в личную почту пейджер
Usagisan:

Это переменная, в которой хранится адрес вновь созданного узла.
Потом адрес этого узла вставляется в список узлов. После чего сама переменная q уже становится не нужна.

=====
Каждый выбирает по себе -
Щит и латы, посох и заплаты.
Меру окончательной расплаты
Каждый выбирает для себя.

Usagisan
Посетитель

ID: 400314

# 6

= общий = | 27.12.2016, 18:48 | цитировать цитировать  | профиль профиль  |  отправить письмо в личную почту пейджер

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

Usagisan
Посетитель

ID: 400314

# 7

= общий = | 27.12.2016, 18:52 | цитировать цитировать  | профиль профиль  |  отправить письмо в личную почту пейджер

И почему мы их создаём не в структуре?

Лысков Игорь Витальевич
Старший модератор

ID: 7438

# 8

= общий = | 27.12.2016, 19:02 | цитировать цитировать  | профиль профиль  |  отправить письмо в личную почту пейджер
Usagisan:

Если все будет в элементах списка, то как мы найдем эти элементы? smile
Надо же иметь адрес начала (как минимум), адрес хвоста можно не использовать. Но с ним удобнее.
Если адрес хвоста не использовать, то при вставке надо постоянно искать хвост.
Кроме того, бывает, что надо проходить список в обратном порядке (раз есть ссылка на предыдущий элемент).
Тогда иметь адрес хвоста просто необходимо.

=====
Каждый выбирает по себе -
Щит и латы, посох и заплаты.
Меру окончательной расплаты
Каждый выбирает для себя.

Usagisan
Посетитель

ID: 400314

# 9

= общий = | 28.12.2016, 16:45 | цитировать цитировать  | профиль профиль  |  отправить письмо в личную почту пейджер

Можете, пожалуйста, пояснить цикл, который начинается с 62 строки?

Лысков Игорь Витальевич
Старший модератор

ID: 7438

# 10

= общий = | 28.12.2016, 17:02 | цитировать цитировать  | профиль профиль  |  отправить письмо в личную почту пейджер
Usagisan:

//проходим по всем узлам, начиная с головы.
//т.к. pHead портить нельзя, используем дополнительную переменную node
//циклим, пока адрес узла не 0, т.е. пока не пройдем по всей цепочке
for(node=pHead; node; node=node->next)
//для каждого узла сравниваем буквы, если равны, получим 1, иначе 0
//node->info[0] даст нам первую букву слова node->info
//strlen(node->info)-1 дает адрес последней буквы слова
//node->info[strlen(node->info)-1] даст последнюю букву
//node->info[0] == node->info[strlen(node->info)-1] проверяем на равенство,
// в итоге получим 1, если равно, или 0, если неравно
//ну и складываем результат сравнения
count += (node->info[0] == node->info[strlen(node->info)-1]);
//можно было записать:
// if (node->info[0] == node->info[strlen(node->info)-1])
// count++;
//результат тот же

=====
Каждый выбирает по себе -
Щит и латы, посох и заплаты.
Меру окончательной расплаты
Каждый выбирает для себя.

Usagisan
Посетитель

ID: 400314

# 11

= общий = | 28.12.2016, 17:12 | цитировать цитировать  | профиль профиль  |  отправить письмо в личную почту пейджер

Большое спасибо за такие подробные ответы!

Лысков Игорь Витальевич
Старший модератор

ID: 7438

# 12

= общий = | 28.12.2016, 17:23 | цитировать цитировать  | профиль профиль  |  отправить письмо в личную почту пейджер
Usagisan:

Главное, чтобы на пользу smile smile

=====
Каждый выбирает по себе -
Щит и латы, посох и заплаты.
Меру окончательной расплаты
Каждый выбирает для себя.

 

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

Яндекс Rambler's Top100

главная страница | поддержка | задать вопрос | интересные статьи

Время генерирования страницы: 0.14760 сек.

© 2001-2017, Портал RFPRO.RU, Россия
Авторское право: ООО "Мастер-Эксперт Про"
Калашников О.А.  |  Гладенюк А.Г.
Версия системы: 7.40 от 02.09.2016
Бесплатные консультации онлайн