Ru-Board.club
← Вернуться в раздел «Прикладное программирование»

» Вопросы по программированию на C/С++

Автор: Cheery
Дата сообщения: 10.07.2007 03:38
Igorr

Цитата:
а если нужны фукции типа, то они у вас и так уже переопределены.
или я не понял проблему.

да я без функций хотел обойтись.. ну да ладно, главное, что сейчас работает.. спасибо.
ps: если кому нужна книга Addison Wesley: C++ Templates: The Complete Guide могу выложить в ebookz.. слил только что и читаю
Автор: Qraizer
Дата сообщения: 10.07.2007 12:43
А так не пробовал?
Код: inline double pi()
{
static const double pi_value=2*acos(0.0);
return pi_value;
}
Автор: Cheery
Дата сообщения: 13.07.2007 01:05
эм.. а вот такое кто нить может объяснить? Visual Studio 2005 Pro
cout выдает правильное значение, а вот дебаг..

бррр.. причем ведет себя так только с переменными определенными в функции.. глобальные показывает правильно

ps: SP1 проблемы не решил
pps: похоже нашел в чем дело
http://support.microsoft.com/kb/100773/en-us?spid=3041&sid=1310
глупо
Автор: Antananarivu
Дата сообщения: 13.07.2007 13:46
Сразу скажу я новенький в этом деле, поэтому вопросы будут глупые, смешные и непоследовательные...
А теперь вопрос.. наткнулся в программе, которую пытаюсь понять на такую строчку
return (&x)[i-1];
при этом x,y,z - это переменные типа Double, объявленные в этом классе. В зависимости от i мы получаем, - (&x)[0] - x; (&x)[1] - y; (&x)[2] - z.
Вот собственно и все... Вопрос, что здесь происходит? Как это называется и где об этом можно почитать? Я так понимаю, что берется адрес переменной и индексируется, но во-первых я нигде не встречал, что это так возможно (согласитесь, что это не очевидно, это же не массив, не контейнер), а во-вторых, почему получается, что x,y,z лежат в памяти друг за другом (может они и не лежат, допускаю, что это я чего-то совсем уж глобально не понял).
В общем буду благодарен за любой ответ, а уж за подробное объяснение или за ссылку на главу учебника буду благодарен еще больше! Заранее спасибо..
Автор: Cheery
Дата сообщения: 13.07.2007 20:36
Antananarivu

Цитата:
Вопрос, что здесь происходит?

что происходит - возвращается адрес элемента i-1 массива
Автор: Antananarivu
Дата сообщения: 13.07.2007 21:09
Cheery
Все равно не понимаю... какой массив?
class T3DVector
{
double x,y,z;
T3DVector (double x0,y0,z0){x=x0,y=y0,z=z0};
double& T3DVector operator[](int i) {return (&x)[i-1];};
}
int main()
{
T3DVector vec(11,22,33);
double x1=vec[1];
cout << x1 <<endl; // выдадет 11
x1=vec[2];
cout << x1 <<endl; // выдадет 22
x1=vec[3];
cout << x1 <<endl; // выдадет 33
return 0;
}
Пишу по памяти... к сожалению сейчас под рукой нет программы... мог наврать в программном коде, но смысл я думаю понятен.
Тут нет никакого массива, тут просто x,y,z. Что мы индексируем? Почему это работает? Что это вообще за форма записи (&x)[i-1]? Я такую нигде не встречал... Я чувствую, что глобально чего то не понимаю... где об этом можно почитать?...
Автор: Abs62
Дата сообщения: 14.07.2007 18:04
Antananarivu

Цитата:
Что это вообще за форма записи (&x)[i-1]? Я такую нигде не встречал...

Краткая.

Код: double *p=&x;
x1=p[i-1];
Автор: Antananarivu
Дата сообщения: 14.07.2007 18:36
Да, что-то начал понимать! Спасибо! Но пока до книжки не добрался, хочу еще спросить в правильном направлении ли я мыслю.
double *p = &x; - тут p указатель типа double, который указывает на адресс переменной x. Верно?
x1 = p[i-1]; тут мы записываем в х1 значение переменной на которую в данный момент указывает указатель, так?
Вопроса два: во-первых, что мы получим, например в данном случае:
x1 = p[100]; ? Я так понимаю получим полный бред, точнее значение, которое заранее неизвестно, то есть мы возьмем значение некоего адреса в области памяти, так?
И во-вторых, в изложенном выше примере класса, откуда у нас уверенность, что в памяти машины адреса переменных x,y,z будут располагаться друг за другом? Ну то есть, почему, написав x1 = p[0] мы получим х, х1 = p[1] получим y, x1=p[2] получим z?
Автор: Abs62
Дата сообщения: 14.07.2007 19:30
Antananarivu

