Форум программистов, компьютерный форум, киберфорум
Наши страницы
С++ для начинающих
Войти
Регистрация
Восстановить пароль
 
dwa83
0 / 0 / 0
Регистрация: 14.06.2013
Сообщений: 15
#1

не пойму из-за чего Access violation - C++

24.06.2013, 03:31. Просмотров 584. Ответов 12
Метки нет (Все метки)

При запуске проги происходит Access violation. Причём ранее проект был написан в bcb6, затем ради эксперимента(и возможного переезда) перенесён в vc++ 6. И там, и здесь всё работало в норме. При переезде обратно на борланда опять же всё компилится, но происходит access violation при new. Понять не могу почему.

C++
1
2
3
4
5
6
7
// выделение памяти под полигоны
void Mesh::CreatePolygons(int count)
{
  this->p_count=count;
  this->DelPolygons();
  this->polygon= new Polygon3d[count];  // здесь происходит ошибка
}
до этого в основном модуле происходит объявление

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
StaticModel model;      // статичная модель
 
StaticModel представляет собой
struct StaticModel
{
  float rotx;
  float roty;
  float rotz;
 
  unsigned short m_count;       // количество сеток
  Mesh *mesh;                   // массив сеток
  TextureLibrary *texlib;       // указатель на библиотеку текстур
  Shader *shader;
  Vector3f work;
 
  void CreateMeshes(int count); // выделение памяти для отдельных сеток модели
  unsigned int FindChunk(ifstream& ifs, unsigned short id, bool isParent=true);
  bool Load3DS(char *p_filename);
  void Render();
};
CreatePolygons вызывается из

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
bool StaticModel::Load3DS(char *p_filename)
{
    int p;
 
    FILE *file = fopen(p_filename, "rb");         
    if (file==NULL) 
    {
      MsgLog(p_filename);   
      MsgLog("Файл модели не найден");
      return false; 
    }   
    
    unsigned short mcount;
 
    fread(&mcount,1,2,file);  // считали количество сеток
    CreateMeshes(mcount);       // создаём массив сеток
    for (int i=0; i<mcount; i++)
    {
      bool smooth;
      unsigned short vc,tc,pc;
 
      fread(&smooth,1,1,file);  // считаем сглаживание
      fread(&vc,1,2,file);  // считаем количество вершин
      mesh[i].CreateVertices(vc); // создаём массив вершин
      fread(&tc,1,2,file);  // считываем количество текстурных координат
      mesh[i].CreateTexcoords(tc);// создаём массив текстурных координат
      fread(&pc,1,2,file);  // считываем количество полигонов
      mesh[i].CreatePolygons(pc); // <- создаём массив полигонов ->> переходя отсюда и происходит ошибка
 
      // считываем все вершины
      for (int v=0; v<vc; v++)
      {
        fread(&mesh[i].vertex[v].x,1,4,file);
        fread(&mesh[i].vertex[v].z,1,4,file);
        fread(&mesh[i].vertex[v].y,1,4,file);
        mesh[i].vertex[v].z=-mesh[i].vertex[v].z;
      }
 
      // считываем все текстурные координаты
      for (int t=0; t<tc; t++)
      {
        fread(&mesh[i].texcoord[t].x,1,4,file);
        fread(&mesh[i].texcoord[t].y,1,4,file);
      }
 
      // считываем все номера вершин в полигонах
      for (p=0; p<pc; p++)
      {
        fread(&mesh[i].polygon[p].nom_vertex[0],1,2,file);
        fread(&mesh[i].polygon[p].nom_vertex[1],1,2,file);
        fread(&mesh[i].polygon[p].nom_vertex[2],1,2,file);
      }
 
      // считываем все номера текстурных координат для полигонов
      for (p=0; p<pc; p++)
      {
        fread(&mesh[i].polygon[p].nom_texcoord[0],1,2,file);
        fread(&mesh[i].polygon[p].nom_texcoord[1],1,2,file);
        fread(&mesh[i].polygon[p].nom_texcoord[2],1,2,file);
      }
 
      for (p=0; p<pc; p++)
      {
        // расчёт тангент-оси
        Vector3f p1 = mesh[i].vertex[mesh[i].polygon[p].nom_vertex[0]];
        Vector3f p2 = mesh[i].vertex[mesh[i].polygon[p].nom_vertex[1]];
        Vector3f p3 = mesh[i].vertex[mesh[i].polygon[p].nom_vertex[2]];
 
        Texcoord t1 = mesh[i].texcoord[mesh[i].polygon[p].nom_texcoord[0]];
        Texcoord t2 = mesh[i].texcoord[mesh[i].polygon[p].nom_texcoord[1]];
        Texcoord t3 = mesh[i].texcoord[mesh[i].polygon[p].nom_texcoord[2]];
 
        mesh[i].polygon[p].tangent=((t3.y-t1.y)*(p2-p1)-(t2.y-t1.y)*(p3-p1))/((t2.x-t1.x)*(t3.y-t1.y)-(t3.x-t1.x)*(t2.y-t1.y));
 
        mesh[i].polygon[p].tangent.normalise();
      }
 
      // имя файла текстуры
      char tname[255]={0};
      int cnt=0;
      do
      {
        fread(&tname[cnt],1,1,file);
        cnt++;
      }
      while (tname[cnt-1]!=0);
 
      // загрузка текстуры и карты нормалей
      mesh[i].texID=texlib->Load(tname);
      char nm_name[255] = {0};
      strcat(nm_name, "nm_");
      strcat(nm_name, tname);
      mesh[i].normmapID=texlib->Load(nm_name);
      
      // расчёт нормалей
      if (smooth)
      mesh[i].CalculateSmoothNormals();
      else
      mesh[i].CalculateNormals();
      
    }
 
    fclose(file);
    return true;
}
Не пойму что не так.. Если вручную count заменить на 1 или 20, то проходит нормально, но при следующем new в другой функции опять ошибка доступа..
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
24.06.2013, 03:31
Я подобрал для вас темы с готовыми решениями и ответами на вопрос не пойму из-за чего Access violation (C++):

