ITCS - Ликбез по программированию - ПРОГРАММИРОВАНИЕ
Сегодня: Четверг, 08.12.2016, 01:08 (МСК)| Здравствуйте, Гость| Мой профиль | Регистрация | Вход | RSS

Что такое matte painting?

Визуальная среда Flowstone

Эргономика компьютерных клавиатур

Новинки в области цифровых камер

Программы — виртуальные гитаристы
Главная » ПРОГРАММИРОВАНИЕ

Ликбез по программированию

25.08.2010


Нас читает много студентов… Действительно, и вопросов по программированию от них стало приходить не мало. В основном спрашивают по С/С++, потому как эти языки наиболее часто преподаются в вузах. Многие вопросы являются простыми, но как показывает практика, далеко не все могут быстро найти на них ответы. Поэтому постараемся восполнить эти пробелы. 

Со своей стороны я бы выделил сначала топ-10 ошибок начинающих программистов, с которыми можно встретиться наиболее часто. Это из личного опыта:
  • Ошибка «одиннадцатого столба» (ошибка неучтенной единицы). То есть, сколько нужно столбов, чтобы сделать забор из десяти пролетов? Правильно, одиннадцать, хотя многие думают и считают, что десять. Кстати, этому способствует и то, что отправной точкой отсчета в большинстве языков программирования является 0, а не 1 (массивы и т.п.).
  • Путаница со скобками и точками с запятой. Иногда это даже приводит к неожиданным результатам. Эта ошибка наиболее часто возникает, когда код пишется не в специализированных редакторах.  
  • Неправильное преобразование типов, а также непонимание некоторых типов.
  • Проблемы работы с памятью.
  • Переполнение стека.
  • Ошибка выхода за диапазон. Несоответствие переменных и присваиваемых им значений.
  • Целочисленное переполнение.
  • Не(!)использование потоков там, где это нужно. 
  • Использование потоков там, где этого не нужно.
  • Большая направленность на expression-oriented. Это даже не ошибка, а просто создание нечитабельного для других кода. Конечно, круто использовать тернарный «?» вместо конструкции if-then-else (по секрету сказать, он даже быстрее работает), но мало кто поймет такие записи. Я не против такого, но бывают случаи, когда программист «где-то увидел» и начал применять везде, где только можно. 
Повторюсь, что это из личного опыта. Причем любой программист учится на ошибках, как правило, своих. 


***


Итак, очень много вопросов пришло по преобразованию типов в С/С++, особенно в тех вариантах, когда такого отдельного типа как string нет, и есть невнятный CString (программирование под MFС).

Итак, даем код конвертации из CString в char* и обратно.

#include <atlbase.h>
USES_CONVERSION;
CString strData(_T("Some Data"));
char* lpszString = T2A((LPTSTR)(LPCTSTR)strData);

Обратное преобразование еще проще, у меня оно всегда работает так:):

strData=A2T(lpszString);

Если вы делаете подобные преобразования в разных зонах видимости кода, то наличие строки «USES_CONVERSION;» перед преобразованиями обязательно. То есть, если говорить простыми словами T2A (text-to-array) и A2T (array-to-text) должны быть обоснованы. Не забудьте в заголовке файла поставить <atlbase.h>. 

Вообще, немного странно, что многие букву «А» или «a» в данных случаях почему то переводят как «ANSI». Это большое заблуждение, «а» обозначает array, то есть массив. В классическом С и в С++ нет такого типа как string, а есть массив символов типа char. 


***


Теперь перейдем к больному для многих вопросу, перехода от целых чисел к строковым массивам и обратно. Давайте напишем класс:

class str2int 
{public:
explicit str2int(char const *s)
: m_value(atoi(s))
{}
//Операторы
public:
operator int() const {
return m_value;
}
//Члены
private:
int m_value;
};

Все теперь вы можете смело набирать строку int x = str2int(char*…). Как видно в рамках представленного класса, ключевым пунктом является функция atoi(), которую можно перевести (array to integer). То есть, вы можете и просто пользоваться ей напрямую. Есть и обратная функция itoa(), которая преобразует целочисленную переменную в символьную строку. 

Записывается так:

char zBuff[1024];
char* z=itoa(int_value,zBuff,10);

То есть, int_value — это значение, которое нам необходимо перевести в строку, zBuff — буфер, через который мы это проделываем, последняя цифра — основание системы счисления. Все, если хотите, можете написать для этого специальный класс, назвав его как-нибудь оригинально, например, str2int.


***


Еще один часто задаваемый вопрос касается разделения строки на лексемы. Существует и используется несколько различных вариантов. Но в классических рекомендациях для C и C++ это делается с помощью функции strtok(). Выглядит это так… Допустим, вы пишите клиентскую или серверную программу и получаете строку szRecvBuff. Вам нужно ее «распарсить». Обычно в таких случаях сначала ставят команды через символьные разделители (самый частый случай — пробелы). Например:

