Воскресенье, 06 Октября 2024, 23:30

Приветствую Вас Гость

[ Новые сообщения · Игроделы · Правила · Поиск ]
Результаты поиска
nilremДата: Четверг, 14 Января 2010, 16:16 | Сообщение # 481 | Тема: Нужна помощь в создании игры. Crystal of Surius.
Просветленный разум
Сейчас нет на сайте
Отличная графика! Красивая, яркая.
Мне бы такую для игр на кпк.

Если тебе не надоест учить гм, то получится хорошая(как минимум в плане графики) игра.


Windmill 2

WindMill 2D Game Engine
nilremДата: Четверг, 14 Января 2010, 23:35 | Сообщение # 482 | Тема: Текстуры на заказ
Просветленный разум
Сейчас нет на сайте
ЖiR@F, некрофил.

Windmill 2

WindMill 2D Game Engine
nilremДата: Пятница, 15 Января 2010, 23:05 | Сообщение # 483 | Тема: Предложения по улучшению
Просветленный разум
Сейчас нет на сайте
Файлообменники генерируют ссылку для конкретного пользователя под конкретный ip. Так что просьба невыполнимая.

Windmill 2

WindMill 2D Game Engine
nilremДата: Суббота, 16 Января 2010, 15:51 | Сообщение # 484 | Тема: Как делать игры на с++, превратись из новичка в профи
Просветленный разум
Сейчас нет на сайте
Vinchensoo,

Quote (Vinchensoo)
От BOOM: Подробная книга о DX9, необходимы знания C++ скачать книгу

это и есть Горнаков - DirectX 9 уроки программирования на C++


Windmill 2

WindMill 2D Game Engine
nilremДата: Суббота, 16 Января 2010, 17:49 | Сообщение # 485 | Тема: Как делать игры на с++, превратись из новичка в профи
Просветленный разум
Сейчас нет на сайте
Quote (Naigelgog)
На мой вопрос так никто и не ответил.

karuy ответил, и я с ним согласен. Для новичка книга подходящая.


Windmill 2

WindMill 2D Game Engine
nilremДата: Суббота, 23 Января 2010, 12:57 | Сообщение # 486 | Тема: Предлагаю услуги сценариста
Просветленный разум
Сейчас нет на сайте
Почитал Le Grand Secret. Поначалу хотел написать рецензию, но поленился.
Поэтому просто вставил комментарии в текст.
В приложении первая глава с моими комментариями.
И воспринимай их не как критику, а как совет.
Прикрепления: LGS1g.rar (10.0 Kb)


Windmill 2

WindMill 2D Game Engine
nilremДата: Суббота, 23 Января 2010, 13:12 | Сообщение # 487 | Тема: Конкурс на GcUp.ru #4
Просветленный разум
Сейчас нет на сайте
Quote (TovTripleZ)
Вопрос конечно глупый, но... разве был третий конкурс?

Конкурс "Средневековый дом" - http://www.gcup.ru/forum/16-1377-1

За оффтоп в теме – бан. Не забывайте, данный раздел жестко модерируется.

Так что... отдыхай 7 дней.


Windmill 2

WindMill 2D Game Engine
nilremДата: Суббота, 23 Января 2010, 14:52 | Сообщение # 488 | Тема: Вопрос-Ответ - мини вопросы по созданию игр
Просветленный разум
Сейчас нет на сайте
vc, используй указатели.
http://www.rsdn.ru/article/cpp/fastdelegate.xml


Windmill 2

WindMill 2D Game Engine
nilremДата: Суббота, 23 Января 2010, 16:32 | Сообщение # 489 | Тема: Курс : "Основы С++ для начинающих программистов игр."
Просветленный разум
Сейчас нет на сайте
Урок 2. Область видимости имен

Тема, которую мы рассмотрим на этом уроке, касается не только функций, но и переменных. Поэтому для упрощения буду дальше говорить в основном о них.
Область видимости, это часть программы в которой можно использовать указанную переменную. Бывает она всего двух видов: глобальная и локальная.
Глобальная область это весь наш файл с исходным кодом. Локальная же область, это область, принадлежащая определенному блоку кода, например функции. Локальные области могут быть вложенными друг в друга. Вне своей области локальная переменная невидима, то есть ее нельзя использовать, тогда как глобальная переменная может использоваться в любой объявленной в ней локальной. Локальная область видимости ограничивается фигурными скобками.
Давайте рассмотрим простой пример.

Code

int i;

void main()
{
  i=20;
}

void func()
{
  i = 321;
}


Это весь код, никаких инклюдов, ничего.

Переменная i, объявленная вне главной функции main(), является глобальной. Она видима и внутри main и внутри вообще любой другой функции, например func.
Запомните, глобальная область предназначена только для объявлений или определений. Никакие другие действия в ней не работают. Если вы захотите выполнить, например, присваивание:

Code

int i;

i=123; // ошибка
void main()
{
  i=20;
}


то компилятор укажет на ошибку. Он решит, что вы пытаетесь заново объявить переменную i, да еще и неправильно, забыв указать тип. Если нужно задать глобальной переменной начальное значение, то делается это сразу при объявлении вот так:
Code

int i=123; // все ОК
void main()
{
  i=20;
}

Теперь слегка изменим пример:
Code

void func();

void main()
{
  int s;
  s = 10; // все ОК
}

void func()
{
  s = 321; // ошибка
}