Не пойму чего хочет компилятор
Вот значит перепечатал буква в букву с книги Страуструпа такой код в main() ....

Ошибка в коде.не пойму из-за чего
Задача была таковой. Проанализировать массив данных с 15 элеметов.Элементами...

Access violation
Помогите пожалуйста. Не могу разобраться. Нашел в каком месте ругается. Но не...

access violation at address
Дорогие форумчане, столкнулся с проблемой, читаю бинарный файл по структуре : ...

Ошибка Access Violation
Собственно, проблемма: Есть класс, в котором есть переменные (3 шт): class...

Crash (access violation)
Задача: http://acm.timus.ru/problem.aspx?space=1&amp;num=1313 p.s. ссылку лучше...

12
alsav22
5438 / 4833 / 831
Регистрация: 04.06.2011
Сообщений: 13,587
24.06.2013, 14:47 #2
DelPolygons() как реализован? Если удалять ещё нечего?

Добавлено через 3 минуты
Причина ошибки может и не в этом, но, при чтении из файла (да и в других случаях), размер типа данных (unsigned short) лучше задавать через sizeof(), а не вручную.
1
dwa83
0 / 0 / 0
Регистрация: 14.06.2013
Сообщений: 15
24.06.2013, 16:05  [ТС] #3
Цитата Сообщение от alsav22 Посмотреть сообщение
DelPolygons() как реализован? Если удалять ещё нечего?
Удаление происходит так, вроде всё правильно, ошибка получается именно при new
Код
// удаление полигонов
void Mesh::DelPolygons()
{
  if (this->polygon!=NULL) delete []this->polygon; // удалим если уже выделено
  this->polygon=NULL;
}
0
alsav22
5438 / 4833 / 831
Регистрация: 04.06.2011
Сообщений: 13,587
24.06.2013, 16:15 #4
В отладчике смотрели?
C++
1
this->polygon= new Polygon3d[count];
count здесь нормальный?
0
dwa83
0 / 0 / 0
Регистрация: 14.06.2013
Сообщений: 15
24.06.2013, 16:45  [ТС] #5
Вроде нормальный. Ставил точку останова - count = 576 (полигонов). Пробовал вручную указывать значения, если указывать маленькие типа 20-50, то выделяется, иначе access violation. Да и если проходит, то уже в другом модуле в строчке
TextureElement *newtex = new TextureElement; //
опять такая же ерунда