Цитата:
то есть мы возьмем значение некоего адреса в области памяти, так?

Примерно так. Получим значение, лежащее по адресу p+100. Причём целевой адрес зависит от типа указателя. Доберёшься до книги - прочитаешь.

Цитата:
И во-вторых, в изложенном выше примере класса, откуда у нас уверенность, что в памяти машины адреса переменных x,y,z будут располагаться друг за другом?

Расположение в памяти членов класса прописано в разделе 9.2 Стандарта C++:

Цитата:
12 Nonstatic data members of a (non-union) class declared without an intervening access-specifier are allocated so that later members have higher addresses within a class object. The order of allocation of nonstatic data members separated by an access-specifier is unspecified (11.1). Implementation alignment requirements might cause two adjacent members not to be allocated immediately after each other; so might requirements for space for managing virtual functions (10.3) and virtual base classes (10.1).
Автор: Cheery
Дата сообщения: 14.07.2007 19:41
Вот, кстати, как выглядит код
http://mia.sourceforge.net/doku/lib/3DVector_8hh-source.html
Автор: Antananarivu
Дата сообщения: 14.07.2007 20:15
Abs62
Cheery
Спасибо.... теперь еще текст стандарта придется видимо изучать. А у меня с английским неважно Вот ведь как, начинаешь изучать, вроде ничего сложного, учебник для начинающих 100 страниц, а начинаешь копать и чуть ли не в любой строчке вопрос, ответ на который открывает все глубины твоего незнания... вот теперь еще стандарт открылся... темный лес для меня.
Еще по поводу ссылки... значит это некий стандартный класс 3DVector, точнее даже шаблон? Я просто до шаблонов еще не дошел. А кем он написан? А то нашим программистом это вроде представлялось как его собственное творение! ли я чего-то не понял?
P.S. Интересно быстро ли я утомлю вас вопросами?.. Но ведь правда очень интересно, а сам во всем разобраться не могу и больше спросить не у кого.
Автор: Igorr
Дата сообщения: 14.07.2007 21:00
Antananarivu

Цитата:
сам во всем разобраться не могу и больше спросить не у кого.

Цитата:
Но пока до книжки не добрался

Без знаний основ Си копаться в кодах Си++ - неэффективная трата времени. Начните, хотя бы, с Б.Керниган, Д.Ритчи "Язык программирования Си" (я, например, с нее начинал, правда, после Фортрана). Только после этого смотрите литературу по Си++ (здесь на форуме есть специальные темы по электронной литературе по программированию). Иначе, предполагаю, вам все это может быстро надоесть и отбить всякое желание заниматься программированием в дальнейшем.
Автор: TeXpert
Дата сообщения: 14.07.2007 22:45
Antananarivu
Возьми книгу (лучше всё же купи!) Липпмана со товарищи "Язык программирования C++: Вводный курс", последнее издание. Изложение элементарное и современное.
Автор: Antananarivu
Дата сообщения: 14.07.2007 23:40
TeXpert
А я как раз по этой книге и занимаюсь Видимо, что-то упустил, во всяком случае, в памяти того, что любой указатель можно индексировать не осталось. То, что с помощью звездочки можно взять значение, осталось, а вот про индексирование нет
Автор: BattleMage
Дата сообщения: 14.07.2007 23:56
Доброго времени суток. Подскажите ламерку в чём ошибка...
Вобщем пишу некоторое подобие базы данных книг в С++Builder. Берём StringGrid и записываем в ячейки некоторые данные (5 полей: название, автор, жанр, издательство, год издания). Данные вводятся в Edit-ы.

Структура объявлена так:
struct kniga
{
struct kniga *next;
char nazvanie[20];
char avtor[20];
char zhanr[20];
char izdatelstvo[20];
int god_izdaniya;
};
struct kniga *ptr;