Здесь внутри функции main объявлена переменная с, внутри самой функции с ней можно делать все что угодно. Но попытка использовать ее в функции func вызовет ошибку, поскольку func не принадлежит к области видимости функции main.
Казалось бы, чисто теоретически, можно было бы сделать вот так.
Code

void func();

void main()
{
  int s;
  s = 10; // все ОК
  void func()
  {
   s = 321;
  }
}

Но, не судьба. Запомните, объявлять и писать реализацию функции можно только в глобальной области. Поэтому попытка проделать такое вызовет ошибку.
Следующий пример:
Code

int s;

void main()
{
  s = 10; // все ОК
  while()
  {
   s = 321; // тоже все ОК
   int w;  
   w = 128; // все ОК
  }
  w = 512; // А вот здесь ошибка!
}

Что и где доступно, видно из комментариев. Здесь у цикла есть собственная область видимости. Создать такую область можно, просто выделив что-то фигурными скобками.
Code

int s;

void main()
{
  s = 10; // все ОК
  {
   s = 321; // тоже все ОК
   int w;  
   w = 128; // все ОК
  }
  w = 512; // А вот здесь ошибка!
}

Здесь тот же пример но без цикла, тем не менее области видимости сохранились. Ключевое значение имеют только фигурные скобки. Но поскольку по синтаксису наличие таких скобок в цикле обязательно, то можно смело говорить что циклы имеют собственную локальную область видимости.

Ранее, описывая требования для имен переменных, я говорил, что имя должно быть уникальным. Теперь я хочу это правило дополнить. Имя должно быть уникальным в пределах одной области видимости.

То есть:

Code

void func();

void main()
{
  int s;
}

void func()
{
  int s;
}

Не вызовет никаких проблем. Переменная s является для каждой из функций локальной, посему в другой области она невидима и такая запись не приводит к возникновению ошибки.
Хорошо, теперь вот такой пример:
Code

int s;
  void func();

void main()
{
  int s;
  s = 10;
}

void func()
{
  s = 50;
}

Здесь переменная s объявлена также и в глобальной области. Казалось бы, она должна быть видимой и внутри других функций и подобная запись должна приводить к ошибке. Но нет!
Ранее озвученное правило продолжает действовать. Просто если имя объявлено в глобальной области, то везде используется оно, но если в локальной области объявлена переменная с аналогичным именем, то используется локальная.
Поэтому в приведенном выше примере

Присваивание s = 10; никак не затрагивает s глобальную. Тогда как в функции func присваивание производится как раз глобальной переменной. Так что можно даже сказать, что это две разные переменные. И следующая программа это продемонстрирует:

Code

#include <iostream>
using namespace std;

int s;
void func();

void main()
{
  setlocale(0,"");
  int s=30;
  cout<<"Локальная s ="<<s;
  func();
  cin.get();
}

void func()
{
  s = 10;
  cout<<"\nГлобальная s ="<<s;
}

Результат ее работы наглядно иллюстрирует, что изменение локальной переменной никак не влияет на ее глобального тезку.
Отлично. Все это хорошо. А вот что тогда делать, если нам зачем-то нужно обратится к этой самой глобальной одноименной переменной.
Для этого есть специальный оператор - ::. С его помощью можно запросто обратится к глобальной области. Как им пользоваться проиллюстрировано в примере ниже:

Code

#include <iostream>
using namespace std;

int s=10;

void main()
{
  setlocale(0,"");
  int s=30;
  cout << "Локальная s =" << s;
  cout << "\nГлобальная s =" << ::s; // Вот здесь вот оно, это двойное двоеточие
  cin.get();
}


Все, если вы внимательно читали и рассматривали примеры, то должны все понять. Теперь можно вернутся к функциям, и поговорить о том, зачем же нужно их объявление.
Допустим где то в программе, глубоко в областях видимости, хотя это и не важно, у нас есть две функции, использующие для работы друг друга:
Code

void a()
{
  b();
}
...
void b()
{
  a();
}

Если объявления нет, то как же первая функция узнает о существовании второй?
Вот такой вариант не пройдет:
Code

void b()
{
  a();
}
...
void a()
{
  b();
}
...
void b()
{
  a();
}

Компилятор не допустит существования двух функций с одинаковыми именами. Да и не эффективно это, ведь функция может содержать несколько сотен строк кода. Поэтому, дабы избежать подобных недоразумений, и используется предварительное объявление:
Code

void b();

void a()
{
  b();
}
...
void b()
{
  a();
}

Проблемы области видимости.

А теперь поговорим о некоторых проблемах для локальных областей видимости. Есть у них один недостаток. Объявленная внутри локальной области переменная существует до тех пор, пока эта область активна. Рассмотрим следующий пример:

Code

int* func()
{
  int* pi;
  int i=55;
  pi = &i;
  return pi;
}

void main()
{
  int* pС;
  pС = func();

}

Сейчас нам необходимо вспомнить об указателях. Функции способны работать с ними так же, как и с любым другим типом данных. В приведенном примере func()
возвращает указатель на переменную i. Вот только сама переменная, по завершении работы функции, перестает существовать. В результате наш указатель указывает на все, что угодно, то есть по старому адресу, только не на существовавшую ранее переменную, а ее значение (55) окажется потерянным.
Хуже всего то, что компилятор никак не сможет помочь вам избежать таких вот ситуаций. Тут уж все в руках программиста.

На этом с видимостью завязываем, и вновь возвращаемся непосредственно к функциям. Ведь узнать нам придется еще очень много.