Добавлено через 14 минут
Вот на всякий случай весь модуль, может кто разберётся и подскажет в чём ошибка. Странно, что раньше всё работало нормально..
Кликните здесь для просмотра всего текста
h
Код
#include "Shaders.h"
#include "Textures/TextureLibrary.h"

// полигон
struct Polygon3d
{
  unsigned short nom_vertex[3];     // номера вершин
  unsigned short nom_texcoord[3];   // номера текстурных координат
  Vector3f normal[3];               // нормали
  Vector3f tangent;
};

// элемент модели
struct Mesh
{
  unsigned int texID;           // идентификатор текстуры меша
  unsigned int normmapID;       // id карты нормалей
  bool SmoothNormal;            // сглаженные ли нормали
  unsigned short v_count;       // количество вершин
  unsigned short p_count;       // количество полигонов
  unsigned short t_count;       // количество текстурных координат
  unsigned short n_count;       // количество нормалей
  Vector3f *vertex;  // динамический массив вершин
  Vector3f *normal;  // динамический массив нормалей
  Texcoord *texcoord;// массив текстурных координат
  Polygon3d *polygon;// динамический массив полигонов

  void CalculateNormals();
  void CalculateSmoothNormals();

  void CreateVertices(int count);  // выделение памяти для вершин
  void CreateTexcoords(int count); // выделение памяти для текстурных координат
  void CreateNormals(int count);   // выделение памяти для нормалей
  void CreatePolygons(int count);  // выделение памяти для полигонов

  void DelVertices();
  void DelTexcoords();
  void DelNormals();
  void DelPolygons();
};

struct StaticModel
{
  float rotx;
  float roty;
  float rotz;

  unsigned short m_count;       // количество сеток
  Mesh *mesh;                   // массив сеток
  TextureLibrary *texlib;       // указатель на библиотеку текстур
  Shader *shader;
  Vector3f work;

  void CreateMeshes(int count); // выделение памяти для отдельных обьектов модели
  unsigned int FindChunk(ifstream& ifs, unsigned short id, bool isParent=true);
  bool Load3DS(char *p_filename);
  void Render();
};

Кликните здесь для просмотра всего текста
cpp
Код
#include <windows.h>
#include <GL\gl.h>
#include <GL\glu.h>
#include <fstream.h>

#include "Math3d.h"
#include "Model3d.h"
#include "ErrorLog.h"

// удаление вершин
void Mesh::DelVertices()
{
  if (this->vertex!=NULL) delete []this->vertex; // удалим если уже выделено
  this->vertex=NULL;
}

// удаление текстурных координат
void Mesh::DelTexcoords()
{
  if (this->texcoord!=NULL) delete []this->texcoord; // удалим если уже выделено
  this->texcoord=NULL;
}

// удаление нормалей
void Mesh::DelNormals()
{
  if (this->normal!=NULL) delete []this->normal; // удалим если уже выделено
  this->normal=NULL;
}

// удаление полигонов
void Mesh::DelPolygons()
{
  if (this->polygon!=NULL) delete []this->polygon; // удалим если уже выделено
  this->polygon=NULL;
}

// выделение памяти под массив вершин
void Mesh::CreateVertices(int count)
{
  this->v_count=count;
  this->DelVertices();
  this->vertex= new Vector3f[count];
}

// выделение памяти под массив текстурных координат
void Mesh::CreateTexcoords(int count)
{
  this->t_count=count;
  this->DelTexcoords();
  this->texcoord= new Texcoord[count];
}

// выделение памяти под массив текстурных координат
void Mesh::CreateNormals(int count)
{
  this->n_count=count;
  this->DelNormals();
  this->normal= new Vector3f[count];
}

// выделение памяти под массив полигонов
void Mesh::CreatePolygons(int count)
{
  this->p_count=count;
  this->DelPolygons();
  this->polygon= new Polygon3d[count];
}


