Нужна помощь с 3 лабами (за деньги)
Ниже будут условия для трех моих лабораторных по программированию (на C++, в Visual Studio 2008 [ну, сдавать на нем]). Хочется узнать, за сколько сделаете и в какие сроки.
Проги нужно писать без особых умностей и не скупиться на комментарии. Я должен понять код, иначе будут проблемы с последующей сдачей.
В C++ разбираюсь плохо, но и не ноль полный: из 10 почти 6.5 лаб сделал сам:)
На всякий случай задания даю в виде прикрепленного файла Word. И большая просьба: не цитировать в форуме задание: мой препод хорошо умеет пользоваться гуглом:)
PS
"Лабы" - это все условия лаб в текстовом файле;
на C++, в Visual Studio 2008
...
"Lab7" - это я попытался сделать Лабу 7, №1. Все сделал, осталось только придумать, как загружать исходную строку.
Седьмая лаба действительно практически сделана.
Замечания: System и System::IO - это пространства имён FCL платформы .NET. То есть предназначены для "управляемого" C++. Короче, выкидываем эти строки:
using namespace System::IO; // удаляем
Раз уж вы пишете на C++, а не на C, то для чтения из файла лучше использовать не FILE *f (что подразумевает применение fscanf), а потоки:
//FILE *f;//хранится заданная фраза - это выкидываем
ifstream f; // объявляем поток для чтений
f.open("test.txt"); // открываем поток
getline(f, s); // читаем строку
f.close(); // закрываем поток
Если теперь запустить программу, выскочит ошибка. Причина - не задано начальное значение переменной k. Исправляется это просто: unsigned int i = 0, j, k = 0; // счетчик. Мораль: переменные нужно инициализировать всегда!
Поэтому в процессе поиска нечаянно натыкаюсь на решение моей проблемы, разбираюсь много-много часов подряд, а потом оказывается, что тоже самое можно сделать существенно проще (например - я пытался использовать класс String^, но потом оказалось, что гораздо проще работать со string. Разницу так и не просек).
koodeer, у меня сейчас появилась отличная идея. Я буду вам очень благодарен, если поддержите меня.
Вот вы прочитали тексты трех лаб, и, конечно, видите решение. А не могли бы по каждой кратко написать, в каком направлении мне искать информацию?
Идея в том, чтобы я не копал весь инет в поисках сам-не-знаю-чего, а искать прицельно то, что поможет решить задачу.
PS Ошибок на тему инициализации k не возникло. Даже Предупреждений не было :)
Ошибок не было? Будут! Очевидно вы компилили программу в конфигурации Release. Если скомпилировать в конфигурации Debug, то ошибка возникает всегда:
Разница есть. Если в объявлении переменных (типов) присутствует знак ^ - значит, это один из типов управляемого C++.NET. Если в своих исканиях по интернету встречаете код C++ с такими знаками, то можете сразу его пропускать. Аналогично, если в примерах кода встречаются записи using namespace System; это тоже свидетельство управляемого C++. Также не обращайте внимание на код C++, если прямо написано, что он под платформу .NET. Вам это пока не нужно. В принципе, можно смешивать в одной программе управляемый и неуправляемый код, но лучше этого не делать, особенно на начальных порах.
Идея в том, чтобы я не копал весь инет в поисках сам-не-знаю-чего, а искать прицельно то, что поможет решить задачу.
Собсно, я даже не знаю, что подсказать. Имхо, лабы решаются элементарно. Ничуть не сложнее седьмой.
Достаточно ввести в гугле что-то вроде односвязный список исходник с++ и в ссылках можно утонуть. Не знаю что проще: найти в этом море инфы нужное или написать код самому :).
Подсказки по последней лабе: скопировав класс танализ (пишу по-русски - шифруемся от препода :D), не забудьте поставить в конце точку с запятой ;. Для замены символов вполне естественно использовать метод replace класса string.
Хех, у меня та же проблема... Я потому и помогаю, чтобы самому освоить что-то новое по ходу дела. С++ действительно очень объёмен, именно за это его любят и ненавидят. :cool:
Что ж. Раз просто, то сделаю сам. Хотя с ужасом вспоминаю, что седьмую лабу, первую часть, делал примерно 2 дня полных (с утра до вечера). Именно потому, что находил не ту информацию, которую надо (это к вопросу о [FONT="Lucida Console"]String^[/FONT] и [FONT="Lucida Console"]string[/FONT]).
В общем, с вашими подсказками поиск будет гораздо проще и эффективнее. Если столкнусь с «нерешаемыми» проблемами – очень надеюсь на вашу помощь здесь:).
Начал делать 10 лабу. Запнулся почему-то не на создании класса (с этим все гладко было), а в процессе кодинга.
Что делает нижеописанный метод: Определить, сколько раз в заданном предложении встречаются 3 одинаковых символа подряд (учитываем, что это могут быть 2 разных символа).
Замечание1: я решил сначала отдельно написать метод, а потом засунуть его в класс.
Замечание2: комментарии писал чисто для себя, не задумывался об их понятности. Поэтому если возникают вопросы - задавайте.
#include "windows.h"
#include "stdio.h"
#include <conio.h>
#include "vector"
#include <string>
#include <iostream>
#include "locale"
#include <fstream>
using namespace std;
int main()
{
setlocale(LC_ALL,"Russian");
ifstream Input;//поток на ввод
ofstream Output;//поток на вывод
string s1;//заданная строка
vector <char> M1;//содержит буквы, создающие искомые комбинации
vector <int> M2;//содержит количество раз, которые встречаются эти комбинации
Input.open("C:\\Users\\Михаил\\Desktop\\ДРП\\Lab10Help\\Input.txt");
Output.open("C:\\Users\\Михаил\\Desktop\\ДРП\\Lab10Help\\Output.txt");
getline(Input,s1);
char buf2=s1.at(0), buf1=' ',buf3=' ';//buf2 - текущий символ, buf1 - предыдущий, buf3 - следующий
char buf;
unsigned short int i=0,j=0;//счетчики
unsigned short int k=0;//считает 3 одинаковых символа
unsigned short int z=0;//считает, скольок раз эта комбинация встретилась в предложении
bool flag=true;
for (i = 0 ; i < s1.length()-1 ; i++)
{
//находим 3 следующих подряд одинаковых символа
buf2 = s1.at(i); buf3 = s1.at(i+1);
if (buf2 == buf1 && buf2 == buf3) k++;//Если и предыдущий, и следующий символы равны текущему (buf2)
buf1 = s1.at(i);
[COLOR="DarkRed"]if (M1.empty() && k == 1) M1.at(0) = buf2; else[/COLOR]//Если M1 пуст и найдена искомая комбинация, то можно задать начальное значение для M1
{
if (k == 1)
{
for (j = 1 ; j < M1.max_size() ; j++)//определяем, встречался ли уже такой buf
{
buf = M1.at(j);
if (buf == buf2) flag = false;
}
if (flag)//если да - добавляем новую букву в M1 и количество ее обнаружений (1) - в M2
{
M1.push_back(buf2);
M2.push_back(1);
}
else M2.at(j) = M2.at(j) + 1;//если нет - то увеличиваем количество обнаружений в M2 соответствующего buf на 1
}
}
}
_getch();
return 0;
}
Проблема появилась в строке [FONT="Lucida Console"][COLOR="DarkRed"]if (M1.empty() && k == 1) M1.at(0) = buf2; else[/COLOR][/FONT]. Выдается ошибка:
Дополнительные сведения: Внешний компонент создал исключение.
То ли ему не нравится сравнение в [FONT="Lucida Console"]if ()[/FONT], то ли присваивание, следующее за [FONT="Lucida Console"]if[/FONT].
И вдогонку вопрос, не относящийся к теме сообщения: чем отличается объявление заголовочных файлов при использовании [FONT="Lucida Console"]""[/FONT] и [FONT="Lucida Console"]<>[/FONT] ? Т.е. чем отличается [FONT="Lucida Console"]#include <conio.h>[/FONT] от [FONT="Lucida Console"]#include "conio.h"[/FONT] ?
PS 2koodeer: Лабу 7 спокойно сдал преподу.
Проблема появилась в строке [FONT="Lucida Console"][COLOR="DarkRed"]if (M1.empty() && k == 1) M1.at(0) = buf2; else[/COLOR][/FONT].
То ли ему не нравится сравнение в [FONT="Lucida Console"]if ()[/FONT], то ли присваивание, следующее за [FONT="Lucida Console"]if[/FONT].
С помощью функции at можно работать лишь с уже существующими элементами вектора! Если элемента под номером n не существует, то нельзя к нему обратиться at(n).
В данном случае
происходит попытка присвоения значения нулевому элементу в то время, как вектор пуст! Ведь условие empty() сработало.
Нужно переписать так:
Ещё ошибка:
Надо:
Смотрим: max_size
В алгоритм не вникал, но заметил, что индекс j может выйти за размер вектора M2 здесь:
И вдогонку вопрос, не относящийся к теме сообщения: чем отличается объявление заголовочных файлов при использовании [FONT="Lucida Console"]""[/FONT] и [FONT="Lucida Console"]<>[/FONT] ? Т.е. чем отличается [FONT="Lucida Console"]#include <conio.h>[/FONT] от [FONT="Lucida Console"]#include "conio.h"[/FONT] ?
Смотрим: Директива #include
Вот что я наваял:
#include <iostream> // cout
#include <fstream> // ifstream, ofstream
#include <string> // string, getline
#include <atlstr.h> // CString
#include <conio.h> // getch()
using namespace std;
class _analiz
{
char s;
public:
_analiz(char s1) {s=s1;}
int analiz()
{
//int i; // Нахуя?
if (isdigit(s)!=0) return 1;//цифра
if (islower(s)!=0) return 2;//нижн. регистр
if (isupper(s)!=0) return 3;//верхн. регистр
if (isspace(s)!=0) return 4;//пробел
if (ispunct(s)!=0) return 5;//разделитель
return 0;//др. символ
}
};
void main()
{
setlocale(LC_ALL, "Russian");
string s; // нужна только для чтения из файла
ifstream Input;
Input.open("...");
getline(Input, s);
Input.close();
CString cs(s.c_str()); // дальше работаем с CString
cout << cs << endl; // исходная строка
for (char ch='0'; ch<='9'; ++ch)
cs.Remove(ch); // удаляем цифры
cout << cs << endl; // строка после удаления цифр
cs.Replace(' ', '_'); // меняем пробелы на подчёркивания
cout << cs << endl; // строка после замены пробелов подчерками
int count = 0; // счётчик вхождений трёх одинаковых символов подряд
for (int i = 0; i < cs.GetLength() - 2; ++i)
{
char ch = cs.GetAt(i);
if (ch == cs.GetAt(i+1) && ch == cs.GetAt(i+2))
{
_analiz t(ch);
if (t.analiz() == 2) // нижний регистр
{
CString source(ch, 3); // что меняем (три одинаковых символа)
CString dest( (char)_toupper(ch) ); // на что меняем
count += cs.Replace(source, dest);
}
else if (t.analiz() == 3) // верхний регистр
{
CString source(ch, 3); // что меняем (три одинаковых символа)
CString dest( (char)_tolower(ch) ); // на что меняем
count += cs.Replace(source, dest);
}
else count++;
}
}
cout << cs << endl; // строка после всех замен
cout << "Count = " << count << endl;
ofstream Output;
Output.open("...");
Output << cs;
Output.close();
getch();
}
Пришлось поломать голову, как сюда приткнуть рекомендованный класс. (Заменил в его названии первую буковку - шифруемся :D).
Применил в коде тип строки CString. В нём очень удобны, на мой взгляд, методы Remove и Replace.
Поясню их принцип работы: Remove удаляет все вхождения указанного символа из строки. Replace производит замену тоже во всей строке всех совпадений. Метод Replace возвращает количество произведённых замен, именно его и прибавляем к count.
Комбинация с буквой "р" встретилась 1 раз
Комбинация с буквой "п" встретилась 2 раз
Либо я не понял твоего кода, и он учитывает этот момент тоже:) Я сделал так:
#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <vector>
#include <string>
#include <iostream>
#include <locale>
#include <fstream>
using namespace std;
class Search
{
public:
Search(string s);//Конструктор
~Search();//Деструктор
//void DelNumber(s1);//удаление цифр
//void Lowercase(s1);//если буквы нижнего регистра, заменить на верхнего
//void Uppercase(s1);//если буквы верхнего регистра, заменить на нижнего
//void ReplaceSpace(s1);//замена пробелов на знаки подчеркивания
int Detect();//определить, сколько раз встречаются 3 одинаковых символа
private:
string s1;//данная строка
};
Search::Search(string s)
{
s1 = s;
}
Search::~Search()
{
}
int Search::Detect()
{
vector <char> M1;//содержит буквы, создающие искомые комбинации
vector <int> M2;//содержит количество раз, которые встречаются эти комбинации
char buf2=s1.at(0), buf1=' ',buf3=' ';//buf2 - текущий символ, buf1 - предыдущий, buf3 - следующий
char buf=' ';//буфер
unsigned short int i=0,j=0;//счетчики
unsigned short int k=0;//если найдено 3 одинаковых символа подряд, k = 1
unsigned short int z=0;
bool flag=true;
for (i = 0 ; i < s1.length()-1 ; i++)
{
buf2 = s1.at(i); buf3 = s1.at(i+1);
if (buf2 == buf1 && buf2 == buf3) k++;//Если и предыдущий, и следующий символы равны текущему (buf2)
buf1 = s1.at(i);
if (k == 1)
{
for (j = 0 ; j < M1.size() ; j++)//определяем, встречался ли уже такой buf
{
buf = M1.at(j);
if (buf == buf2) {flag = false; z = j;}//если да, сохраняем номер соответствующей позиции в M1
}
if (flag)//если нет - то увеличиваем количество обнаружений (M2) соответствующего buf на 1
{
M1.push_back(buf2);
M2.push_back(1);
}
else {M2.at(z) = M2.at(z) + 1;}
}
k = 0; flag = true;
}
cout << "В введенной фразе следующие символы удовлетворяют поставленному условию:\n";
for (i = 0 ; i < M1.size() ; i++)
{
cout << "\nКомбинация с символом '" << M1.at(i) << "' встречается " << M2.at(i) << " раз";
}
return 0;
}
int main()
{
setlocale(LC_ALL,"Russian");
ifstream Input;//поток на ввод
ofstream Output;//поток на вывод
string s11;//заданная строка
Input.open("C:\\Users\\Михаил\\Desktop\\ДРП\\Lab10\\Input.txt");
Output.open("C:\\Users\\Михаил\\Desktop\\ДРП\\Lab10\\Output.txt");
getline(Input,s11);
Search analiz(s11);
analiz.Detect();
_getch();
return 0;
}
PS Я вроде говорил, что препод позволил менять класс. Это я к тому, что мой класс в общем не особо похож на то, что было задано :)
Комбинация с буквой "р" встретилась 1 раз
Комбинация с буквой "п" встретилась 2 раз
Либо я не понял твоего кода, и он учитывает этот момент тоже:)
Нет, в том моём варианте подсчёта отдельных комбинаций не предусмотрено. Считается лишь их общее количество.
В твой код не вникал, могу лишь отметить неудачный нейминг векторов: M1 и M2 - такие названия совершенно ни о чём не говорят. Вот названия для функций выбраны довольно удачные.
PS Я вроде говорил, что препод позволил менять класс. Это я к тому, что мой класс в общем не особо похож на то, что было задано :)
Где такое было сказано?
Ну, если нет необходимости использовать никчёмный класс, то вот мой новый вариант, подсчитывающий отдельно количество вхождений 3 символов:
#include <iostream> // cout
#include <fstream> // ifstream, ofstream
#include <string> // string, getline
#include <atlstr.h> // CString
#include <conio.h> // _getch()
#include <vector> // vector
#include <map> // map
#include <locale> // locale
using namespace std;
void main()
{
setlocale(LC_ALL, "Russian"); // для вывода русских букв в консоли
locale rus("Russian_Russia"); // для работы функций islower, isupper с русскими буквами
string s; // нужна только для чтения из файла
ifstream Input;
Input.open("...");
getline(Input, s);
Input.close();
CString cs(s.c_str()); // дальше работаем с CString
cout << cs << endl; // исходная строка
for (TCHAR ch='0'; ch<='9'; ++ch)
cs.Remove(ch); // удаляем цифры
cout << cs << endl; // строка после удаления цифр
cs.Replace(' ', '_'); // меняем пробелы на подчёркивания
cout << cs << endl; // строка после замены пробелов подчерками
map<TCHAR, int> m;
for (int i = 0; i < cs.GetLength() - 2; ++i)
{
TCHAR ch = cs.GetAt(i);
if (ch == cs.GetAt(i+1) && ch == cs.GetAt(i+2))
{
if (islower(ch, rus)) // нижний регистр
{
CString source(ch, 3); // что меняем (три одинаковых символа)
CString dest( (char)_toupper(ch) ); // на что меняем
m[ch] = cs.Replace(source, dest);
}
else if (isupper(ch, rus)) // верхний регистр
{
CString source(ch, 3); // что меняем (три одинаковых символа)
CString dest( (char)_tolower(ch) ); // на что меняем
m[ch] = cs.Replace(source, dest);
}
else
{
m[ch]++; // считаем
i += 2; // перепрыгиваем через одинаковые символы
}
}
}
cout << cs << endl; // строка после всех замен
map<TCHAR, int>::iterator iter;
for (iter = m.begin(); iter != m.end(); ++iter)
cout << "Подряд 3 символа '" << iter->first << "' встретились " << iter->second << " раз" << endl;
ofstream Output;
Output.open("...");
Output << cs;
Output.close();
_getch();
}
Код исправлен по сравнению с предыдущим и теперь при компиляции не выдаётся ни одного предупреждения.
Компилил в Visual Studio 2005. Проверял и Debug, и Release.
Ма-а-аленькая подсказка: в свойствах проекта обязательно выставить свойство Character set в значение Use Multi-Byte Character Set. Со значением Use Unicode Character Set программа будет работать неправильно. Причём сделать это нужно как в конфигурации Debug, так и Release.
PS: я однако отжог в комментариях ненужной переменной в прошлый раз :)
koodeer, класс обязательно нужно использовать, но его можно менять по своему усмотрению.
Сможешь помочь переделать прогу? То есть понятно, что по сути появятся только 1) новые переменные, для передачи их методам-членам и 2) куски кода будут разбросаны по этим методам.
Но я никогда не работал с [FONT="Lucida Console"]CString[/FONT] и [FONT="Lucida Console"]map[/FONT], да и классы в новинку. И разбираться щас с этим воооще нереал.:confused:
Все в порядке вещей:D
- Насколько хорошая реализация?
- В чем ошибка? (строку, которая выдает ошибку, я выделил в [FONT="Lucida Console"]коде[/FONT] жирным). То есть программа запускается, но на определенном этапе вылетает.
#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <vector>
#include <string>
#include <iostream>
#include <locale>
#include <fstream>
#include <set>
using namespace std;
int main()
{
setlocale(LC_ALL,"Russian");
vector <char> M1;//содержит буквы, создающие искомые комбинации
vector <int> M2;//содержит количество раз, которые встречаются эти комбинации
ifstream Input;//поток на ввод
ofstream Output;//поток на вывод
string s1,s2;//заданная строка и ее копия (вспомогательная)
string substr;//подстрока
string::iterator it1, it2;//итераторы
unsigned short int i=0,z=0;//счетчики
size_t found;//ищет вхождения подстроки substr
char buf1, buf2;
bool flag=true;
Input.open("...");
Output.open("...");
getline(Input,s1); Input.close(); s2 = s1;
for (it1 = s1.begin() ; it1 < s1.end() ; it1++)
{
for (i = 0 ; i < 3 ; i++) substr.push_back(*it1);//выделили подстроку
found = s1.find(substr);
if (found < s1.length())//если такая подстрока есть, то:
{
for (i = 0 ; i < M1.size() ; i++)//1. Определяем, встречалась ли уже такая подстрока substr
{
buf1 = M1.at(i); buf2 = substr.at(0);
if (buf1 == buf2) {flag = false; z = i;}
}
if (flag)//2.1. Если НЕ встречалась - то записываем новую комбинацию в M1
{
M1.push_back(substr.at(0));
M2.push_back(1);
}
else//2.2. Если встречалась - то увеличиваем количество обнаружений (M2) на 1
{
M2.at(z) = M2.at(z) + 1;
flag = true;
}
s1.erase(found,3);
}
substr.clear();
}
cout << "Была введена следующая фраза:\n" << s2 << "\n\n";
cout << "\nВ введенной фразе следующие символы удовлетворяют поставленному условию:";
for (i = 0 ; i < M1.size() ; i++)
{
cout << "\nКомбинация с символом '" << M1.at(i) << "' встречается " << M2.at(i) << " раз";
}
_getch();
return 0;
}
В чем ошибка?
...
То есть программа запускается, но на определенном этапе вылетает.
for (it1 = s1.begin() ; it1 < s1.end() ; it1++)
{
...
s1.[COLOR="Red"]erase[/COLOR](found,3);
...
}
Скорее всего, ошибка в этом. Используя итератор нельзя менять содержимое контейнера, к которому обращается итератор. С помощью итератора можно лишь читать данные.
Исчо адын вариант:
#include <iostream> // cout
#include <fstream> // ifstream, ofstream
#include <string> // string, getline
#include <atlstr.h> // CString
#include <conio.h> // _getch()
#include <vector> // vector
#include <map> // map
#include <locale> // locale
using namespace std;
class tanaliz
{
char s;
locale loc;
public:
tanaliz(char s1, locale loc1)
{
s = s1;
loc = loc1;
}
int analiz()
{
if (isdigit(s, loc)!=0) return 1;//цифра
if (islower(s, loc)!=0) return 2;//нижн. регистр
if (isupper(s, loc)!=0) return 3;//верхн. регистр
if (isspace(s, loc)!=0) return 4;//пробел
if (ispunct(s, loc)!=0) return 5;//разделитель
return 0;//др. символ
}
};
void main()
{
setlocale(LC_ALL, "Russian");
locale rus("Russian_Russia");
string s; // нужна только для чтения из файла
ifstream Input;
Input.open("...");
getline(Input, s);
Input.close();
CString cs(s.c_str()); // дальше работаем с CString
cout << cs << endl; // исходная строка
for (TCHAR ch='0'; ch<='9'; ++ch)
cs.Remove(ch); // удаляем цифры
cout << cs << endl; // строка после удаления цифр
cs.Replace(' ', '_'); // меняем пробелы на подчёркивания
cout << cs << endl; // строка после замены пробелов подчерками
map<TCHAR, int> m;
for (int i = 0; i < cs.GetLength() - 2; ++i)
{
TCHAR ch = cs.GetAt(i);
if (ch == cs.GetAt(i+1) && ch == cs.GetAt(i+2))
{
tanaliz t(ch, rus);
if (t.analiz() == 2) // нижний регистр
{
CString source(ch, 3); // что меняем (три одинаковых символа)
CString dest( (char)_toupper(ch) ); // на что меняем
m[ch] = cs.Replace(source, dest);
}
else if (t.analiz() == 3) // верхний регистр
{
CString source(ch, 3); // что меняем (три одинаковых символа)
CString dest( (char)_tolower(ch) ); // на что меняем
m[ch] = cs.Replace(source, dest);
}
else
{
m[ch]++; // считаем
i += 2; // перепрыгиваем через одинаковые символы
}
}
}
cout << cs << endl; // строка после всех замен
map<TCHAR, int>::iterator iter;
for (iter = m.begin(); iter != m.end(); ++iter)
cout << "Подряд 3 символа '" << iter->first << "' встретились " << iter->second << " раз" << endl;
ofstream Output;
Output.open("...");
Output << cs;
Output.close();
_getch();
}
Класс допилил, чтобы он работал с русскими буквами.