Windmill 2

WindMill 2D Game Engine
nilremДата: Суббота, 23 Января 2010, 16:47 | Сообщение # 490 | Тема: Курс : "Основы С++ для начинающих программистов игр."
Просветленный разум
Сейчас нет на сайте
Урок 3. Обширный функционал


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

Перегрузка функций


Идя по свежим следам, вновь вернемся к именам. Именам функций.
Имя, которое используем мы и имя, которым функция представлена в программе, различны. В отличии от нас, программа также учитывает количество и тип аргументов а также тип возвращаемого значения. Все это вместе называют полным именем функции, ее сигнатурой.
Пример:
Code

int func();
char func();  // ошибка
int func(int);
int func(char);
char func(int,int);
char func(int,float);

Все это разные функции.
Возможность создавать функции с одинаковыми именами называется перегрузкой функций.
И обратите внимание на вторую строку, возле которой приписано "ошибка". От первой она отличается возвращаемым значением. Но на этапе компиляции компилятор не сможет предугадать, какой тип данных будет возвращен, и какую же из перегруженных функций нужно использовать. Поэтому такая перегрузка недопустима и порождает ошибку.
Может возникнуть вопрос, зачем же эта перегрузка нужна. Зачем сознательно вносить такую путаницу в программу. Оказывается для того, чтобы эти самые программы упростить. Понять это поможет следующий пример:
Code

int sum(int a, int b)
{
   return a+b;
}
float sum(float a, float b)
{
   return a+b;
}

void main()
{
   cout<<sum(10,20);
   cout<<sum(10.5,20.7);
}

Здесь мы видим перегруженную функцию sum(). Альтернатива это создать функции с разными именами и все время мучится, вызывая правильную для конкретного типа данных. А так компилятор сам подберет нужную, сравнив передаваемые ей типы.

Необходимо отметить, что указанный выше пример работать в Microsoft Visual Studio 2008 не будет. Компиляция завершится следующей ошибкой:

error C2668: sum: неоднозначный вызов перегруженной функции

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

cout<<sum(10.5f,20.7f);


или так:
Code

cout<<sum((float)10.5,(float)20.7);


Значение аргументов по умолчанию.


И еще немного об именах.
В С++ есть возможность присваивать используемым в функциях аргументам значение по умолчанию. Делается это очень просто. Достаточно выполнить присваивание в момент объявления функции:
Code

int func(int i=50);


Здесь аргументу, представленному переменной int i, по умолчанию присвоено 50. Оно будет использоваться, если при вызове не передавать функции никакого значения.
Пример:
Code

#include <iostream>
using namespace std;

void func(int i=50);    // обьявление с заданием аргумента по умолчанию

void main()
{
   func();    // первый вызов
   func(111);    // второй вызов
   cin.get();
}

void func(int i)
{
   cout<<i<<"\n";
}

Здесь при первом вызове функции не передается никакое значение, поэтому используется значение по умолчанию. При втором вызове используется 111.

Конечно же у функции может быть больше одного аргумента.
Code

void func(int arg1, int arg2, int arg3);


Присвоить значение по умолчанию аргументу arg2, можно только в том случае, если значение по умолчанию уже есть у arg3.
Так делать нельзя:
Code

void func(int arg1, int arg2 = 125, int arg3);

Можно только так:
Code

void func(int arg1, int arg2 = 125, int arg3 = 0);

Если объявление функции не используется, то аргументы по умолчанию задаются в ее реализации:
Code

#include <iostream>
using namespace std;

void func(int i=50)    //  задание аргумента по умолчанию
{
   cout<<i<<"\n";
}

void main()
{
   func();    // первый вызов
   func(111);    // второй вызов
   cin.get();
}


Встраиваемые функции


Использование функций имеет один маленький недостаток. На вызов функции тратится некоторое время. Происходит это потому, что под код функции резервируется отдельное место в памяти. По ходу выполнения программы, при вызове функции программе приходится переходить к этому месту, а затем возвращаться обратно. Естественно что этот переход не происходит мгновенно, и хорошо если она вызывается всего раз, а вот если 100, значит и переходов будет столько же, и потраченного времени в сто раз больше.
Получается что получить большую скорость работы программы можно, вписывая код функции в место вызова. Это еще бы было нормально, если бы функция вызывалась всего пару раз, а вот если опять сотню. Это ж получится такой объем кода, что сам черт в нем не разберется.
Чтобы обойти все эти проблемы, можно использовать оператор inline.
Синтаксис следующий:
Code

inline Тип_возвращаемого_значения  имя_функции(список агрументов);

Пример:
Code

inline int sum();

Этот оператор заставляет компилятор встраивать код функции в место ее вызова. Как говорится, и волки сыты и овцы целы, то есть и код небольшой и легко читаем, и программа работает быстро.
Но все же есть одно но. Если такая функция вызывается 100 раз, то при компиляцию в программу будет вставлено 100 ее экземпляров. За увеличение скорости придется заплатить увеличением программного кода и занимаем местом в памяти. В результате никакого выигрыша может и не быть. Поэтому нужно руководствоваться следующим правилом: Если функция содержит всего две-три строки кода, то ее можно, и даже нужно, делать встраиваемой. Если же функция большая, да к тому же используется много раз, то делать ее встраиваемой нельзя.

Статические переменные.