При записывании содержимого полей ввода (Edit-ов) в соответствующие поля структуры, возникает ошибка Lvalue required. Что это значит?

Компилятор указывает на строчки:
ptr->nazvanie=Edit1->Text;
ptr->avtor=Edit2->Text;
ptr->zhanr=Edit3->Text;
ptr->izdatelstvo=Edit4->Text;
ptr->god_izdaniya=IntToStr(Edit5->Text);

Заранее спасибо
Автор: xdude
Дата сообщения: 15.07.2007 04:01
BattleMage
Дык нельзя в массив просто запхать другой массив. Замени
Код: ptr->nazvanie=Edit1->Text
Автор: Cheery
Дата сообщения: 15.07.2007 04:04

Цитата:
ptr->god_izdaniya=IntToStr(Edit5->Text);

может наоборот?
Автор: BattleMage
Дата сообщения: 15.07.2007 09:56
xdude
Дык нельзя в массив просто запхать другой массив. Замени ptr->nazvanie=Edit1->Text на
strcpy(ptr->nazvanie, Edit1->Text)

Уже попробывал... Ни фига, теперь на строчке strcpy(ptr->nazvanie)=Edit1->Text;
показывает 2 ошибки:
[C++ Error] Unit1.cpp(42): E2193 Too few parameters in call to 'strcpy(char *,const char *)'
[C++ Error] Unit1.cpp(42): E2277 Lvalue required

Добавлено:
Cheery, кстати ты прав по поводу "наоборот"

Добавлено:
ой ой ой... прошу прощения за тупость, xdude. не так напсиал.
так надо было: strcpy(ptr->nazvanie,Edit1->Text);
хотя все равно не помогло

теперь нет ошибки Lvalue required? зато есть такие:
[C++ Error] Unit1.cpp(42): E2034 Cannot convert 'AnsiString' to 'const char *'
[C++ Error] Unit1.cpp(42): E2342 Type mismatch in parameter '__src' (wanted 'const char *', got 'AnsiString')
Автор: Zyava
Дата сообщения: 15.07.2007 14:55

Цитата:
теперь нет ошибки Lvalue required? зато есть такие:
[C++ Error] Unit1.cpp(42): E2034 Cannot convert 'AnsiString' to 'const char *'
[C++ Error] Unit1.cpp(42): E2342 Type mismatch in parameter '__src' (wanted 'const char *', got 'AnsiString')


А так?
strcpy(ptr->nazvanie, Edit1->Text.c_str());
Автор: BattleMage
Дата сообщения: 15.07.2007 15:34
Zyava, скомпилировалось, но вот что-то это меня не сделало радостым...

теперь написано так:
strcpy(ptr->nazvanie, Edit1->Text.c_str());
strcpy(ptr->avtor, Edit2->Text.c_str());
strcpy(ptr->zhanr, Edit3->Text.c_str());
strcpy(ptr->izdatelstvo, Edit4->Text.c_str());
ptr->god_izdaniya=StrToInt(Edit5->Text);

Объявление структуры такое же:
struct kniga
{
struct kniga *next;
char nazvanie[20];
AnsiString avtor;
AnsiString zhanr;
AnsiString izdatelstvo;
int god_izdaniya;
};
struct kniga *ptr;

однако ничего... ошибка:
Access violation at address 32658812 in module 'CC3260MT.DLL'. Write jf address 0000004 (ошибка при нажатии на клавишу exe-шника)

Добавлено:
кстати такой вопрос... глупым наверное покажется. вот создал я на форме Edit и Button. 2 раза кликнул по батону и написал:
char s[20];
s=Edit1->Text;
почему он показывает ошибку. вроде типы похожи: массив символов char и строка Ansi?

а если напишешь:
AnsiString s;
s=Edit1->Text;
то ошибок не покажет...
Автор: TeXpert
Дата сообщения: 15.07.2007 17:17
BattleMage
Цитата:
struct kniga *ptr;
Ты объявил только указатель, а надо бы выделить память под это дело.

Добавлено:

Цитата:
ошибка при нажатии на клавишу exe-шника

