Консультация № 187824
22.04.2014, 16:36
156.36 руб.
0 13 1
Здравствуйте!
Нужна срочная помощь по решению этой лабы! Вся надежда на вас! smile
У меня возникли сложности с таким вопросом:
Из входного потока вводится произвольное число строк. Длинна строки не ограничена. Каждая строка представляет собой последовательность слов, разделенных одним или несколькими пробелами и/или знаками табуляции. Строка представлена списком (первое поле элемента списка - символ строки; второе- указатель на следующий элемент списка или NULL в конце списка). Конец ввода определяется концом файла.

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

Примечания:
1. Для ввода строк неопределённой длины посимвольный ввод не использовать!
2. Логически законченные части алгоритма решения задачи должны быть оформлены отдельными функциями с параметрами (например, ввод строки - списка, вывод списка, пропуск разделителей и др.).
3. Целесообразно обработку строки оформить отдельной функцией: структура программы должна быть следующей: пока не обнаружен конец файла {ввести строку, представленную списком; обработать список в соответствии с условием задачи; вывести результат; освободить память, выделенную под список}.
4. Новый список формировать, модифицируя исходный список.

Добавить комментарии по коду. Огромное спасибо!

Обсуждение

Неизвестный
22.04.2014, 19:43
общий
Компилирую в линуксе
давно
Профессионал
304622
583
23.04.2014, 00:12
общий
Что-то как-то мудрено. Что значит "строка представлена списком"? Если посимвольный ввод не использовать, то какой использовать (для неоганиченной строки")?
Неизвестный
23.04.2014, 06:02
общий
списком - т.е. не кусок памяти, как обычно, а связанный список, где данные одного элемента - символ.

Цитата: Сергей Бендер
Если посимвольный ввод не использовать, то какой использовать (для неоганиченной строки")?

там по тексту: "Конец ввода определяется концом файла.", т.е. читаем строку из файла
Неизвестный
23.04.2014, 06:04
общий
Тут вот какой момент непонятен: "Для каждой строки сформировать новую строку, составленную из последних букв каждого слова исходной строки. В полученной строке слова разделять только одним пробелом."

Т.е. "Мама мыла раму." превращается в "а а у."?
Неизвестный
23.04.2014, 07:55
общий
23.04.2014, 07:57
Да, все верно. Причем между словами может стоять несколько табуляций и/или пробелов. А в полученной строке буквы должны разделяться только 1 пробелом "
Неизвестный
23.04.2014, 08:20
общий
А какой-нить код есть уже? Или вообще пусто?
Неизвестный
23.04.2014, 08:59
общий
Пустой
Неизвестный
23.04.2014, 09:13
общий
ну если никто до завтра-послезавтра не возьмётся, я посмотрю
Неизвестный
25.04.2014, 10:35
общий
это ответ
Здравствуйте, Антон!

я сделал 2 класса, CNode - для одного узла с одним сиволом и указателем на следующий узел
CSentence - для содержания листа узлов и работы с ними

Основная функция main()
Логически законченные части алгоритма оформлены отдельными методами в классе CSentence и идут по очереди в main

Чтобы сильно не усложнять, я всё сделал в одной строке. Но при выводе учитываются символы превода строк и знаки пунктуации.
Учёт того, что нужно пропустить при разборе есть в условии:
Код:
if(strchr("\n:,.!?", pNodeNext->Char()))

т.е. тут не считаются частями слова: символ новой строки, двоеточие, запятая, точка, восклицательный и вопросительный знаки.

В функции main закомментирована зачитка из файла, вставлена зачитка из строки. Нужно закомментировать зачитку из строки, раскомментировать зачитку из файла и написать там своё имя файла

Проект сделан в MS Visual studio 6.0, как консольное приложение

Приложение:
//#include "stdafx.h"
#include <stdio.h>
#include <string.h>

#define NULL 0

//---------------------------------
// class CNode
//
// used to keep one character in
// our string in list

class CNode
{
char m_ch;
CNode *m_pNext;
public:
CNode(char c);
~CNode();
char Char(){return m_ch;}
CNode *Next() {return m_pNext;}
CNode *NextCreate(char c);
void NextSet(CNode *pNext) {m_pNext = pNext;}
void Convert(char cFrom, char cTo);
bool IsSpace() {return (strchr(" ", m_ch)!= NULL); }
};

CNode::CNode(char c)
{
m_ch = c;
m_pNext = NULL;
}
CNode::~CNode()
{
}

// create next Node for this Node and init it by c
CNode *CNode::NextCreate(char c)
{
return (m_pNext = new CNode(c));
}

// char checker and converter
void CNode::Convert(char cFrom, char cTo)
{
if(m_ch == cFrom)
m_ch = cTo;
}

//---------------------------------
// class CSentence
//
// used for sentence
// keep head of list of CNode
//
class CSentence
{
CNode *m_pHead;
public:
CSentence();
~CSentence();
void Clear();
bool IsEmpty() {return (m_pHead == NULL);}

void Create(char*pString);
void CreateFromFile(char* pFileName);

void StringAdd(char *pString);
void CharDel(CNode &pNodeDel, CNode *pStart = NULL);

void Process();

void Print();
};

CSentence::CSentence()
{
m_pHead = NULL;
}

CSentence::~CSentence()
{
Clear();
}

// make if empty
void CSentence::Clear()
{
CNode *pNode, *pNodeCur = m_pHead;
while(pNodeCur)
{
pNode = pNodeCur;
pNodeCur = pNode->Next();
delete pNode;
}
m_pHead = NULL;
}

// create Sentence from string
void CSentence::Create(char*pString)
{
if(!pString)
return;

Clear();

CNode *pNode = m_pHead = new CNode(*pString);
while(*(++pString))
pNode = pNode->NextCreate(*pString);
}

// create Sentence from file
void CSentence::CreateFromFile(char* pFileName)
{
char szLine[1024] = {0}; // one line in file
FILE *fptr = fopen(pFileName, "r");
if(fptr)
{
while(!feof(fptr)) // while not end of file
{
fgets(szLine, 1024, fptr); // get a line
StringAdd(szLine); // add that line
}
fclose(fptr);
}
}

// add string to current content of the Sentence
void CSentence::StringAdd(char* pString)
{
if(IsEmpty()) // if we have no context - create it
{
Create(pString);
}
else // else find a tail and concatenate
{
CNode *pNode = m_pHead; // begin from head

while(pNode->Next()) // find a tail
pNode = pNode->Next();

while(*pString) // add char by char
pNode = pNode->NextCreate(*pString++);
}
}

void CSentence::CharDel(CNode &pNodeDel, CNode *pStart)// = NULL
{
if(&pNodeDel == m_pHead) // if we delete a head Node:
{
CNode *pNode = m_pHead->Next();
delete m_pHead;
m_pHead = pNode;
return;
}

// else we find previous node and remove it
//
//1. ?-> pNode -> pNext
//2. pPrev-> pNode -> pNext
//3. pPrev X pNext
//4. pPrev -> pNext

CNode *pNode = pStart;
if(!pNode)
pNode = m_pHead;

// 1 & 2
while(pNode && (pNode->Next() != &pNodeDel))
pNode = pNode->Next();


if(pNode)
{
// 4.
pNode->NextSet(pNodeDel.Next());
// 3.
delete &pNodeDel;
}
}

void CSentence::Process()
{
if(IsEmpty())
return;

CNode *pNode = m_pHead;
pNode->Convert('\t', ' '); // check it's tab

CNode *pNodePrev = NULL;
CNode *pNodeNext = pNode->Next();
if(pNodeNext == NULL)
return; // nothing to process

while(pNodeNext)
{
if(strchr("\n:,.!?", pNodeNext->Char())) // if it's newline character or comma or smth like it...
{
pNode = pNode->Next(); // jump
if(!pNode)
break;
pNode = pNode->Next(); // jump
if(!pNode)
break;
pNodeNext = pNode->Next();
continue;
}

pNodeNext->Convert('\t', ' '); // check it's tab

// both are Spaces
if(pNode->IsSpace() && pNodeNext->IsSpace())
{
CharDel(*pNodeNext, pNode); // remove next
pNodeNext = pNode->Next(); // go to next Node
continue;
}

// both are not Spaces
if(!pNode->IsSpace() && !pNodeNext->IsSpace())
{
pNodeNext = pNode->Next(); // look for own Next
CharDel(*pNode, pNodePrev); // remove current
pNode = pNodeNext; // now current is his own Next
pNodeNext = pNode->Next(); // go to next Node
continue;
}
// edge
pNodePrev = pNode; // remember start pos for searching (see CharDel)
pNode = pNode->Next(); // jump to next position
pNodeNext = pNode->Next(); // jump to next position
}
}

// pring string char by char
void CSentence::Print()
{
CNode *pNode = m_pHead;
while(pNode)
{
printf("%c", pNode->Char());
pNode = pNode->Next();
}
}

//---------------------------------
int main(int argc, char* argv[])
{
CSentence Sntc;

// Load a string
Sntc.Create("Hello, world \t and you: all!");
//Sntc.CreateFromFile("c:\\info.txt");

// show, what we got
Sntc.Print();
printf("\n---\n"); // text divider

// process the string
Sntc.Process();

// show what we have now
Sntc.Print();

return 0;
}
Неизвестный
08.05.2014, 09:31
общий

вот такое при компиляции
Неизвестный
08.05.2014, 09:48
общий
это warning компилятора, ничего страшного, это он пугается, что константную строку передают в функцию, которая по описанию работает с переменными(строками).
Можно в коде заменить

void Create(char*pString);

на

void Create(const char*pString);

и

void CSentence::Create(char*pString)

на

void CSentence::Create(const char*pString)
Неизвестный
08.05.2014, 12:14
общий
теперь при раскомментировании зачитку из файла:

и повторной конмиляции он пишет это :

Неизвестный
08.05.2014, 12:27
общий
тоже самое, добавить const перед char* тут:

void CreateFromFile(char* pFileName);
void CSentence::CreateFromFile(char* pFileName)

а сама программа-то собирается? Несмотря на warning-и она должна собираться и работать. Или GCC не собирает бинарник при warning-ах?
Форма ответа