// расчёт нормалей
void Mesh::CalculateNormals()
{
  for (int i=0; i<p_count; i++)
  {
    Vector3f a=vertex[polygon[i].nom_vertex[0]]-vertex[polygon[i].nom_vertex[1]];
    Vector3f b=vertex[polygon[i].nom_vertex[0]]-vertex[polygon[i].nom_vertex[2]];
    Vector3f norm=cross(a,b);
    norm.normalise();
    polygon[i].normal[0]=norm;
    polygon[i].normal[1]=norm;
    polygon[i].normal[2]=norm;
  }
}

// расчёт сглаженных нормалей
void Mesh::CalculateSmoothNormals()
{
  int p;

  CalculateNormals();

  Vector3f *nrm=new Vector3f[p_count]; // временный массив нормалей полигона
  for (p=0; p<p_count; p++)
  nrm[p]=polygon[p].normal[0];

  for (int i=0; i<v_count; i++)
  {
    Vector3f vnorm;
    for (p=0; p<p_count; p++)
    {
      // если вершина входит в полигон..
      if ((polygon[p].nom_vertex[0]==i)||
          (polygon[p].nom_vertex[1]==i)||
          (polygon[p].nom_vertex[2]==i))
      vnorm+=nrm[p]; // прибавляем нормаль полигона
    }
    vnorm.normalise(); // нормализуем

    // проставим нормаль во всех полигонах, использующих эту вершину
    for (p=0; p<p_count; p++)
    {
      if (polygon[p].nom_vertex[0]==i) polygon[p].normal[0]=vnorm;
      if (polygon[p].nom_vertex[1]==i) polygon[p].normal[1]=vnorm;
      if (polygon[p].nom_vertex[2]==i) polygon[p].normal[2]=vnorm;
    }
  }

  delete []nrm;
}


// выделение памяти под массив сеток
void StaticModel::CreateMeshes(int count)
{
  this->m_count=count;
  if (this->mesh!=NULL) // если массив сеток создан
  {
    for (int i=0; i<m_count; i++)
    {
      this->mesh[i].DelNormals(); //удалим нормали
      this->mesh[i].DelVertices(); //удалим вершины
      this->mesh[i].DelTexcoords(); //удалим текстурные коорды
      this->mesh[i].DelPolygons(); //удалим полигоны
    }
    delete []this->mesh;
  }
  this->mesh= new Mesh[count];

  for (int i=0; i<m_count; i++)
  {
    this->mesh[i].vertex=NULL;
    this->mesh[i].normal=NULL;
    this->mesh[i].texcoord=NULL;
    this->mesh[i].polygon=NULL;
  }
}