Интересно). У файла есть клавиша).
Автор: BattleMage
Дата сообщения: 15.07.2007 22:12
TeXpert, СПАСИБО! думаю: вроде все правильно, вот только мелочь: память забыл выделить Постараюсь, таких ошибок не допускать

Добавлено:
А это снова я Очередной вопрос. Вот у меня есть структура. у неё 5 полей. как мне её содержимое записать в текстовый файл?

FILE *db;
db=fopen("DataBase.xxx","a+b");

Кстати какой лучше вариант открытия потока выбрать? Вообще мне не только записывать нужно, но и считывать... a+?
Автор: Qraizer
Дата сообщения: 16.07.2007 12:10
Ну надо же! Молчали-молчали, но вот три дня не было доступа на форум из-за падения маршрутизации где-то по дороге от провайдера до forum.ru-board.com, и как раз в эти три дня такая активность. Извиняюсь у авторов вопросов за несвоевременные ответы, но всё же не могу промолчать. Ибо вопросы не шуточные.
Cheery
У тебя инициализированная локальная переменная. Стандарт не определяет точное время её инициализации. Он только гарантирует, что она уже будет инициализирована на момент своего первого использования. Это сделано для предоставления возможности компилятору выполнять агрессивную оптимизацию. Например, если у тебя будет разветвлённая функция, и в одной из веток потока исполнения переменная ни разу не используется, то оптимизатор может умудриться в этой ветке не инициализировать и эту переменную, чтоб не тратить на это время. Точка останова в отладчике показывает, что в момент её срабатывания она ещё хранит мусор, а std::cout - что инициализация-таки прошла успешно. Вот и всё. Отладчик - он вправе нарушать некоторые предположения компилятора и оптимизатора.
Abs62
Antananarivu
Ты совершенно правильно не понимаешь, как это может работать. Я тоже не понимаю, как автору этого кода такое могло прийти на ум. За такой код нужно немедленно увольнять. Желательно, без выходного пособия, чтоб не повадно было.
Цитата:
Все равно не понимаю... какой массив? ... Что это вообще за форма записи (&x)[i-1]?
Abs62 тебе намекнул, и даже стандарт процитировал. Однако возьму смелость чуть прояснить. Операция & возвращает указатель. Неважно, является ли указатель результатом каких-нибудь вычислений, адресом переменной или именем массива - всё равно это указатель, т.е. тип данных, для которого определена операция индексирования, и при этом определена посредством других двух операций - операции сложения и разыменования: ptr[ptrdiff] есть *(ptr+ptrdiff), где ptr есть произвольный типизированный (т.е. не void) указатель на конкретные (т.е. не элементы класса) данные (т.е. не на функцию), а ptrdiff есть некое данное типа ptrdiff_t. И кстати, из-за возможности перемены мест слагаемых без изменения смысла действа не удивляйся, если вдруг увидишь где-нибудь вот такую запись: ptrdiff[ptr]. Так что в своём примере ты видишь самую обычную (просто чуть замаскированную) адресную арифметику.
Цитата:
Почему это работает?
Потому что повезло.
Цитата:
Расположение в памяти членов класса прописано в разделе 9.2 Стандарта C++: ...
Ага. Вот только если уж Вы, уважаемый ссылаетесь на стандарт, то по меньше мере не вырывайте статьи из контекста, а если ещё и цитируете, то будьте добры хотя бы читать, что цитируете. Вот, из Вашей же цитаты:
Цитата:
Implementation alignment requirements might cause two adjacent members not to be allocated immediately after each other; so might requirements for space for managing virtual functions (10.3) and virtual base classes (10.1).
Собственно к чему это я. Тот же стандарт чётко определяет область применения адресной арифметики - внутри диапазона статического или динамического массива, а также получение значения указателя (но не его разыменование c целью добраться до данных по этому адресу!) строго сразу за последним элементом массива. Всё. Во всех остальных случаях результат неопределён.
Автор: Zyava
Дата сообщения: 16.07.2007 13:08

Цитата:
BattleMage

У тебя половина членов структуры char[] половина AnsiString - странно как-то
Для AnsiString можно и просто присваивать строки, зачем strcpy?