Допустим, что нам зачем-то нужно посчитать, сколько раз конкретная функция вызывалась в программе. Первый пришедший на ум способ сделать это – создать отдельную глобальную переменную и в коде функции увеличивать ее на единицу.
Вот так:
Code

#include <iostream>
using namespace std;

int r=0;    // глобальная переменная-счетчик

inline int sum(int a, int b)
{
   r++;    //использование глобальной переменной
   return a+b;
}

void main()
{
   for(int i =0;i<50;i++)
   {
    sum(10,20);
   }
   cout<<r;    // результат подсчета
   cin.get();
}

Есть у подобного способа один недостаток. Допустим, вы скопировали вашу функцию в другую программу, или вообще дали своему другу. А в этой другой программе, ну или у друга, нет специально объявленной глобальной переменной. Программа работать не будет и хорошо, если вы вспомните почему.
Естественно, способ решить подобную проблему есть. Это оператор - static.
Объявив с его помощью переменную внутри функции
Code

int sum(int a, int b)
{
   static int r=0;    // статическая переменная-счетчик
   r++;   
   return a+b;
}

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

Рекурсивные функции


Может быть то, что я сейчас скажу, покажется вам бредом, но знайте, функция способна вызывать сама себя.
Code

int func()
{
func();
}

Называется эта возможность рекурсией. Рекурсия может быть прямая и косвенная.
Прямая – когда функция вызывает сама себя, косвенная – когда функция вызывает другую функцию, которая в свою очередь вызывает первую. Кстати, это уже знакомая ситуация:
Code

void b();

void a()
{
   b();
}
...
void b()
{
   a();
}


Применяется рекурсия в разных случаях, когда например нужно выполнить ее для какого то значения, а затем эта же функция применяется к полученному результату.
Для рекурсивных функций является обязательным наличие условия, способного прекратить рекурсию.
Небольшое откровение. Я не люблю рекурсию, особенно прямую. Нет такой ситуации, когда бы без нее нельзя было обойтись. К тому же множественный вызов функций, передача аргументов расходуют дополнительное время и память. Но все же есть одно преимущество - использование рекурсии позволяет сделать код более компактным.
Специально приводить пример рекурсии я не буду.


Windmill 2

WindMill 2D Game Engine
nilremДата: Суббота, 23 Января 2010, 17:18 | Сообщение # 491 | Тема: Курс : "Основы С++ для начинающих программистов игр."
Просветленный разум
Сейчас нет на сайте
Урок 4. Функции и указатели.


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

Массивы и указатели.

Я уже раньше намекал, что имя массива является также и константным указателем на массив, а также на первый его элемент. Убедится в этом можно из следующего примера:
Code

#include <iostream>
using namespace std;

void main()
{
    int array[10];
    cout<<'\n'<< array;  // отображение адреса массива
    cout<<'\n'<<&array [0];    // отображение адреса первого элемента
    cin.get();
}


Оба напечатанных адреса будут идентичными.
Напомню, что для отображения адреса первого элемента использовался оператор взятия адреса &, ведь первый элемент это число, а не указатель.
Что же нам это дает? Да ничего особенного, если не знать, что к указателям также можно применять операторы инкременты и декременты. При этом адрес изменяется не на единицу, как обычно, а на размер переменной в байтах.
В результате доступ к элементам массива можно выполнять еще одним способом. Его вы видите в примере:
Code

#include <iostream>
using namespace std;

void main()
{
    int a[10];
    for(int i=0;i<10;i++)
    {
     a[i]=i;
     cout<<a[i]<<' ';
    }
    for(int i=0;i<10;i++)
    {
     cout<<*(a++)<<' ';
    }
    cin.get();
}


Вот только работать этот пример не будет. Ведь а это константный указатель, то есть изменить его нельзя. Чтобы пример заработал необходимо создать указатель обычный и передать ему адрес из константного:
Code

#include <iostream>
using namespace std;

void main()
{
    int a[10];
    for(int i=0;i<10;i++)
    {
     a[i]=i;
     cout<<a[i]<<' ';
    }
    cout<<'\n';
    int *pa=a;
    for(int i=0;i<10;i++)
    {
     cout<<*(pa++)<<' ';
    }
    cin.get();
}

Опять напомню что в записи *(pa++) звездочка это оператор разыменования указателя, с помощью которого получаем хранящееся по адресу значение. Скобки здесь используются, чтобы не запутаться с приоритетами операторов.
При доступе к элементам массива с использованием указателя и инкременты(декременты) остерегайтесь выхода за пределы массива.
Code

#include <iostream>
using namespace std;

void main()
{
    int a[10];
    for(int i=0;i<10;i++)
    {
     a[i]=i;
     cout<<a[i]<<' ';
    }
    cout<<'\n';
    int *pa=a;
    for(int i=0;i<11;i++)
    {
     cout<<*(pa++)<<' ';
    }
    cin.get();
}

В этом примере происходит доступ к несуществующему 11 элементу(с индексом 10, ведь как вы помните отсчет начинается с 0). В результате программа выдает нам какое-то, непонятно откуда взявшееся число.

Динамическое распределение памяти.