bool StaticModel::Load3DS(char *p_filename)
{
    int p;

	FILE *file = fopen(p_filename, "rb");         
	if (file==NULL) 
	{
	  MsgLog(p_filename);	
      MsgLog("Файл модели не найден");
	  return false;	
	}	
	
    unsigned short mcount;

	fread(&mcount,1,2,file);  // считали количество сеток
    CreateMeshes(mcount);       // создаём массив сеток
    for (int i=0; i<mcount; i++)
    {
      bool smooth;
      unsigned short vc,tc,pc;

      fread(&smooth,1,1,file);  // считаем сглаживание
      fread(&vc,1,2,file);  // считаем количество вершин
      mesh[i].CreateVertices(vc); // создаём массив вершин
      fread(&tc,1,2,file);  // считаем количество текстурных координат
      mesh[i].CreateTexcoords(tc);// создаём массив текстурных координат
      fread(&pc,1,2,file);  // считаем количество полигонов
      mesh[i].CreatePolygons(pc); // создаём массив полигонов

      // считаем все вершины
      for (int v=0; v<vc; v++)
      {
        fread(&mesh[i].vertex[v].x,1,4,file);
	    fread(&mesh[i].vertex[v].z,1,4,file);
	    fread(&mesh[i].vertex[v].y,1,4,file);
        mesh[i].vertex[v].z=-mesh[i].vertex[v].z;
	  }

      // считаем все текстурные координаты
      for (int t=0; t<tc; t++)
      {
        fread(&mesh[i].texcoord[t].x,1,4,file);
	    fread(&mesh[i].texcoord[t].y,1,4,file);
	  }

      // считаем все номера вершин в полигонах
      for (p=0; p<pc; p++)
      {
        fread(&mesh[i].polygon[p].nom_vertex[0],1,2,file);
	    fread(&mesh[i].polygon[p].nom_vertex[1],1,2,file);
	    fread(&mesh[i].polygon[p].nom_vertex[2],1,2,file);
      }

      // считаем все номера текстурных координат для полигонов
      for (p=0; p<pc; p++)
      {
        fread(&mesh[i].polygon[p].nom_texcoord[0],1,2,file);
	    fread(&mesh[i].polygon[p].nom_texcoord[1],1,2,file);
	    fread(&mesh[i].polygon[p].nom_texcoord[2],1,2,file);
      }

      for (p=0; p<pc; p++)
      {
        // расчёт тангент-оси
        Vector3f p1 = mesh[i].vertex[mesh[i].polygon[p].nom_vertex[0]];
        Vector3f p2 = mesh[i].vertex[mesh[i].polygon[p].nom_vertex[1]];
        Vector3f p3 = mesh[i].vertex[mesh[i].polygon[p].nom_vertex[2]];

        Texcoord t1 = mesh[i].texcoord[mesh[i].polygon[p].nom_texcoord[0]];
        Texcoord t2 = mesh[i].texcoord[mesh[i].polygon[p].nom_texcoord[1]];
        Texcoord t3 = mesh[i].texcoord[mesh[i].polygon[p].nom_texcoord[2]];

        mesh[i].polygon[p].tangent=((t3.y-t1.y)*(p2-p1)-(t2.y-t1.y)*(p3-p1))/((t2.x-t1.x)*(t3.y-t1.y)-(t3.x-t1.x)*(t2.y-t1.y));

        mesh[i].polygon[p].tangent.normalise();
      }

      // имя файла текстуры
      char tname[255]={0};
      int cnt=0;
      do
      {
        fread(&tname[cnt],1,1,file);
        cnt++;
      }
      while (tname[cnt-1]!=0);

      // загрузка текстуры и карты нормалей
      mesh[i].texID=texlib->Load(tname);
	  char nm_name[255] = {0};
      strcat(nm_name, "nm_");
      strcat(nm_name, tname);
      mesh[i].normmapID=texlib->Load(nm_name);
      
      // расчёт нормалей
      if (smooth)
      mesh[i].CalculateSmoothNormals();
      else
      mesh[i].CalculateNormals();
      
	}

	fclose(file);
    return true;
}