Код: strcpy(ptr->nazvanie, Edit1->Text.c_str());
ptr->avtor, Edit2->Text;
ptr->zhanr = Edit3->Text;
ptr->izdatelstvo = Edit4->Text;
ptr->god_izdaniya=StrToInt(Edit5->Text);
Автор: BattleMage
Дата сообщения: 16.07.2007 14:14
Zyava, это я просто не оттуда скопировал. Они все char [20].

Это работает уже. Спасибо ещё раз. Теперь другая проблема. Как это все дело (структуру мою где 5 полей типа char [20]) записать в файл бинарный. Точнее записал, но вот не считывается...

Вот так записал:
db=fopen("DataBase.xxx","wb");
fwrite((char*)&ptr,sizeof(ptr),1,db);
fclose(db);

Вот так считываю. То что считал хочу записать в ячейки StringGrid-a:
db=fopen("DataBase.xxx","rb");
fread((char*)&ptr,sizeof(ptr),1,db);
while (fgetc(db)!=EOF)
{
StringGrid1->Cells[0][StringGrid1->RowCount]=IntToStr(StringGrid1->RowCount);
StringGrid1->Cells[1][StringGrid1->RowCount]=ptr->nazvanie;
StringGrid1->Cells[2][StringGrid1->RowCount]=ptr->avtor;
StringGrid1->Cells[3][StringGrid1->RowCount]=ptr->zhanr;
StringGrid1->Cells[4][StringGrid1->RowCount]=ptr->izdatelstvo;
StringGrid1->Cells[5][StringGrid1->RowCount]=ptr->god_izdaniya;
StringGrid1->RowCount++;
}
fclose(db);

И вообще у меня есть сомнения, что файл, в который я записал действительно бинарный. Когда я запускаю AkelPad - ом действительно бинарный файл (другой), то он показывает что "вы действительно решили его открыть", а вот при открытии DataBase.xxx не показывает... Неужели он текстовый?!
Автор: Antananarivu
Дата сообщения: 16.07.2007 16:01
Qraizer
Спасибо! Очень интересный комментарий, многое прояснил! Появляйтесь здесь почаще! ))
Еще вопрос появился..он довольно общий, если потребуется могу уточнить.
Есть некий класс, в классе определена функция член. Ее реализация выглядит так
T3DMatrix T3DMatrix::inv()
{
T3DMatrix res;
res = !(*this);
*this = res;
return res;
};
Это не суть важно, но ! - это перегруженный оператор и в данном случае он возвращает обратную матрицу. Так вот не поняв, зачем это тут все так наворочено я переписал функцию следующим образом:
T3DMatrix T3DMatrix::inv()
{
*this = !(*this);
return *this;
};
После этого вроде как ничего не изменилось, как работает так и работает. А теперь собственно вопрос: правильно ли я понимаю, что моя переделка функции в данном случае абсолютно корректна? Видимо предыдущий программист вводил res для того, чтобы сохранить сам объект содержащийся в *this, но то ли забыл, то ли еще чего и добавив строку *this = res; лишил всякого смысла ввод дополнительной переменной res. Или есть какое-то общее правило, что *this = !(*this) или там *this = -(*this) - это плохой стиль программирования чреватый потом ошибками? Заранее спасибо!
Автор: Abs62
Дата сообщения: 16.07.2007 16:09
Qraizer

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