А сейчас настало время познакомится с одним из самых распространенных способов использования указателей.
Когда ваша программа начинает свою работу, операционная система выделяет для нее место в памяти. Называется это место стек. Размер стека не безграничный, поэтому иногда возникает проблема, когда ваши данные, например большой массив, в него попросту не помещаются. Эта проблема получила название – переполнение стека, и приводит к краху работы программы.
Обидно получается. В компьютере вон сколько памяти, а попытка создать парумегабайтный массивчик делает программу неработоспособной. Но выход есть.
Ко всей этой неиспользуемой, находящейся за пределами стека памяти, можно получить доступ. Память эта, кстати, называется динамической(точнее динамически распределяемой), то есть непостоянной, в противовес постоянному стеку.
Для того, чтобы разместить данные в динамической памяти используется указатель и специальный оператор - new.
Работает он очень просто. По запросу программы он резервирует где-то в динамической памяти свободный кусочек, и возвращает его адрес.

Синтаксис оператора следующий:
Code

указатель  =  new  тип_данных;

Пример:
Code

int *pi = new int;

согласно этой записи оператор new выделит в области динамического распределения некий, соответствующий размеру типа данных, объем памяти, и передаст указателю pi его адрес. Как мы помним, размер целочисленного типа данных 4 байта, столько и будет выделено.
В дальнейшем доступ к этой памяти производится через указатель.
Code

#include <iostream>
using namespace std;

void main()
{
    int *pi = new int;
    *pi=10;
    cout<<*pi;
    cin.get();
}


Ключевой особенностью использования динамически распределенной памяти является ее независимость от области видимости. Будучи созданной один раз она доступна везде, куда можно передать ее адрес:
Code

#include <iostream>
using namespace std;

int* func()
{
    int* pa=new int;    // динамическое выделение памяти
    *pa=123123;
    return pa; // возврат адреса
}

void main()
{
    int* pi;
    pi=func(); // получение адреса на распределенную память
    cout<<*pi;
    cin.get();
}

Здесь функция func() возвращает адрес на динамически выделенную память. Теоретически после завершения работы функции все созданные в ней переменные должны быть утрачены. Но это не относится к динамическому распределению памяти. Что и подтверждает строчка cout<<*pi;, печатающая ранее присвоенное в функции и никуда не подевавшееся корректное значение.
Динамическое распределение памяти настолько мощное средство, что даже по завершению программы выделенная в ней память остается недоступной для других программ.(Было это во времена ДОСа и первых Windows, сейчас же операционные системы работают с памятью более грамотно). Так вот, если все время выделять память, рано или поздно она кончится. Поэтому когда память под переменную становится не нужной, ее нужно освободить. Для этих целей используется оператор delete.

Синтаксис следующий:
Code

delete указатель;

здесь указатель – это указатель на динамически-распределенную область памяти.
Пример:
Code

#include <iostream>
using namespace std;

int* func()
{
    int* pa=new int;    
    *pa=123123;
    delete pa;  // освобождение ранее выделенной памяти.
    return pa;    
}

void main()
{
    int* pi;
    pi=func();    
    cout<<*pi;
    cin.get();
}

Теперь все отлично, память мы освободили. Вот только программа стала неработоспособной. Ведь освободив память мы уничтожили хранящееся там значение.
Как же тогда быть. Ведь если не использовать delete внутри функции, по ее завершении указатель прекратит свое существование, а значит и освободить память будет невозможно. А вот и нет. При использовании delete это не обязательно должен быть тот самый указатель, но это обязательно должен быть тот самый адрес.

Code

#include <iostream>
using namespace std;

int* func()
{
    int* pa=new int;    
    *pa=123123;
    return pa;    
}

void main()
{
    int* pi;
    pi=func();    
    cout<<*pi;
    delete pi; // освобождение ранее выделенной памяти.
    cout<<*pi;
    cin.get();
}


Предупреждаю сразу – это был плохой пример. Посмотрите его и забудьте. Если где-то в функции выделяется память, то она в этой функции и должна освобождаться. Лучше по новому выделить в main память и передать туда значение, а не разбрасываться вот так вот памятью, а то в конце концов можно окончательно запутаться, и превратить свой код в кучу мусора. Тем не менее таким способом пользуются довольно часто, особо отмечая, что потом память нужно освобождать, например создавая для этого специальные функции и указывая в документации, что их вызов по окончании работы обязателен.

Иногда программист забывает где-то освободить память, и если этот код выполняется неоднократно, можно выделить довольно много памяти в никуда. Такую ситуацию называю утечкой памяти, и это одна из довольно распространенных ошибок, которые в будущем попортят вам нервы.

С выделением памяти под обычные переменные разобрались, теперь рассмотрим как это делается с массивами.
Code

указатель  =  new  тип_данных[размер массива];

В принципе разница небольшая. Необходимо всего лишь указать после типа данных размер массива. Для того чтобы освободить выделенную таким образом память используется следующая запись.
Code

delete [] указатель;    

здесь квадратные скобки указывают, что удаляется именно массив. Указывать размер при этом не нужно.

Что то мой разговор об указателях затягивается, пора возвращаться к функциям.

Параметры-адреса


Давайте рассмотрим такой простой пример:
Code

#include <iostream>
using namespace std;

void print(int a)
{
    a = 32;
    cout<<a<<'\n';
}

void main()
{
    int i=10;
    print(i);
    cout<<i<<'\n';
    cin.get();
}