«get from далее перечисление».

Итак:

char *p;
p=strtok(szRecvBuff," ");
komanda1=p;
p=strtok(NULL," ");
komanda2=p;
//и так далее…
//можете сделать цикл
//while(p);

Разделителем у нас является пробел, который кстати является символом (если кто не знает). В качестве символьных разделителей можно применять любые Unicode символы и их последовательности. Обратите внимание на то, что второй раз мы уже обращаемся к строке через NULL, поскольку сама строка содержится в указателе, а после p=strtok(szRecvBuff," "); мы сместились на следующую позицию. Стоит сказать, что разделители при формировании строк, если вы не умеете работать с очисткой памяти нужно указывать явно, потому, как строки могут заполняться всевозможным мусором. 

Доп. инфо: объединение символьных массивов производится с помощью функции strcat(), копирование из одного массива в другой — с помощью strcpy(). 


***


Также часто спрашивают о формировании потоков, а именно, как их делать и как вызывать. Конечно, есть много специализированной литературы, но вспоминаем правило: «хуже отсутствия документации может быть только неправильная документация». В принципе, доступно написано о потоках в книге Тома Арчера и Эндрю Уайтчепела «Visual C++ .NET. Библия пользователя» (Диалектика, 2003), хотя сама книга довольно странная:), в общем, на любителя.  

В принципе, опишу самую простую конструкцию потока. 

Создаем, например, так:

DWORD WINAPI Thread1(LPVOID lpParam)
{
// «тело потока»
return 0;
}
Запускаем так:
HANDLE        hThread1;
DWORD         dwThread1Id;
hNetThread = CreateThread(NULL, 0, Thread1, 
                    0, 0, &dwThread1Id);

Есть и другие варианты и методики. Тема обширна. Хотя лично моя рекомендация — обращайтесь с потоками осторожно, а лучше поищите и прочитайте дополнительную литературу. Например, я нашел много уникальных технологий (потому как потоки, особенно для С++ — очень важная тема), после чего некоторые книги и даже методические пособия для вузов выглядят просто теоретическими выкладками, которые на практике оказываются неэффективными. 


***


Очень много вопросов по MFC, причем самых тривиальных, например, как создавать DDX переменные и т.п. Это во многом понятно, потому как в Visual Studio 2008 все несколько перевернуто, то есть, старые книги не совсем подходят, а новых я на прилавке еще не видел, хотя… видел, но большинство из них посвящено С#. В общем, чтобы долго не распаляться отошлю к вышеуказанной «библии пользователя», там все доступно описано и показано на примерах. 

Когда многие программируют под MFC с диалоговыми окнами, то им часто необходим таймер, но его нет в Toolbox’е, когда вы переходите к форме. Ситуация решается просто. В h-файле в описании класса диалогового окна вводите строку:

afx_msg void OnTimer(UINT nIDEvent); 

В *.cpp-файле в рамках BEGIN_MESSAGE_MAP вводите:

ON_WM_TIMER()

Потом в коде помещаете функцию, например:

void CMyDlg::OnTimer(UINT nIDEvent) {}

которая будет вызываться командой SetTimer(1, 1000, NULL), где 1000 — это интервал. 


***


Как в C# повесить иконку в SysTray (там, где часы), и сворачивать туда окно программы? 
В принципе, в рамках Visual Studio все делается практически идентично для всех языков программирования, используется класс NotifyIcon. В объявление класса формы вписываем:

public partial class Form1 : Form
    {
private System.Windows.Forms.NotifyIcon notifyIcon1;
}
Далее в:
public Form1 {
//создаем окошко в трее
this.notifyIcon1 = new System.Windows.Forms.NotifyIcon(this.components);
//сюда загружаем иконку
notifyIcon1.Icon = new Icon("COLOR.ICO");
// называем окошко в трее и запускаем его
notifyIcon1.Text = "Наша программа";
notifyIcon1.Visible = true;
// Handle the DoubleClick event to activate the form            
notifyIcon1.DoubleClick += new System.EventHandler(this.notifyIcon1_DoubleClick);
}

После этого пишем:

private void notifyIcon1_DoubleClick(object sender, EventArgs e)
{
//Показываем форму.
this.Show();
//Делаем окно "нормальным".
WindowState = FormWindowState.Normal;
}
private void Form1_Resize(object sender, EventArgs e)
{
if (FormWindowState.Minimized == WindowState)
{
this.Hide();
}
}

Все. Подробная информация по использованию класса NotifyIcon есть как в справке по Visual Studio, так и в MSDN.  


Кристофер

Перепечатка материалов или их фрагментов возможна только с согласия автора











Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
Ассоциация боевых роботов
Рекомендуем...
Новости

Разделы

Опросы

Какой язык программирования вы считаете наиболее актуальным сегодня?
Всего ответов: 308

Друзья

3D-кино






Найти на сайте:








Об авторе       Контакты      Вопрос-ответ        Хостинг от uCoz