Ага. То бишь при отсутствии виртуальных функций, виртуальных базрвых классов и выравнивании на 8 (или менее) байт этот грязный хак будет работать. Будь расположение членов класса совсем неопределено, возникла бы масса проблем с записью/чтением в/из файл(а) тех же заголовочных структур.
Автор: Qraizer
Дата сообщения: 16.07.2007 21:15
Antananarivu
Для общего случая тут нельзя сказать, как более правильно, ибо когда речь идёт о перегруженных операторах, нельзя говорить за вообще любые случаи. Всё зависит от того, как именно и что именно перегружается. В контексте, когда при перегрузке интуитивный смысл операторов не меняется, можно сказать, что обе формы - и оригинальная, и твоя изменённая - эквивалентны.
Однако у меня будут возражения по самой форме реализации этой функциональности. Как-то не принято реализовывать методы класса путём заюзывания в них перегруженных операторов. Поясню. Перегруженный оператор ! возвращает значение. Скорее всего его прототип выглядит как T3DMatrix operator!(const T3DMatrix&);. Или я не прав? Если нет, тогда это серьёзная ошибка проектирования. Далее, раз так, то этот оператор не обязан быть даже методом класса, ибо не меняет его внутренного состояния, а конструирует новый экземпляр. Раз так, то реализация оператора присваивания, который обязан быть методом класса и при этом полагается на неметод класса, выглядит просто странно. Обычно делают наоборот - делают методы класса, которые выполняют нужные действия, а перегруженные операторы реализуют с использованием этих методов. Но это всё не настолько критично, чтобы сказать, что это неправильно. Кривое проектирование - да. Но ошибочным оно-таки не является.
К слову сказать, могу перечислить проблемы проектирования T3DVector-а:
public: T x,y,z; - открытые данные; тут без комментариев.
T3DVector(int); - на кой понадобился этот конструктор - совершенно непонятно.
int get_dim() const - то же самое. Интересно поглядеть на более общий TxDVector , если он у автора вообще получится; я в этом сильно сомневаюсь, если судить по интерфейсу T3DVector
template <class in> T3DVector(const T3DVector<in>&); - если автор считал, что этот шаблонный контруктор сойдёт за конструктор копии, то он неправ - не сойдёт. Как результат, компилятор попытается сгенерить тривиальный копирующий конструктор, если он ему понадобится.
template <class in> T3DVector<T>& operator =(const T3DVector<in>&) - тоже самое. Это не тот же оператор присваивания, который будет заюзан при присваивании одного экземпляра другому. Снова компилятор будет пытаться генерировать тривиальный оператор присваивания. Более того, этот шаблонный перегруженный оператор небезопасен по отношению к пользовательским исключениям.
Непонятно откуда взялась ::norm2(). Я её прототипа не увидел.
T3DVector<T>& operator +=(const T3DVector<T>&) и иже с ним - также небезопасны к исключениям.
assert(a != T()); внутри T3DVector<T>& operator /=(const T3DVector<T>&) - совершенно лишняя строка, даже вредная.
void write(std::ostream&)const и void read(std::istream&) - а я предпочитаю использовать UNICODEовые потоки. И что мне теперь делать? Кроме того, они спроектированы с нарушениями рекомендаций по разработке подобных методов. А read() - так вообще неправильно написан.
__STL_TEMPLATE_NULL struct __type_traits<T3DFVector> и иже с ними - врут.
template <class T> std::istream& operator >> (std::istream&, T3DVector<T>&) - неверен. Даже новички такие ошибки редко допускают.
template <class T> inline const T3DVector<T> operator /(const T3DVector<T> a,const T) и иже с ним - константный параметр по значению... гм... я логику не осилил. assert() внутри - аналогично уже сказанному.
template <class T> inline const bool operator == (const T3DVector<T>&,const T3DVector<T>&) - навязывает оператору сравнения самому разбираться с неточностью представления данных с плавающей точкой.
В общем, я бы поостерёгся пользоваться этим классом.
Abs62
В общем да. Но не совсем. Если быть совсем уж точным, то там говорится, что не гарантируется отсутствие незанятого пространства между элементами. Т.е. между x1, x2 и/или x3 могут быть пустоты. Для массивов же отсутствие пустот как раз гарантируется (это утверждение именно в этой цитате отсутствует, но присутствует в соответствующем разделе стандарта).
Автор: Abs62
Дата сообщения: 16.07.2007 22:06
Qraizer

Цитата:
Если быть совсем уж точным, то там говорится, что не гарантируется отсутствие незанятого пространства между элементами. Т.е. между x1, x2 и/или x3 могут быть пустоты.

Там говорится и то, при каких именно условиях не гарантируется отсутствие пустот. В прочих случаях расположение полей в классе чётко определено. Иначе все апишные функции, получающие параметром указатель на структуру (а в WinAPI таких немало) просто не могли бы работать корректно. Такие вещи не могут быть unspecified.
Автор: BattleMage
Дата сообщения: 17.07.2007 00:19
Эгегей... меня кто-нибудь слышит? сообщение от 15:14 16-07-2007

Страницы: 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193

Предыдущая тема: не знаю как назвать тему :-)


Форум Ru-Board.club — поднят 15-09-2016 числа. Цель - сохранить наследие старого Ru-Board, истории становления российского интернета. Сделано для людей.