Здесь у нас есть функция print, которой передается переменная i. Внутри функции этой переменной присваивается новое значение. Но потом, после функции оказывается что значение переменной i осталось неизменным. То есть изменить значение переменной, которая передавалась функции как аргумент, нельзя.
Так происходит потому, что функции на самом деле передается не оригинальная переменная, а всего лишь хранящееся в ней значение. Поэтому такой способ передачи называют передачей по значению. Любые манипуляции с этим значением внутри функции оригинальную переменную не затрагивают.
Получается, что бы не делала функция результат ее работы за пределы функции не выйдет. В таком случае зачем они вообще нужны. Ах, да. Функция же может возвращать значение. Вот только всего одно. А если нам нужно больше?
Тут на помощь опять приходят указатели. Функция работает с указателями так же, как и с обычными переменными, то есть передает их значение. А что у нас хранится в указателе? Правильно, адрес ячейки памяти, в которой хранится некое значение. А значит мы можем в полной мере воздействовать на это значение. Это проиллюстрировано следующим примером:
Code

#include <iostream>
using namespace std;

void print(int* a)
{
    *a = 32;
    cout<<*a<<'\n';
}

void main()
{
    int i=10;
    int *pi = &i;
    print(pi);
    cout<<i<<'\n';
    cin.get();
}

Здесь в функции объявляется переменная i, которой присваивается число 10. Затем эта переменная передается функции print. Причем передается не сама переменная, а указатель на нее, как того требует прототип функции:
Code

void print(int* a);

аргументом функции является указатель, то есть попросту говоря адрес. Внутри функции с помощью оператора разыменования * по адресу присваивается новое значение. По завершении работы функции оказывается, что теперь значение переменной i изменилось, и равно тому, что было присвоено в функции. То есть нам удалось изменить значение переданной функции переменной. Что и требовалось. Вот такие вот полезные указатели. Такой способ передачи аргументов называется передачей по указателю.
Добавлю, что запись
Code

int *pi = &i;
    print(pi);

можно сократить так:
Code

    print(&i);

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

Кроме передачи по значению и передачи по указателю есть еще и третий способ, называемый передача аргументов по ссылке.
Он не требует от программиста непосредственной работы с указателями, хотя тоже работает с адресами переменных. Но вся эта работа скрыта от программиста.
Вот предыдущий пример, измененный так, чтобы продемонстрировать передачу по ссылке.
Code

#include <iostream>
using namespace std;

void print(int& a)
{
    a = 32;
    cout<<a<<'\n';
}

void main()
{
    int i=10;

    print(i);
    cout<<i<<'\n';
    cin.get();
}

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

void print(int& a)


int& a означает что будет производится передача по ссылке(можно сказать что переменная а это новый тип данных, который называется ссылка, и является синонимом адреса). В коде примера нет ни одного указателя. Но функция print(i)получает не значение переменной, а ее адрес, и записывает 32 по этому адресу. То есть результат тот же, что и при использовании указателей.
По-моему, намного проще.


Windmill 2

WindMill 2D Game Engine
nilremДата: Суббота, 23 Января 2010, 17:23 | Сообщение # 492 | Тема: Язык программирования D
Просветленный разум
Сейчас нет на сайте
vc, таким названием и оформлением темы ты нарываешься на бан.

Windmill 2

WindMill 2D Game Engine
nilremДата: Суббота, 23 Января 2010, 17:24 | Сообщение # 493 | Тема: Бан лог
Просветленный разум
Сейчас нет на сайте
TovTripleZ, бан 7 дней за оффтоп в теме про 4 конкурс.

Windmill 2

WindMill 2D Game Engine
nilremДата: Суббота, 23 Января 2010, 17:37 | Сообщение # 494 | Тема: Курс : "Основы С++ для начинающих программистов игр."
Просветленный разум
Сейчас нет на сайте
Для обсуждения, вопросов и замечаний создана отдельная тема.

http://gcup.ru/forum/7-1739-1



Windmill 2

WindMill 2D Game Engine
nilremДата: Воскресенье, 24 Января 2010, 20:22 | Сообщение # 495 | Тема: Вопрос опытным программистам
Просветленный разум
Сейчас нет на сайте
При создании массива объектов всегда используется конструктор по умолчанию(без параметров, или все параметры имеют значение по умолчанию).

Без вариантов.

То есть, то о чем мечтает Apati, невозможно.

Я в таких случаях использую тот способ что и el_r


Windmill 2

WindMill 2D Game Engine
nilremДата: Понедельник, 25 Января 2010, 15:11 | Сообщение # 496 | Тема: Как создать свой движок
Просветленный разум
Сейчас нет на сайте
Kelloway забыл случай №3 - повышение навыков программирования.

Windmill 2

WindMill 2D Game Engine
nilremДата: Суббота, 30 Января 2010, 09:21 | Сообщение # 497 | Тема: Visual C++ 2008 Express Edition
Просветленный разум
Сейчас нет на сайте
Quote (BetMora)
error spawning rc.exe,

IDE не может найти компилятор ресурсов (resource compiler).
Причины могут быть следующие:
1. Неправильные пути в настройках студии.
Нажимаем Сервис-Параметры-Проекты и решения-Каталоги VC++. В пункте Показать каталоги для: выбираем Исполняемые файлы. В списке должна присутствовать строка

$(WindowsSdkDir)\bin

2. В системе не установлена, или установлена несовместимая версия Windows Sdk.
Обычно Sdk лежат здесь

C:\Program Files\Microsoft SDKs\Windows\

Удали Visual C++, и установи заново. Вероятно что при прошлой установке Windows Sdk не установился, или установился не корректно.

3. Windows Vista или 7

Ищи совместимую версию.


Windmill 2

WindMill 2D Game Engine
nilremДата: Суббота, 30 Января 2010, 09:31 | Сообщение # 498 | Тема: компоновщик
Просветленный разум
Сейчас нет на сайте
Quote (Pesets)
Эм, по-моему в любом IDE, который компилирует в машинный код (и Visual C++ в том числе), есть свой линкер...

Таки да. И называется эта штука обычно link.exe.


Windmill 2

WindMill 2D Game Engine
nilremДата: Суббота, 30 Января 2010, 14:14 | Сообщение # 499 | Тема: Вопрос-Ответ - мини вопросы по созданию игр
Просветленный разум
Сейчас нет на сайте
vc,
Это вообще какой язык?

Если С++ то:

Если обьект класса обявлен как обычно, до доступ производится с помощью точки:

Code
elfs.anyfunctions();

если же объект объявлен как указатель то с помощью стрелки:

Code
elfs->anyfunctions();

или же "разыменовав" указатель *, с помощью точки:

Code
(*elfs).anyfunctions();

скобки обязательны, поскольку приоритет у точки выше чем у *.

зы: Еще один подобный сверхнубский вопрос и получишь бан. То, что ты спросил, описано в каждой книжке по с++.


Windmill 2

WindMill 2D Game Engine
nilremДата: Суббота, 30 Января 2010, 19:20 | Сообщение # 500 | Тема: Обзор игровых журналов
Просветленный разум
Сейчас нет на сайте
Играм посвящено много журналов. В этой теме мне бы хотелось сделать их небольшой обзор.
Начну с тех, что ближе мне, то есть с Украинских.

Самый первый, и самый старший из таких журналов - "Мой компьютер игровой". Абревиатура - МиК
Первый его номер появился в далеком 1997, Стабильно издается с 2000 года. С тех пор журнал каждые две недели доносил до пользователей игровые новости. Информацию, обзоры и рецензии на новые, только что вышедшие или находящиеся в разработке игры.
К сожалению, в 2009 году, в связи с экономическим кризисом, журнал прикрыли.
За все время вышло 315 номеров
Сайт - http://www.mikportal.org
а также Игроград, http://www.igrograd.ua


gameplay
Еще один украинский игровой журнал. Если МиК был больше похож на газету (качеством бумаги, часто выходил), то Гейплей внешне это уже солидный глянцевый журнал. Первые его номера появились в 2005 году и большинство статей были переводом британского журнала games.
Журнал всегда оперативно публикует рецензии на новинки, освещает разрабатываемы игры. Также в журнале всегда присутствуют мировые рейтинги игр и обзоры с различных игровых конференций. Помимо прочего есть статьи про новейшее игровое железо.
Вместе с журналом идет восьмигиговый диск, содержащий множество видеороликов, демо и бесплатных игр а также последние версии драйверов на всевозможное оборудование.
За все время вышло 52 номера.
Сайт - http://www.gameplay.com.ua


Шпиль
Опять таки украинский глянцевый игровой журнал. Один из старейших игровых журналов, выходил с 2001 года, и также не выдержав кризиса, был закрыт в марте 2009 года. Журнал быстро купил другой издатель, и уже в июне вышел следующий номер.
Что интересно, за год выходит 18 номеров журнала - 12 обычных и 6 спецвыпусков. Правда последнее время Шпиль дизайном и наполнением все больше смахивает на gameplay.
В комплектацию журнала входит пятигиговый диск. До 2007 года был cd.
За все время вышло 94 номера.
Сайт - http://www.shpil.com/


Игромания
Крупнейший российский игровой журнал. Издается с 1997 года. Самый «жирный» среди журналов.
208 страниц, правда 20 из них обычно отдано под рекламу, но поскольку это реклама игр, компьютеров, комплектующих, то в таком обьеме особо и не заметно.
Журнал охватывает все возможные игровые тематики. Кроме того наличествуют обзоры различного софта и компьютерного железа. В журнале принято оценивать по 10-бальной системе каждую описываемую игру, чтобы читатель сразу видел что и чего стоит.
Журнал комплектуется двусторонним плакатом, наклейками и двумя двуслойными DVD, один из которых содержит только видео (трейлеры, видеоновости, видеообзоры, репортажи собственного производства), второй — демоверсии, моды, дистрибутивы онлайн игр, патчи, софт, флэш-игры, коды, сохранения, трейнеры, обои, утилиты для вскрытия и редактирования игр и много чего еще.
За все время вышло 149 номеров.
Обьем – 208-256 страниц
С середины 2009 года появилась еще одна версия журнала - Игромания Лайт. В нем всего 128 страниц и один диск, зато выходит каждые две недели.
Сайт - http://www.igromania.ru


Гейм.ЕХЕ
Очень древний журнал, первый номер увидел свет в 1995 году! Назывался он тогда Магазин Игрушек.
Последний, к сожалению, в 2006. Выходил журнал ежемесячно. Объем – 144 страницы.
Журнал имел ярко выраженный элитарный, эстетский, интеллектуальный характер. Даже само название намекало на наличие ума у читателей. Не всем было дано понять что значит .ЕХЕ. Тематика стандартная для таких журналов, но вот информация преподносилась как материалы критического, аналитического, художественного и т. п. характера, и была ориентирована не на детей, а больше на «взрослых» детей. Что в конце концов журнал и погубило.
Объем – 144 страницы.
За все время вышло 133 номера.
Сайт - http://www.game-exe.ru/


Лучшие компьютерные игры
Ежемесячный журнал, посвященный игровой индустрии. Основное внимание в нем уделяется подробному разбору и разносторонней оценке новых, свежевышедших, игр. Большое внимание уделяется руководствам по играм, описанию прохождений, советам по эффективной игре. В журнале печатаются статьи по игровой аналитике, а также познавательные материалы по околоигровым темам вроде «оружие в играх», «исторические сюжеты в играх» и тому подобных.
Журнал комплектуется двумя дисками, один из которых является своего рода «Видеожурналом» - чем то вроде самостоятельной ежемесячной видеопрограммы, состоящей из роликов игр, так и репортажей с разработчиками или игроками. В видеожурнале можно увидеть программу новостей игровой индустрии, пообщаться с интересными разработчиками в разных точках земного шара, посмотреть авторское видео непосредственно из игр.
Как по мне, журнал сплагиачен с Игромании. Так мне показалось на первый взгляд. Потом оказалось, что журнал в действительности является ее ответвлением. Игромания охватывает обширный набор тем, тогда как ЛКИ действительно концентрируется на лучших играх.
Издается с 2003 года.
Обьем – 184 страницы.
За все время вышло 99 номеров.
Сайт - http://www.lki.ru/


Страна Игр
Еще один старейший игровой журнал, издается с 1996 года.
В журнале публикуются рецензии, аналитические материалы, новости игровой индустрии, интервью с разработчиками, репортажи с российских и зарубежных выставок и фестивалей, авторские колонки экспертов. Существует также отдельная рубрика «Банзай!» об аниме, манге и японской поп-культуре в целом.
В отличие от других игровых изданий, «Страна Игр» не является гидом покупателя, не предоставляет информацию о взломе игр или создании модификаций для них, не советы по прохождению, не описывает все выходящие на российском рынке релизы. Журнал делает акцент на аналитических статьях об играх и индустрии, репортажах с выставок, интервью, авторских колонках экспертов, материалах на общепознавательные темы (кино, литература, кросс-форматные культурные явления). Уникальной для российских и зарубежных игровых изданий является обширная рубрика об аниме.
Комплектуется двумя ДВД.
Обьем – 192 страницы.
За все время вышло 299 номеров.
Сайт - http://www.gameland.ru/magazines/si/


Великий Dракон
Это не просто старейший журнал. Это патриарх.
Помните ли вы рекламу «Денди! Денди! Мы всё любим Денди! Денди — играют все!»
Так вот это журнал как раз тех времен.
Первый его номер появился в 1993 году, правда назывался тогда журнал «Видео-Асс Dendy». Об этой, популярной тогда приставке, ну и немного о других, он и писал. Кстати фирма Денди его тогда и финансировала.
В 1995 году был переименован в «Великий Dракон».
В 2004 году журнал прекратил свое существование, хотя интернетом до сих пор бродят слухи, что следующий, 66 номер, выйдет на днях(
Обьем – от 24 до 100 страниц.
За все время вышло 65 номеров.
Оффициального сайта нет. Неофициальный - http://www.greatdragon.ru
Архив журнала - http://gd-archive.ru


PC Gamer
Популярный международный журнал. Издается в Англии с 1993 года. В России с 2002.
Статьи и рецензии в журнале всегда адекватны и непредвзяты. Ели в других журналах можно встретить статьи написанные по заказу кого-нибудь из разработчиков, и восхваляющие игры, являющиеся на самом деле отстоем, то здесь мы узнаем только правду.
Из за этой позиции на журнал неоднократно подавались судебные иски.
Это сказал не я, это написано в интернете. Я русского PC Gamer-а в глаза не видел. А вот его английский вариант являлся и является самым крупным игровым журналом в мире.
Комплектуется одним ДВД с видеороликами, скриншотами и дополнениями, а также новыми телепрограммами «Икона видеоигр», «Inспектор Гаdжет» и «Подпольная правда».
С декабря 2008 года не выпускается.
Обьем – 128 страниц.
Сайт - http://www.pc-gamer.ru/


РС Игры
Журнал принадлежит тому же издательству, что и Страна игр. Издается с 2003 года. Первоначально был посвящен только играм для персонального компьютера, но последнее время в журнал начали попадать статьи и про консоли.
В комплектацию журнала входят три двуслойных ДВД диска.
Обьем – 192-240 страниц.
За все время вышло 74 номера.
Сайт - http://www.gameland.ru/magazines/pg/


Навигатор игрового мира
Издается с 1997 года.
Ключевой особенностью журнала является рубрикация по игровым жанрам. Цель журнала, помочь читателям сориентироваться во всем том многообразии игр, что выходят в последнее время.
В комплектацию журнала входят три двуслойных ДВД диска.
Обьем – 176 страниц.
За все время вышло 152 номера.
Сайт http://gamenavigator.ru/


Виртуальные Радости
Единственный белорусский журнал, даже не журнал а всего лишь газета, посвященный компьютерным играм. Жаль мне белорусов, но может это и к лучшему, а то в большинстве наших журналов что не плагиат то мусор. Они только и умеют, что пестреть отфотошопленными скриншотами. Журнала не видел, так что ничего сказать не могу.
Сайт http://www.nestor.minsk.by/vr/


Кого я забыл? Что читаете вы?


Windmill 2

WindMill 2D Game Engine
Поиск:

Все права сохранены. GcUp.ru © 2008-2024 Рейтинг