void StaticModel::Render()
{

  for (int m=0; m<m_count; m++)
  {
    shader->SetTexture(0,mesh[m].texID,"TextureSampler");
    shader->SetTexture(1,mesh[m].normmapID,"NormalSampler");

    glBegin(GL_TRIANGLES);
    for (int p=0; p<mesh[m].p_count; p++)
    {
      // передадим в шейдер значения осей
      GLuint uni = shader->GetUniformLocation("Tangent");
      shader->setUniformf(uni, mesh[m].polygon[p].tangent.x, mesh[m].polygon[p].tangent.y, mesh[m].polygon[p].tangent.z);


      for (int v=0; v<3; v++)
      {

        glNormal3f(mesh[m].polygon[p].normal[v].x,
                   mesh[m].polygon[p].normal[v].y,
                   mesh[m].polygon[p].normal[v].z);
        glTexCoord2f(mesh[m].texcoord[mesh[m].polygon[p].nom_texcoord[v]].x,
                     mesh[m].texcoord[mesh[m].polygon[p].nom_texcoord[v]].y);
        glVertex3f(mesh[m].vertex[mesh[m].polygon[p].nom_vertex[v]].x,
                   mesh[m].vertex[mesh[m].polygon[p].nom_vertex[v]].y,
                   mesh[m].vertex[mesh[m].polygon[p].nom_vertex[v]].z);

      }
    }
    glEnd();
  }



}
0
alsav22
5438 / 4833 / 831
Регистрация: 04.06.2011
Сообщений: 13,587
24.06.2013, 17:37 #6
Удалил.
0
dwa83
0 / 0 / 0
Регистрация: 14.06.2013
Сообщений: 15
26.06.2013, 09:54  [ТС] #7
Вобщем всё странным образом заработало после скачки с бубном. Скорее всего действительно файл неправильно считывался, и некоторые массивы создавались как new[0], потому ошибка доступа была. Теперь интересно почему например fread(&с, 1, 100, file); работает не так, как fread(&с, 100, 1, file); Ведь в первом случае 100 раз считывает по 1 байту, а во втором 1 раз пачку в сто байт? И ещё такой вопрос, чем пользоваться "правильнее", FILE или fstream и почему?
0
Tulosba
:)
Эксперт С++
4746 / 3240 / 496
Регистрация: 19.02.2013
Сообщений: 9,046
26.06.2013, 10:18 #8
Цитата Сообщение от dwa83 Посмотреть сообщение
Теперь интересно почему например fread(&с, 1, 100, file); работает не так, как fread(&с, 100, 1, file)
А в чем проявляется "не так"?
Цитата Сообщение от dwa83 Посмотреть сообщение
чем пользоваться "правильнее", FILE или fstream и почему?
FILE - это c-style, fstream - с++
0
dwa83
0 / 0 / 0
Регистрация: 14.06.2013
Сообщений: 15
26.06.2013, 10:22  [ТС] #9
Цитата Сообщение от Tulosba Посмотреть сообщение
А в чем проявляется "не так"?
Не правильно считывалось, поменял местами размер считываемого блока и количество блоков - всё стало считываться правильно(именно то количество байт, которое нужно), странности какие-то.

То-есть принципиальной разницы, как я понял, нету, и можно и FILE и fstream.
0
Tulosba
:)
Эксперт С++
4746 / 3240 / 496
Регистрация: 19.02.2013
Сообщений: 9,046
26.06.2013, 10:56 #10
Цитата Сообщение от dwa83 Посмотреть сообщение
странности какие-то
а код возврата fread() проверяли и в том и в другом случаях?
Цитата Сообщение от dwa83 Посмотреть сообщение
и можно и FILE и fstream.
Можно. Но следует придерживаться единого стиля. И я бы рекомендовал fstream (надеюсь не нужно объяснять преимущества ООП подхода перед процедурным).
0
dwa83
0 / 0 / 0
Регистрация: 14.06.2013
Сообщений: 15
26.06.2013, 11:24  [ТС] #11
Цитата Сообщение от Tulosba Посмотреть сообщение
а код возврата fread() проверяли и в том и в другом случаях?
Не проверял, понадеялся зря на безошибочность. Думаю стоит добавить проверку правильности считывания.
А вообще почему первый вариант может вернуть ошибку?(тогда как второй по сути такой же, но считывает без ошибки)
0
Tulosba
:)
Эксперт С++
4746 / 3240 / 496
Регистрация: 19.02.2013
Сообщений: 9,046
26.06.2013, 11:35 #12
Цитата Сообщение от dwa83 Посмотреть сообщение
А вообще почему первый вариант может вернуть ошибку?
С ходу не скажу. Надо смотреть конкретный код.
0
alsav22
5438 / 4833 / 831
Регистрация: 04.06.2011
Сообщений: 13,587
26.06.2013, 11:37 #13
Цитата Сообщение от dwa83 Посмотреть сообщение
А вообще почему первый вариант может вернуть ошибку?(тогда как второй по сути такой же, но считывает без ошибки)
Вы сначала проверку сделайте, всё может и не так оказаться.
0
26.06.2013, 11:37
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
26.06.2013, 11:37
Привет! Вот еще темы с решениями:

Access violation writing location
#include &lt;iostream&gt; using namespace std; template &lt; typename t &gt; void...

access violation reading location
access violation reading location такая проблема если вести информацию про...

Access violation writing exeption
Добрый день! Почему такой код вызывает Access violation writing exeption ?...

почему выдает access violation?
подскажите плиз изза чего доступ ограничивает, и как сделать чтоб я мог каждому...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
13
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru