Отправляет email-рассылки с помощью сервиса Sendsay

Инвестирование с нуля

  Все выпуски  

Программирование на Си и С++ с нуля 142) Отладка


Школа программирования

142) Программирование на Си и С++ с нуля: Отладка

В прошлом выпуске я ошибся в форме описания многомерных массивов - конечно, массив с двумя и большим числом измерений объявляется не так: m[10,10] , а так: m[10][10] . То есть длина по каждому измерению берется в собственную пару квадратных скобок. Это я перепутал с Дельфи и C#, где длины через запятую вводятся. Правильно:

  int A[15][20];
  int M3D[5][2][100];

Письма.

Хотел бы обратить внимание читателей Вашей рассылки на интересные материалы, размещённые на сайте Beginа (www.prog-begin.net.ru), которые связаны с заданными вопросами.

какая функция позволяет проверять текущую дату

В своё время Лену её сосед попросил написать программу-напоминалку для учёта рабочих дней (у него был скользящий график). В процессе обсуждения родилась статья, как раз и посвящённая использованию функций даты-времени в Билдере. Найти её можно здесь:
http://www.prog-begin.net.ru/modules.php?name=News file=article sid=48
Исходники для Билдера к этой статье (программа часы-будильник-календарь) можно найти здесь:
http://www.prog-begin.net.ru/modules.php?name=Files go=view_file lid=9
На основе этой программы Лена сделала настоящий шедевр, он выложен в разделе "Дельфи", есть, по-моему, и экзешник.

Давно хотел спросить - на С++ создаються игры или есть языки предназначенные для создания игр?

Если говорить о кроссплатформенных играх, то очень часто приходится сталкиваться с необходимостью знания, помимо C/C++, интерпретируемого языка Lua, особенностью которого является "встраивание" в программы на Си и возможность вызова функций Lua из C-функций. На этом языке часто пишут конфигурационные скрипты и файлы локализации.
Если же говорить об играх для Windows, то, возможно, кого-то заинтересуют статьи о программировании с нуля космической аркады в среде Билдера:
http://www.prog-begin.net.ru/modules.php?name=News file=article sid=47
http://www.prog-begin.net.ru/modules.php?name=News file=article sid=49
На основе этих статей был "старыми" читателями Вашей рассылки создан проект "Космическая аркада", который вёлся параллельно в Билдере и Дельфи. Файлы проекта можно найти здесь:
http://www.prog-begin.net.ru/modules.php?name=Files go=cat cid=30
а обсуждение проекта на форуме здесь:
http://www.prog-begin.net.ru/modules.php?name=Forums file=viewforum f=22
Некоторые простейшие текстовые (консольные) игрушки также можно найти здесь:
http://www.prog-begin.net.ru/modules.php?name=Files go=showcat cid=14

Как изменить цвет конкретной строчки Memo1?

По определению свойства шрифта в классе TMemo едины для всех строк. Поэтому да, нужно воспользоваться компонентом RichEdit. Пример выделения цветом произвольных строк с использованием методов SelStart, SelLength и SelAttributes-Color этого компонента можно найти в другом проекте Бегина - "Редактор кода" - здесь:
http://www.prog-begin.net.ru/modules.php?name=Files go=cat cid=28
Обсуждение на форуме - здесь:
http://www.prog-begin.net.ru/modules.php?name=Forums file=viewforum f=23
Андрей Кузнецов aka Dr_Andrew

Ссылку на сайт Бегина я вынес в корешок рассылки. Если от меня долго нет ответа - обращайтесь туда!

Варианты ответов на задания.

  // декларация массива и переменных
  int x[100];
  int i, min, max, imin, imax;
  //---------------------------------------------------------------------------
  __fastcall TForm1::TForm1(TComponent* Owner)
          : TForm(Owner)
  {
  // очистка полей вывода
  Memo1->Clear();
  Memo2->Clear();
  Memo3->Clear();
  }
  //---------------------------------------------------------------------------

  void __fastcall TForm1::Button1Click(TObject *Sender)
  {
  /* заполнение массива случайными числами от 0 до 999, а так же
  вывод его в поле
  Memo1 в удобоувариваемом виде*/
  randomize();
  Memo1->Text = "";
  for (i = 0; i < 100; i++) {
    x[i] = random(1000);
    Memo1->Text = Memo1->Text + x[i] + " ";
    }
  }
  //---------------------------------------------------------------------------

  void __fastcall TForm1::Button2Click(TObject *Sender)
  {
  // нахождение минимального элемента массива и его индекса
  min = x[0];
  for ( i = 1; i < 100; i++ ) {
    if ( min > x[i] ) {
      min = x[i];
      imin = i;
      }
    }

  // нахождение максимального элемента массива и его индекса
  max = x[0];
  for ( i = 1; i < 100; i++ ) {
    if ( max < x[i] ) {
      max = x[i];
      imax = i;
      }
    }

  // вывод минимума и максимума, а также их индексов на экран
  Label1->Caption = "MIN = " + IntToStr(min);
  Label2->Caption = "iMIN = " + IntToStr(imin);
  Label3->Caption = "MAX = " + IntToStr(max);
  Label4->Caption = "iMAX = " + IntToStr(imax);
  }
  //---------------------------------------------------------------------------
  void __fastcall TForm1::Button3Click(TObject *Sender)
  {
  // замена минимального элемента массива на максимальный и
  наоборот
  int a;
  a = x[imin];
  x[imin] = x[imax];
  x[imax] = a;

  // вывод получившегося массива в Memo2
  Memo2->Text = "";
  for (i = 0; i < 100; i++)
  Memo2->Text = Memo2->Text + x[i] + " ";
  }
  //---------------------------------------------------------------------------

  void __fastcall TForm1::Button4Click(TObject *Sender)
  {
  // сортировка по возрастанию
  for (int n = 0; n < 100; n++) { // наверное, n может быть и меньше 100
    for ( i = 0; i < 99; i++ ) { // до i=98, т.к. (i+1)=99 - последний элемент
      if ( x[i] > x[i+1] ) {
  /* перемена местами элементов массива (i-ый меняется c (i+1)-ым )
  без
  использования промежуточной переменной */
        x[i] = x[i] + x[i+1];
        x[i+1] = x[i] - x[i+1];
        x[i] = x[i] - x[i+1];
        }
     }
  }

  // вывод отсортированного массива в Memo3
  Memo3->Text = "";
  for (i = 0; i < 100; i++)
  Memo3->Text = Memo3->Text + x[i] + " ";
  }
  //---------------------------------------------------------------------------
  void __fastcall TForm1::Button5Click(TObject *Sender)
  {
  // очистка Memo-в и Label-ей
  Memo1->Clear();
  Memo2->Clear();
  Memo3->Clear();
  Label1->Caption = "";
  Label2->Caption = "";
  Label3->Caption = "";
  Label4->Caption = "";
  }
  //---------------------------------------------------------------------------
    
  Артем.

Далее.

  1. Нахождение максимального и минимального значения массива.
  Основа – форма с двумя кнопками и двумя списками.
  Код программы:

  int a[100],c,f,i;

  AnsiString d;

  //---------------------------------------------------------------------------

  void __fastcall TForm1::FormCreate(TObject *Sender)

  {

  randomize();

  }

  //---------------------------------------------------------------------------

  void __fastcall TForm1::Button1Click(TObject *Sender)

  {

  ListBox1->Clear();

  for( i=0; i<100; i++)//Заполняем массив случайными значениями и
  выводим в
  список 1

  {

  f=random(100);

  a[i]=f;

  d=IntToStr(a[i]);

  ListBox1->Items->Add(d);

  }

  }

  //---------------------------------------------------------------------------

  void __fastcall TForm1::Button2Click(TObject *Sender)

  {

  f=a[0];

  for( i=0; i<100; i++)//Находим максимальное значение

  {

  if( f<a[i+1])f=a[i+1];

  }

  d=IntToStr(f);

  ListBox2->Items->Add("Max");

  ListBox2->Items->Add(d);//Выводим максимальное значение в список
  2

  ListBox2->Items->Add("Номер Max");

  for( i=0; i<100; i++)//Находим номера максимальных значений

  {

  if( a[i]==f)

  {

  d=IntToStr(i);

  ListBox2->Items->Add(d);//Выводим номера максимальных значений в
  список 2

  }}

  c=a[0];

  for( i=0; i<100; i++)//Находим минимальное значение

  {

  if( c>a[i+1])c=a[i+1];

  }

  d=IntToStr(c);

  ListBox2->Items->Add("Min");

  ListBox2->Items->Add(d);//Выводим минимальное значение в список 2

  ListBox2->Items->Add("Номер Min");

  for( i=0; i<100; i++)//Находим номера минимальных значений

  {

  if( a[i]==c)

  {

  d=IntToStr(i);

  ListBox2->Items->Add(d);//Выводим номера минимальных значений в
  список 2

  }}

  ListBox1->Clear();

  for( i=0; i<100; i++)//Меняем максимальные и минимальные значения

  {

  if( a[i]==f)a[i]=c;

  else

  {

  if( a[i]==c)a[i]=f;

  }

  d=IntToStr(a[i]);

  ListBox1->Items->Add(d);//Выводим новый массив в список 1

  }

  }

  2. Сортировка массива (по убыванию).
  Основа – форма с двумя кнопками и двумя списками.
  Код программы:

  int a[100],c,f,i;

  AnsiString d;

  void __fastcall TForm1::FormCreate(TObject *Sender)

  {

  randomize();

  }

  //---------------------------------------------------------------------------

  void __fastcall TForm1::Button1Click(TObject *Sender)

  {

  ListBox1->Clear();

  ListBox2->Clear();

  for( i=0; i<100; i++)//Заполняем массив случайными значениями и
  выводим в
  список 1

  {

  f=random(100);

  a[i]=f;

  d=IntToStr(a[i]);

  ListBox1->Items->Add(d);

  }

  }

  //---------------------------------------------------------------------------

  void __fastcall TForm1::Button2Click(TObject *Sender)

  {

  for( i=0; i<100; i++)//Сортируем массив по убыванию

  {

  if( a[i]<a[i+1])

  {

  f=a[i];

  a[i]=a[i+1];

  a[i+1]=f;

  for( c=i; c>0; c--)

  {

  if( a[c]>a[c-1])

  {

  f=a[c];

  a[c]=a[c-1];

  a[c-1]=f;

  }}}}

  for( i=0; i<100; i++)//Выводим отсортированный массив в список 2

  {

  d=IntToStr(a[i]);

  ListBox2->Items->Add(d);

  }}

  А теперь вопросы.

  1. Когда я попытался объявить двухмерную матрицу int c[20,10];
  программа
  выдала ошибку:
  [C++ Ошибка] Unit1.cpp(18): E2290 Гpaнuцы Maccuвa missing ]
  Что это означает и как эту ошибку устранить?
  При этом одномерная матрица объявляется нормально.

Это я неправильно написал про способ объявления многомерных массивов. Так надо:

int c[20][10];

2. В список данные добавляются командой Add(). А как программно добавлять данные в массив и как проверять наличие данных в массиве?

Массив - это не объект с методами, а фактически базовый, простой тип данных, просто расширенный механизмом индексации. Массивы создаются с фиксированным числом элементов, хотя есть и динамический способ:

   int *M; // массив М, но число элементов в нем пока неизвестно
   int n;
   n = 10; // число элементов в будущем массиве
   M = new int [n]; // создаем динамически массив, в котором будет n элементов
   M[2] = 5;
   ...
   delete[] M; // завершаем работу с массивом - явно его удаляем!

Но лучше всегда пользоваться статическими массивами - это эффективнее.

3. По боту Вы сказали, что базу данных праздников лучше организовать в файл. Но я попробовал сделать это через массив и в принципе достиг результата:

  AnsiString a[10],b;

  int i;

  ...

  b=Date();

  for( i=0; i<10; i++)

  {

  if( a[i].AnsiPos(b)>0)Label2->Caption="Поздравляю!";

  }

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

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

б) Как сократить получаемую функцией Date() дату до первых четырех цифр, то есть оставить только день и месяц, чтобы ее можно было сравнивать с ежегодными праздниками? Или есть функция, возвращающая только текущие день и месяц?

Честно говоря, я точно не помню, наверное какие-то есть, но можно так сделать - просто выделить в строке подстроку с нужными сведениями. Функция выделения подстроки (это метод типа AnsiString) записывается так: SubString( n, l ), где n - номер символа (с единицы) в строке, а l - длина извлекаемой строки. Например,
AnsiString s;
s = "12345";
Вызов s.SubString(2,3) вернет строку "234".

4. Хотелось бы уточнить вопрос насчет переноса в боте курсора в поле ввода при запуске программы.
Когда я вставил функцию SetFocus() в обработчик формы

  void __fastcall TForm1::FormCreate(TObject *Sender)

  {

  randomize();

  a=random(5);

  if( a==0)

  Memo1->Lines->Add("Привет!");

  ...

  else

  Memo1->Lines->Add("Приветик!");

  Edit1->SetFocus();

  }

то программа выдала ошибку: Project Project1.exe raised exception class Einvalid Operation with message Cannot focus a disabled or invisible window Process stopped. Что это означает и как все-таки перенести курсор в поле ввода, а то он остается в поле Memo?

Вызов SetFocus здесь происходит в обработчике создания формы - не гарантируется, что к этому моменту объект Edit1 уже будет на ней существовать в полноценном виде. Попробуйте вызывать SetFocus позже, из других мест - из обработчика нажатия на кнопку итд.

5. На форме с полем ввода и кнопкой после ввода текста в поле ввода для нажатия на кнопку приходится кликать по ней мышкой или нажимать клавиши Tab и Enter. Как сделать, чтобы кнопка срабатывала после ввода текста в поле ввода только по нажатию клавиши Enter (минуя клавишу Tab)?

Не знаю :)
Можно отлавливать нажатия клавиш в поле ввода (событие OnKeyUp, клавиша отпущена) и проверять, какая клавиша была нажата.

6. По программе с кубиком Вы привели способ блокирования клавиш, предложенный моим тезкой. К сожалению, для моего Билдера этот способ не подошел и программа выдала сплошные ошибки, а, как его исправить, я не знаю. Вместе с тем, для проверки введенных данных на наличие букв в VB6 я применял функцию IsNumeric(). Однако там эта функция работала со строками непосредственно.
В Справке С++ функция IsNumeric() также имеется , но работает с типом данных char
function IsNumeric(c: char): Boolean;
Однако при попытке использовать эту функцию программа выдала ошибку: [C++ Ошибка] Unit1.cpp(46): E2268 Call to undefined function IsNumeric
Не могли бы Вы разъяснить порядок применения функции IsNumeric() и, вообще, типа данных char?

Тип данных char - это фактически тип int, он представляет целые числа. Насчет IsNumeric ничего не знаю. Это у вас, судя по всему, выдалась подсказка не по C++, а по C# :) Они похожи сильно, и изучив С++, несложно будет перейти и на С#, и на Java.

Лучше всего использовать уже упоминавшуюся мной ранее функцию TryStrToInt, которая корректно проверяет перед преобразованием из строки в число саму возможность такого преобразования.

7. При щелчке по объекту в конструкторе кода появляется обработчик типа:

  void __fastcall TForm1::Edit1Change(TObject *Sender)
  {
  ...
  }

то есть, для поля ввода это событие Change. Но у объекта могут быть другие события. Как сделать обработчик для этих других событий?
Я пробовал поменять в обработчике Change на OnEnter, но программа выдала ошибку:
[C++ Ошибка] Unit1.cpp(44): E2316 _fastcall TForm1::Edit1OnEnter(TObject *) is not a member of TForm1
Наверное вопросов слишком много, но, вообще говоря, их еще больше.
Андрей Гагарин

Список событий, которые объект может обрабатывать, доступен на закладке Events Инспектора объектов. Двойной щелчок на любом из них - и формируется нужный обработчик. Там же есть и OnEnter.

С первым заданием справилась быстро, правда, функцией Randomize() пренебрегла, так что каждый раз получается один и тот же результат, хоть и правильный:)

  int a[100],i,max,min,k,l;
  void __fastcall TForm1::Button1Click(TObject *Sender)
  {
  for (i=0; i<100;i++)
  a[i]=random(100);
  }
  int a[100],i,max,min,k,l;
  void __fastcall TForm1::Button1Click(TObject *Sender)
  {
  for (i=0; i<100;i++)
  a[i]=random(100);
  }
  void __fastcall TForm1::Button2Click(TObject *Sender)
  {
  max=0;
  for( i=0;i<100;i++) // ищем наибольшее
  if (a[i]>=max)
   {
   max=a[i];k=i; // max- наиб.элемент, k- его номер
   }
  for( i=0;i<100;i++) // ищем наименьшее
  if (a[i]<=max)
   {
   min=a[i];l=i; // min- наим. элемент, l - его номер
   }
      Label2->Caption=IntToStr(max);
      Label5->Caption=IntToStr(k);
      Label4->Caption=IntToStr(min);
      Label8->Caption=IntToStr(l);
  }

А со вторым заданием пыхтела... Уже почти сдалась. Изрисовала кружочками, квадратиками и буковками пол блокнота. Один коллега, заметив меня за этим занятием, пошутил, что по сравнению с моим упорством корпорация Майкрософт отдыхает:))))
НО ПОЛУЧИЛОСЬ!!!
Хоть мне и не очень нравится алгоритм (мне кажется, все должно быть гораздо проще!), но он работает!!!
Вот программка:

  int a[20],c[20],i,k,max,l;
  AnsiString d;
  void __fastcall TForm1::Button1Click(TObject *Sender)
  {
   for (i=0;i<20;i++)
   {
    a[i]=random(20);
   }
  }
  //---------------------------------------------------------------------------

  void __fastcall TForm1::Button2Click(TObject *Sender)
  {
    for (k=0;k<20;k++)
    { max=0;
     for (i=0;i<20;i++)
           {
            if (a[i]>max)
             {
               max=a[i];l=i; // находим максимальный элемент и его номер
             }
           }
           c[k]=a[l]; // по порядку убывания сохраняем в массив с
           a[l]=0; // обнуляем максимальный элемент массива а
     }
         ListBox1->Clear();
         for (i=0;i<20;i++)
      {
        d=IntToStr(c[i]);
        ListBox1->Items->Add(d);
      }
  }

ВОТ!:)
Светлана.

Отлично, очень даже симпатичный алгоритм, и кстати весьма наглядный. Хорошо, что многие с этим заданием справились - оно все же достаточно сложное, и замечательно, что удалось и сам алгоритм придумать (для этого как раз блокнотики очень активно и используются :), и реализовать его в виде программы. Из этого программирование и состоит.

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

А ведь ничего сложного, правда? После такого задания прежние кажутся ерундой. А через некоторое время и задача на сортировку также покажется тривиальной.

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

Выполнил первое задание:

  int a[100],i,m,n,max,min;

  void __fastcall TForm1::Button1Click(TObject *Sender)
  {
   for (i=0;i<100;i++)
    {a[i]=random(100);}
  }

  void __fastcall TForm1::Button2Click(TObject *Sender)
  {
  min=a[0];
  max=a[0];
  for (i=0;i<100;i++)
  {
     if (max<a[i])
       {max=a[i];
        n=i;}

     if (min>a[i])
       {min=a[i];
        m=i;}

  }

  n+=m;
  m=n-m;
  n-=m;

  Label1->Caption=n;
  Label2->Caption=m;
  Label3->Caption=max;
  Label4->Caption=min;}

  void __fastcall TForm1::FormCreate(TObject *Sender)
  {
  Randomize();
  }

Буквально сегодня днем мне по почте пришла Ваша книга "Технологии Пентагона на службе российских программистов". В тоже время уже вторую неделю учавствую во Всероссийской заочной олимпиаде по информатике 2006/07 - активно решаю задачи по программированию(Paskal). И Ваша книга мне реально помогла - я не мог прооптимизировать решение("превышение максимального времени":-)), но прочитав первую главу у меня появились мысли как улучшить свой код и я сдал задачу. Огромное спасибо за ... мотивацию!:-)

Вам - поздравления и пожелания дальнейших успехов в Олимпиадах и Программировании!

Также рассмотрел вторую задачу, но к сожалению кроме обычной сортировки мне ничего не вспомнилось, поэтому я красиво разместил все на форме и вывел в многострочное поле:

  int i,j,n,a[100];

  void __fastcall TForm1::Button1Click(TObject *Sender)
  {
  for (i=0;i<n;i++)
  for (j=i;j<n;j++)
  { if (a[i]>a[j]) {
             a[j]=a[i]+a[j];
             a[i]=a[j]-a[i];
             a[j]=a[j]-a[i];}}

  }
  //---------------------------------------------------------------------------

  void __fastcall TForm1::Button2Click(TObject *Sender)
  {
  n=StrToInt(Edit1->Text);
  for (i=0;i<n;i++)
  {a[i]=random(50);}
  }
  //---------------------------------------------------------------------------
  void __fastcall TForm1::FormActivate(TObject *Sender)
  {
  Randomize;
  }
  //---------------------------------------------------------------------------
  void __fastcall TForm1::Button3Click(TObject *Sender)
  {
  for (i=0;i<n;i++)
  {Memo1->Lines->Add(IntToStr(a[i])); }
  }

  Александр

Следующее письмо.

Первые вопросы по заполнению массива:
1. Обнаружил, что запись ++i аналогична записи i++; Как более правильно? Или это все равно?

Во многих случаях все равно, но выражение i++ или ++i само по себе возвращает значение и иногда используется в выражениях:

A[ i++ ] = b;

Здесь в одном операторе и значение элемента массива меняется, и счетчик увеличивается. Но выражение i++ сначала формирует свой "результат" (значение переменной i), и лишь затем увеличивает эту переменную. А выражение ++i сначала увеличивает значение переменной, и лишь потом ее новое значение возвращает в программу:

   i = 5;
   n = i++; // в n записано число 5
   i = 5;
   n = ++i; // в n записано число 6

Далее.

  int A[10], i;
  AnsiString s;
   
  ListBox1->Clear();
  for (i=0; i<10; ++i)
  {
  s = IntToStr( A[ i ] = i );
  ListBox1->Items->Add(s);
  }
   s = IntToStr( A[ 4 ]-1 );
   ListBox1->Items->Add(s);

2. Не могу понять :
1. Если записать A[ i ] , а не A[ i ] = i, - массив заполняется случайными числами.

"A[ i ] = i" - это оператор инициализации элемента A[i] значением переменной i. Корректно так:

  for (i=0; i<10; ++i)
  {
  A[ i ] = i;
  s = IntToStr( A[ i ] );
  ListBox1->Items->Add(s);
  }

3. При попытке вывести в обратном порядке выдает ошибку.

  for (i = 10 ; i > 0 ; i --)
   {
  s = IntToStr( A[ i ] = i );
  ListBox1->Items->Add(s);
  }

Что не правильно? Константин. Неправилен оператор

s = IntToStr( A[ i ] = i );

Вообще его смысл непонятен.

В Вашей книге встретил название программы Workshop, для просмотра файлов dll. Если Вас не затруднит - полное скажите название - а то в сети очень много программ с таким именем :)

Уже давно не помню :) Но уверен, что должно быть немало утилит для изымания ресурсов из dll и exe файлов.

Написал программу с сортировкой элементов по возрастанию.
Для наглядности элементы хранил в массиве вместе с их первоначальными номерами Результаты вывел в таблицу StringGrid.
Только с объявлением массива пришлось повозиться: Билдер не воспринимал запись типа: int m[100,2]; а только как в тексте программы. По видимому, опять разница в версиях. Вот листинг:

  int min[2];
  int m [100][2];
  int i,j;
  void __fastcall TForm1::FormCreate(TObject *Sender)
  {
  randomize();
  }

  void __fastcall TForm1::Button1Click(TObject *Sender)
  {
  StringGrid1->Cells[0][0] = "Номера";
  StringGrid1->Cells[1][0] = "Значения";
  for (i=0;i<100;i++)
          {
           m[i][1] = random(1000);
           m[i][0] = i;
           StringGrid1->Cells[1][i+1] = IntToStr(m[i][1]);
           StringGrid1->Cells[0][i+1] = IntToStr(m[i][0]);
          }
  }

  void __fastcall TForm1::Button2Click(TObject *Sender)
  {
  StringGrid2->Cells[0][0] = "Номера";
  StringGrid2->Cells[1][0] = "Значения";
  for (i=0;i<99;i++)
          {
           min[0] = m[i][0];//Запоминаем номер очередного элемента
           min[1] = m[i][1];//и его значение
           for (j=i+1;j<100;j++)
                  {
                  if (min[1] > m[j][1]) //Сравниваем запомненный элемент с
  оставшимися
                          {
                           m[i][0] = m[j][0]; //Если запомненный меньше, то
                           m[i][1] = m[j][1]; //меняем их местами
                           m[j][0] = min[0];
                           m[j][1] = min[1];
                           min[0] = m[i][0];
                           min[1] = m[i][1];
                          }
                  }
           StringGrid2->Cells[1][i+1] = IntToStr(m[i][1]);
           StringGrid2->Cells[0][i+1] = IntToStr(m[i][0]);
          }
  StringGrid2->Cells[1][100] = IntToStr(m[99][1]);
  StringGrid2->Cells[0][100] = IntToStr(m[99][0]);
  }
  Ярослав

Далее.

Выполнил задания и высылаю Вам , первое оказалось простым , но должен сказать , что очень помогли Ваши уроки по Делфи (алоритмы очень похожи) и возникли проблемы перехода на новую строку в ЛистБоксе (появляется какой-то знак , а строка не переносится). Код получился такой

  int mas[100],
      i ;
   
  void __fastcall TForm1::Button1Click(TObject *Sender)
  {
   for (i = 0; i < 100; i++)
    {
     mas[i] = random(100);
     ListBox1->Items->Add(IntToStr(mas[i]));
    }
  }

  void __fastcall TForm1::FormCreate(TObject *Sender)
  {
   randomize();
  }
  //---------------------------------------------------------------------------
  void __fastcall TForm1::Button2Click(TObject *Sender)
  {
   int maks, min,
       maksi,mini;
   
   maks = 0;
   min = 100;
   
   for (i = 0; i < 100; i++)
   {
    if (maks < mas[i])
     {
      maks = mas[i];
      maksi = i;
     }
    if (min > mas[i])
     {
      min = mas[i];
      mini = i;
     }
   }
   ListBox2->Items->Add("Ячейка с индексом "+IntToStr(maksi)+" равна
  "+IntToStr(maks));
   ListBox2->Items->Add("Ячейка с индексом "+IntToStr(mini)+" равна
  "+IntToStr(min));
   
  // меняем местами
   min = min+maks;
   maks = min-maks;
   min = min-maks;
   
   ListBox2->Items->Add("Ячейка с индексом "+IntToStr(maksi)+" равна
  "+IntToStr(maks));
   ListBox2->Items->Add("Ячейка с индексом "+IntToStr(mini)+" равна
  "+IntToStr(min));
  }

А вот во втором задании пришлось подумать , но после недолгих раздумий и тут не оказалось ничего запредельного. Вот код массива отсортированного по убыванию.

  int mas[100],
      mas2[100];
   
  //---------------------------------------------------------------------------
  __fastcall TForm1::TForm1(TComponent* Owner)
          : TForm(Owner)
  {
  }
  //---------------------------------------------------------------------------
   
  void __fastcall TForm1::Button1Click(TObject *Sender)
  {
   int i;
   
   for (i = 0; i < 100; i++)
   {
    mas[i] = random(100)+1;
    ListBox1->Items->Add(IntToStr(mas[i]));
    ListBox3->Items->Add(IntToStr(mas[i]));
   }
  }
  //---------------------------------------------------------------------------
  void __fastcall TForm1::FormCreate(TObject *Sender)
  {
   randomize();
  }
  //---------------------------------------------------------------------------
  void __fastcall TForm1::Button2Click(TObject *Sender)
  {
   int i,n,
       g,l;
   
   g = 0;
   for (n = 0; n < 100; n++)
   {
    for (i = 0; i < 100; i++)
    {
    if (g < mas[i])
     {
      g = mas[i];
      l = i;
     }
    }
    mas2[n] = g;
    mas[l] = 0;
    g =0;
    ListBox2->Items->Add(IntToStr(mas2[n]));
   }
  }
  //---------------------------------------------------------------------------
  void __fastcall TForm1::Button3Click(TObject *Sender)
  {
   ListBox3->Sorted = true;
  }
   
  Роман

Еще ответы.

  int x[100]; //Обрабатываемый массив
  int Imin, Imax; //Индексы минимального и максимального эл-в

  void __fastcall TForm1::Button1Click(TObject *Sender)
  {
    ListBox1->Clear();

    for (int i = 0; i < 100; i++) { //Заполнение массива, вывод
            x[i] = random(1000);
            AnsiString s;
            s = IntToStr(i+1) + ") " + IntToStr(x[i]);
            ListBox1->Items->Add(s);
    }

    Imin = 0;
    Imax = 0;

    for (int i = 0; i < 100; i++) { //Нахождение индексов
            if (x[Imin] > x[i]) Imin = i; //макс. и мин. элементов
            if (x[Imax] < x[i]) Imax = i;
    }

    //Вывод номеров макс. и мин. элементов и сами макс. и мин.
  элементы

    Label10->Caption = "¬ " + IntToStr(Imin + 1);
    Label7->Caption = "¬ " + IntToStr(Imax + 1);
    Edit1->Text = IntToStr(x[Imin]);
    Edit3->Text = IntToStr(x[Imax]);

  }
  //---------------------------------------------------------------------------
  void __fastcall TForm1::Button2Click(TObject *Sender)
  {
    ListBox2->Clear();

    int buff;

    buff = x[Imin]; //Перемена местами элементов
    x[Imin] = x[Imax];
    x[Imax] = buff;

    buff = Imin; //...и их индексов
    Imin = Imax;
    Imax = buff;
                                     //Вывод итогов:
    for (int i = 0; i < 100; i++) { //...массива
            AnsiString s;
            s = IntToStr(i+1) + ") " + IntToStr(x[i]);
            ListBox2->Items->Add(s);
    }
                                                           //...мин. и макс. элем-в, с номерами
    Label9->Caption = "¬ " + IntToStr(Imin + 1);
    Label8->Caption = "¬ " + IntToStr(Imax + 1);
    Edit2->Text = IntToStr(x[Imin]);
    Edit4->Text = IntToStr(x[Imax]);
  }
  //---------------------------------------------------------------------------
  void __fastcall TForm1::FormActivate(TObject *Sender)
  {
    randomize();
  }
  //---------------------------------------------------------------------------

  Задание 2:

  Мой алгоритм сортировки:

  const int maxInd = 32000; //Максимальное число эл-в массива
  int x[maxInd]; //Сортируемый массив
  int T; //Счетчик времени (мс)
  //---------------------------------------------------------------------------
  __fastcall TForm1::TForm1(TComponent* Owner)
          : TForm(Owner)
  {
  }
  //---------------------------------------------------------------------------
  void __fastcall TForm1::Button1Click(TObject *Sender)
  {
     ListBox1->Clear(); //Формирование и вывод
                                                                            //исходного массива
     for (int i = 0; i < maxInd; i++) {
             x[i] = random(100);
             AnsiString s = IntToStr(i+1) + ") " + IntToStr(x[i]);
             ListBox1->Items->Add(s);
     }
  }
  //---------------------------------------------------------------------------
  void __fastcall TForm1::Button2Click(TObject *Sender)
  // алгоритм сортировки
  {
     T = 0; //Начинаем подсчет времени
     Timer1->Enabled = true;

     int HI; //Верхний индекс
     int LI; //Нижний индекс
     int i, j, buff; //Вспомогательные переменные

    //Сортировка
    for (j = maxInd; j > maxInd/2; j--) {
    HI = j - 1;
    LI = maxInd - j;

          for (i = LI+1; i < HI; i++) {

                  if ((x[LI] > x[HI])) {
                          buff = x[HI];
                          x[HI] = x[LI];
                          x[LI] = buff;
                          }
                  if ((x[LI] > x[i])) {
                          buff = x[i];
                          x[i] = x[LI];
                          x[LI] = buff;
                          }
                  if ((x[i] > x[HI])) {
                          buff = x[HI];
                          x[HI] = x[i];
                          x[i] = buff;
                          }
    }
  }
   Timer1->Enabled = false; //Остановка подсчета времени

     ListBox2->Clear();
     for (int i = 0; i < maxInd; i++) {
             AnsiString s = IntToStr(i+1) + ") " + IntToStr(x[i]);
             ListBox2->Items->Add(s);

     Label1->Caption = "Время = " + IntToStr(T) + " c";
   }
  }
  //---------------------------------------------------------------------------

  void __fastcall TForm1::FormActivate(TObject *Sender)
  {
  randomize();
  }
  //---------------------------------------------------------------------------
  void __fastcall TForm1::Timer1Timer(TObject *Sender)
  {
    T++;
  }
  //---------------------------------------------------------------------------

  Описание:

       Циклически, перебираются все элементы массива, и
  сравниваются 1-й,
       текущий (i-й), и последний элементы. Если не выполняется
  условие:
       Первый элемент < i-й элемент < Последний элемент, то
  производится
       смена 2-х элементов местами, таким образом, чтобы это условие
       выполнялось.
       Когда дойдем до последнего элемента, то получим массив, в
  котором
       первый элемент - минимальный, а последний - максимальный.
       Проделываем все сначала, но теперь, в качестве 1-го элемента
       используем второй, а вместо последнего - предпоследний.
       И так далее, n/2 раз, где n - размерность массива.

  Я не знаю, как оценить эффективность такого алгоритма
  теоретически.

  Для сравнения скорости моего алгоритма с каким-нибудь другим,
  например
  - сортировкой вставками, я хотел использовать компонент TTimer
  (см.
  код программы), но не смог этого сделать: время сортировки -
  всегда=0.

  С помощью такой программы:

  int T = 0;
  //---------------------------------------------------------------------------
  void __fastcall TForm1::Button1Click(TObject *Sender)
  {
   Timer1->Enabled = !(Timer1->Enabled);
  }
  void __fastcall TForm1::Timer1Timer(TObject *Sender)
  {
  T++;
   Label1->Caption = IntToStr(T);
  }
  //---------------------------------------------------------------------------
  void __fastcall TForm1::Button4Click(TObject *Sender)
  {
     int i,j,k;
     for (i = 0; i <= 500000000; i++) {
           for (j = 0; j <= 5; j++) {
           }
     }
     ShowMessage("Test complete, T = " + IntToStr(T));
  }

  ,которая наглядно показывает выполнение метода OnTimer, я
  выяснил, что
  во время выполнения циклов этот метод не вызывается.

  Странно, ведь если так, то точный подсчет времени с помощью
  компонента
  TTimer невозможен.

  Этот вопрос, конечно, не по теме выпуска, но все же интересно,
  почему
  TTimer так работает?

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

Теоретически возможно разбить алгоритм на "кусочки", и выполнять каждый кусочек в обработчике таймера. Тогда можно сделать несколько таймеров, в обработчике каждого из которых выполняется очередной кусочек оригинального процесса. Но создание таких программ - весьма трудоемкое занятие!

В вашем случае таймер не будет работать параллельно с интенсивным вычислительным процессом. Но вы можете перед расчетами запоминать текущее время, и по окончании проверять, сколько времени прошло. Для этого используют функцию GetTickCount(), которая возвращает число миллисекунд (тысячных секунды), которое прошло с момента запуска (то ли системы, то ли 1980-го года, не помню, в общем, огромное число :). Само значение GetTickCount() анализировать не надо, достаточно лишь запомнить его и отслеживать периоды. Из-за того, что число миллисекунд может быть большим, для его хранения используют не тип int, а тип long (то же целое, но с расширенным диапазоном):

   long t;
   t = GetTickCount(); // запомнили текущее время
   // сложные вычисления!...
   t = GetTickCount() - t; // сколько мс прошло
   double x;
   x = t/1000; // в x - секунды, потраченные на вычисления


Отладка.

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

Все современные среды программирования поддерживают так называемый режим символьной отладки. Это означает, что программу можно выполнять по шагам (по отдельным командам), приостанавливаясь после каждой выполлненной команды и проверяя текущие значения переменных.

Для знакомства с отладкой создадим пустую форму, добавим к ней кнопку, и в обработчике нажатия на нее введем такой код:

   int m[10];
   int i;
   for( i=1; i<=10; i++ )
     if( i<5) m[i] = 1;
     else m[i] = 2;

В данном коде есть смысловая ошибка, которая приведет к краху программы после запуска. Сможете ее найти?

пауза

Массив индексируется всегда с нуля. Это значит, что его первый элемент имеет индекс 0, а десятый элемент - индекс 9. Здесь же происходит обращение к элементам с индексами от 1 до 10 - и при попытке обращения к несуществующему элементу m[10] (последний доступный элемент - это m[9]) возникнет ошибка времени выполнения (обращение к недоступной области памяти).

Попробуем выполнить этот код по шагам. Для этого установим курсор на строчку с оператором for и нажмем клавишу F5. Эта строчка в редакторе выделится другим цветом. Таким образом мы установили в программе точку прерывания - когда до нее доходит очередь в процессе работы программы, она временно приостанавливается.

Теперь запустим программу клавишей F9 и нажмем кнопку на форме запущенной программы. Ее работа прервется, и управление вернется в среду C++Builder - к оператору for, помеченному клавишей F5. Очередной оператор, который должен быть выполнен на очередном шаге (но еще не выполнен!), помечен подсветкой и стрелочкой слева на панели.

Здесь мы можем посмотреть текущие значения переменных - счетчика i и массива m. Достаточно навести на имя переменной курсор, и во всплывающем окне появится ее текущее значение. В старых версиях C++Builder возможно такой подсказки не было - там надо создать окно слежения за значениями переменных командой View - Debug - Watches (или какой-то аналогичной; ищите слово Watch).
Добавление в это окно переменной, за значением которой мы хотим следить, выполняет клавиша INS.

Далее существующий код можно продолжать выполнять, причем по отдельным шагам. Для этого используется клавиша F8. Нажмем ее - стрелочка и выделение сместится на следующую строку. Однократно выполнится заголовок оператора for, где переменная i получит значение 1. Далее выполнится проверка условного оператора (вновь нажмем F8) - зафиксируется значение элемента m[i], и следующей строчкой кода вновь станет заголовок оператора for. Продолжим цикл по шагам - переменная i будет постепенно увеличиваться до 10, и в конце цикла будет ясно, в чем ошибка - конечным значением i становится 10 (а не 9, как положено для индексации массива из 10 элементов), в результате проиосходит обращение к несуществующему элементу и возникает ошибка.

Теперь можно прервать работу программы - нажатием CTRL + F2, внести исправления и запустить заново. Если требуется продолжить работу с текущего места, нажимаем F9.

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


(c) 2004-2006 Сергей Бобровский bobrovsky as russianenterprisesolutions.com

Школа программирования с нуля
Все предыдущие выпуски базового курса всегда тут:
http://www.infiltration.ru/p/

Неофициальный сайт поддержки (со срочными вопросами - сюда):
www.prog-begin.net.ru.


Вышел мой учебный курс "Технологии Delphi. Разработка приложений для бизнеса".
http://shop.piter.com/book/978591180282/

Учебный курс рассчитан не только на разработчиков, но и на всех тех, кто хочет стать ИТ-менеджером. Для этого как минимум нужно иметь общее представление о современных технологиях разработки и их истории и владеть соответствующей терминологией.
В книге описаны десятки технологий, каждой из которых посвящены отдельные книги. Таким образом, купив одну мою книгу, вы существенно сэкономите :) В книге полностью описан язык Delphi (версия 2006, полностью совместимая с Turbo Delphi) для обеих платформ - Win32 и .NET. Охвачены также темы работы с файлами на этих платформах, создания файл-серверных, клиент-серверных, распределенных приложений, веб-программ (Indy, ASP.NET, веб-сервисы). Описаны языки SQL и OCL. Немало глав посвящены истории программирования и различных технологий. Особое внимание уделено созданию программ с помощью технологии ECO и языка моделирования UML - программы фактически рисуются, и теперь даже для создания корпоративных приложений и их переноса в Интернет не обязательно знать программирование!
Отдельная часть отведена технологиям организации групповой работы, управления требованиями, контроля версий, локализации и тестирования.
Тут подробнее про книгу.

Другие мои книги, которые пока доступны в продаже:


Дизайн рассылки: Алексей Голубев - Web-дизайн и web-программирование


В избранное