Принципи на програмирането със С++

Публикувана на: 20.03.2008, от kr_bozhinov
Кoментари:59

1. Увод


"A little inaccuracy sometimes saves tons
of explanation."
Saki (H. H. Munroe)


Компютри и програмиране.
Всяка програма "казва" на компютъра редицата от стъпки, необходими за да се изпълни дадена задача. Процесът на проектиране и реализиране на програмите се нарича компютърно програмиране. Дейността програмиране е централна в компютърната наука.
За да работи един човек с компютър не е необходимо да бъде програ- мист. Той може да използва (като потребител) написани вече програми и програмни системи. Повечето хора, работещи с компютър, правят именно това. Знанията по програмиране за потребителя на готови програми му помагат по-пълно да използва възможностите им и да увеличи ефективността на своята работа.

Езици за програмиране и транслатори.
** Езици за програмиране от ниско ниво.
На най-ниско ниво инструкциите към компютъра са изключително прости. Процесорът изпълнява така наречените машинни инструкции.
Пример:
1. Премести съдържанието на клетка 40000 от паметта в регистъра AX.
2. Извади 100 от регистъра AX.
3. Ако резултатът е положителен, премини към инструкцията, намираща се в клетка 11280 от паметта.
Инструкциите (машинен език) за процесор Intel 80386 са:
161 40000 45 100 127 11280
Същото на езика Асемблер може да се напише така:
MOV AX, [40000]
SUB AX, 100
JG 11280
MOV (move) означава премести; SUB (subtract) - извади; JG (jump if greater than) - ако резултатът е по-голям от 0, премини към ... Използването на буквени имена вместо адреси от паметта прави програмата по-лесна за четене:
MOV AX, [INT_RATE]
SUB AX, 100
JG INT_ERROR
Езиците от ниско ниво зависят от процесора. Например има разлики в езика Асемблер за процесор Intel 80386 и процесор Motorola 68000.
** Езици за програмиране от високо ниво.
При тези езици програмистът описва схематично основните стъпки (алгоритъма), които трябва да се изпълнят за решаване на дадена задача, а специална програма, наречена транслатор (преводач), превежда това описание в машинни инструкции за конкретен процесор. Транслаторите са два вида - компилатори, които създават файл с кода на програмата на машинен език и интерпретатори, които направо подават на процесора (за изпълнение) поредицата от машинни команди.
Същият пример би изглеждал така на C++:
if (int_rate > 100) message_box("Interest rate error");
и на Паскал:
if int_rate > 100 then writeln('Interest rate error');
Съвременните програмни езици не се отличават по функционалност - по принцип всеки алгоритъм може да се програмира на всеки език за програмиране - разликата е в усилията на програмиста и в ефективността на получената програма. Днес съществуват много програмни езици с различно предназначение. Ето по-известните от тях:
- FORTRAN - главно за реализиране на числени алгоритми (счита се за остарял език);
- Algol 60 - главно за описание на алгоритми;
- ADA - разработен и използван в американската армия;
- Pascal - подходящ за обучение по програмиране;
- Modula 3 - обектно-ориентиран език (модулно програмиране);
- Delphi - обектно-ориентиран език, разширение на езика Pascal;
- Simula - обектно-ориентиран език за симулационно моделиране;
- C - универсален език, свързан с операционна система Unix;
- С++ - обектно-ориентиран език, разширение на езика С;
- Lisp, Prolog - езици за функционално програмиране;
- Basic - език, създаден за първите персонални компютри;
- Java - съвременен обектно-ориентиран език главно за мрежово програмиране.
Съществуват и по-специализирани езици, създанени с точно определена цел. Например:
- PHP, ASP - езици за създаване на WEB страници;
- SQL - език за работа с бази данни;
- Perl - скриптов език - за управление на операционни системи.
"Планираните" езици (Pascal, ADA, Modula 3) са създадени от един човек или от група хора с определена цел - отделните им компоненти са логически свързани и могат лесно да бъдат комбинирани.
"Разрасналите се" езици (C/C++, Basic) се развиват във времето, като различни хора добавят нови елементи в езика и същевременно запазват всички стари конструкции, за да могат написани вече програми на старите версии на езика да се транслират и с новите компилатори, създадени за новите версии на езика.
** История на езика С++.
* Езикът С се създава и развива заедно с операционната система UNIX. Първата версия е създадена през 1973 г. от Денис Ричи. Езикът се развива интензивно и през 1977 г. UNIX е пренаписана на С. Стандартна версия на езика е установена през 1989 година.
* Езикът С++ е създаден от Бьорн Страуструп 1983 г. като към езика С са добавени нови елементи. Всъщност възниква нов обектно-ориентиран език, който веднага получава много широко разпространение. Стандартизацията на езика завършва през 1998 година, като книгата на Страуструп Devil e всъщност този стандарт.
** Системи (среди) за програмиране - обикновено се състоят от текстов редактор, компилатор, библиотеки и система за проверка на програмите (debug). За С/С++ по-известните среди за програмиране са:
- Turbo C/C++ (Borland C++ 3.5, 4.5, 5)- удобен за начинаещи програмисти, има help за езика и добър дебъгер; с библиотеките на К. Хорсман могат да се компилират всички примери от книгата и този сборник;
- Borland C/C++ Builder - поддържа С++ стандарт, удобен за по-напреднали програмисти;
- MS Visual C++ - продукт на Майкрософт, поддържа С++ стандарт;
- Dev C++ - поддържа С++ стандарт, няма help за езика и удобен дебъгер;
- DJGPP е среда за 32-битови програми под DOS. Чрез нея могат да се стартират почти всички програми за операционната система Линукс, които не използват многозадачните, многопотребителските и графичните му възможности.
** Отделни компилатори:
- Borland C++ Compiler 5.5 (BCC) - бърз 32-битов оптимизиран компилатор; поддържа С++ стандарт;
- GCC е GNU компилатор, който поддържа най-новите версии (стандарти) на езиците C, C++, Objective-C, Fortran, Java и Ada, също така и библиотеките за тези езици (libstdc++, libgcj,...).

Проста програма - компилиране и грешки.

// hello.cpp       /*Име на файла, съдържащ текста на програмата*/
#include <iostream>       /*Директива на препроцесора*/
using namespace std;       /*Стандартно пространство на имена*/
      
int main()       /*Главна функция */
{ cout << "Hello, World!
";       /*Оператор за потоков изход*/
return 0;       /*Връща на операционната система числото 0*/
}       
Hello, World!

По-важни характеристики на синтаксиса на езика:
- Азбуката на езика се състои от всички символи от клавиатурата на компютъра.
- Поредица от букви и цифри образува име, разделители между имената са интервал или символ, който не е буква или цифра.
- С++ различава малки от главни букви, напр. имената main и Main са различни.
- Програмата се разполага линейно - по редове (няма горни и долни индекси).
- Програмата се състои от оператори - всеки оператор завършва с точка и запетая ";".
- Един оператор може да се разположи на два и повече реда; няколко оператора може да се разположат на един ред - добрия стил на програмиране изисква един оператор да се пише на един ред (освен ако няма съществена причина за противното).
** Процесът от написване до изпълнение на програмата се състои от следните стъпки:
I стъпка: Написване на текста на програмата; използва се текстов редактор, който създава текстов файл - изходен код (source code) [напр. hello.cpp].
II стъпка: Компилиране на програмата; извършва се от компилатора, който създава файл - обектен код (object code) [напр. hello.o или hello.obj].
III стъпка: Свързване на програмата; извършва се от свързваща програма (linker), която създава изпълним файл [напр. hello.exe или hello или a].
IV стъпка: Изпълнение на програмата; операционната система или програмната система стартира създадения изпълним файл.
** Видове грешки.
* Грешка по време на компилация (синтактична грешка) - неправилно написана конструкция от езика. Компилаторът не може да продължи, дава съобщение за грешка, програмистът трябва да поправи грешката и отново да стартира компилатора.
* Грешка по време на изпълнение (Run-time error) - процесорът не може да изпълни някоя инструкция, напр. делене на 0. Операционната система прекратява изпълнението на програмата.
* Грешка в алгоритъма (логическа грешка) - програмата работи, но дава грешни резултати.

Алгоритми.
Да разгледаме следния пример: Внасяме в банка 10000 лева с 6% годишна лихва. Влогът се олихвява месечно. След колко години сумата по сметката ще стане двойно по-голяма?

Месец       Сума        Пресмятане
0       10000.00       
1       10050.00       =10000.00*1.005
2       10100.25       =10050.00*1.005
3       10150.75       =10100.25*1.005
4       10201.51       =10150.75*1.005
..       ...       ...

1. Започнете с таблицата:
Месец       Сума
0       10000
2. Повтаряйте стъпки 2а-2в докато съдържанието на сметката е под 20000 лева.
2а. Добавете нов ред към таблицата.
2б. В първата колона на този ред поставете число, с 1 по-голямо от това на горния ред.
2в. Във втората колона на същия ред поставете числото от горния ред (същата колона), умножено с 1.005.
3. Разделете последното число от първата колона на 12.
Алгоритъм е описание на стъпките, необходими за решаването на някаква задача, което е еднозначно, изпълнимо и винаги завършва. Описанието може да бъде текст, блок-схема или програма на език за програмиране от високо ниво.

Бройни системи.
Най-често използваните бройни системи са:
* Десетична бройна система - цифри: 0,1,2,3,4,5,6,7,8,9
15210 = 2.100 + 5.101 + 1.102 =152
* Двоична бройна система - цифри: 0,1
101112 = 1.20 + 1.21 + 1.22 + 0.23 + 1.24 = 1+2+4+16 = 23
* Шестнадесетична бройна система - цифри: 0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F
7A116 = 1.160 + 10.161 + 7.162 = 1+160+1792 = 1953

Примерите показват превръщане ва числата от двоична или шестнадесетична бройна система в десетична бройна система. Обратното превръщане става, като се дели многократно числото на основата на бройната система. Остатъка при всяко деление представлява една цифра на числото в бройната система.
Например:

частно       остатък       цифра
23       1       1
11       1       1
5       1       1
2       0       0
1       1       1
      
частно       остатък       цифра
1953       1       1
122       10       A
7       7       7
Превъщането от двоична в шестнадесетична бройна система и обратно става много лесно, защото 16 = 24. Просто 4 двоични цифри образуват една шестнадесетична цифра. Например:
За 11110101000101102 имаме 1111 | 0101 | 0001 | 0110 и получаваме
11112 = 1510 = F16, 01012 = 610 = 616, 00012 = 110 = 116, 01112 = 710 = 716, което е F61716.
 P.S. Инфото  е от тук

Коментари 59

13.05.2010 nikitta

Profile

 #include <iostream>
#include <stack>
using namespace std;

int main()
{
    stack <int> s;
    int n,a,x;
    cin >>n;
    for (int i=1;i<=n;i++)
    {
        cout << "x=";
        cin >> x;
        s.push(x);
    }
    cout<<"a=";
    cin>>a;bool dali=false;


    while (( !s.empty()) && (!dali))
    {
        dali=a==s.top();
        s.pop();

    }

    if (dali) cout << "yes"; else cout<<"no";

    return 0;
}

12.03.2010 Avatara

Profile

Напълно подкрепям горното твърдение.

Бъдещето е на виртуалните технологии. Самият факт, че .NET се наложи толкова бързо, го доказва по безпорен начин.

 

12.03.2010 ilarionov

Profile

Да, семейството на C езиците е обвързано с асемблера

и конкретната компютърна архитектура.

 

От там са и главоболията както с генерирания асемблерски код

така и с представянето на данните.

 

Е този проблем не стои ако се генерира изпълним код за виртуална машина,

например JVM. 

12.03.2010 Avatara

Profile

Здравейте,

Следя с интерес темата. Ако ми позволите бих вметнал нещо, което би било от полза за всички, които ползват C++.

Преди всичко държа да подчертая че между C, C++ и C# съществуват съществени различия, които не са само в синтаксиса. C# е много по-близък като философия до Delphi, отколкото до C. Неразбирането на различията може да доведе до доста забавни недоразумения.

 Ето един пример, който нагледно илюстрира основната слабост на езика: 

 ПРИМЕР:

1. Обикновенна програма:

int index = 0;
  size_t arraySize = ...; // нещо си ...
  for (size_t i = 0; i != arraySize; i++)
  array[index++] = BYTE(i);

... и как изглежда тя в действителност:

1. 0000000140001040     mov byte ptr [rcx+rax],cl
2. 0000000140001043     add rcx,1
3. 0000000140001047     cmp rcx,rbx
4. 000000014000104A     jne wmain+40h (140001040h)

2. Същото, но написано "елегантно":

int index = 0;
for (size_t i = 0; i != arraySize; i++)
  {
    array[index] = BYTE(index);
    ++index;
  }

... и как изглежда в действителност:

1. 0000000140001040     movsxd rcx,r8d
2. 0000000140001043     mov byte ptr [rcx+rbx],r8b
3. 0000000140001047     add r8d,1
4. 000000014000104B     sub rax,1
5. 000000014000104F     jne wmain+40h (140001040h)

Както сами може да се убедите от така приложения пример програмата ни едва ли е станала "по-бърза". на практика сме позволили да се получават труднооткриваеми грешки в резултат на "препълване".

Асемблерните езици са обвързани с конкретна платформа. C++ е по-близък до тях, а не до езиците от високо ниво. Това важи с пълна сила за компилатора и свързващият редактор. Ако не се проконтролира компилирания код е възможно да се допуснат много груби грешки, които да имат фатални последствия при изпълнението на крайните приложения при различни апаратни платформи. Това важи в пълна сила за комуникационните приложения.

Още по-забавно е, че това, което в момента се представя като най-голямата новост в ADO.NET технологиите, на практика е познато на професионалните програмисти от преди десетина години. Визирам технологията MIDAS, която е включена още в Delphi 3 (към момента е известна като Datasnap).

Не е важно на какъв език пишем една програма (това важи с пълна сила за параметри като бързодействие и надежност). Важно е да анализираме детайлно получения резултат за да оптимизираме процеса на разработка и да не се налага да се червим пред потребителите. От фирми като Microsoft, Embarcadero, IBM и др. отдавна са разбрали тази простичка истина.

Понякога за да се открие топлата вода е нужно да се опариш. Stick out tongue

С най-добри пожелания

Avatara

P.S. Този пример едва ли ще откриете в учебниците. Просто много неща се премълчават в интерес на "общи концепции".

Все пак темата е за сновополагащите принципи на програмиране с конкретен програмен език, нали? Wink

Закачам се.

 

 

 

11.03.2010 iv_2007

Profile

Здравейте колеги, написала съм 2 варианта на структурирания тип data. Какъв трябва да е според вас размера на променливата z в двата случая? На какво се дължи разминаването в очакванията?

struct data

{

  int k;

  char ch[10];

}z;

 

struct data

{

  int k;

  char ch[20];

}z;

 

Ще уточня, че използвам среда Dev C++.

11.03.2010 static

Profile

 http://trance.bergon.net/Documents/cpp.tar.gz

Ето ви един учебник за C++

17.12.2009 d_georgieva

Profile

 виж това

http://nikolay.kirov.be/2009/CSCB410/lecture03.html

16.12.2009 gigi4ka

Profile

 iskam da popitam za slednata zada4a poneje mn ne razbiram :

Dadeni sa dve desetcifreni celi chisla. Da se napishe programa na C++ koqto namira sumata na dvete cisla?

 

ako nqkoi moje da mi pomogne moje da pi6e i na ginka_17@abv.bg 

Blagodarq Vi predvaritelno!

14.03.2009 hristov_b

Profile

Предлагам решение на задачата на karolin@, като се използва библиотеката STL, но се приложи за списък, чиито елементи са с определен стуктура. Използвам решението предложено от iv_2007, но го адаптирам при използване на стуктура ( типизиран елемент). Опростена е функцията за сравняване. Ако желаем да се сортира по номер ( тип int ) се ползва функцията cmp. Ако желаем да сортираме по оценки ( тип double) се ползва функцията cmp1. Ако желаем да сортираме по име се ползва функцията cmp2. Ако желаем сортирането да е в низходящ ред - обръщаме знака на неравенството.
#include <iostream>
#include <list>
#include <string>

using namespace std;

struct tElem{int num;
             string name;
      double mark;
            }rec;
bool cmp(const tElem p,const tElem q)
{return p.num<q.num;
}
bool cmp1(const tElem p,const tElem q)
{return p.mark<q.mark;
}
bool cmp2(const tElem p,const tElem q)
{return p.name>q.name;
}

int main ()
{
  list<tElem> mylist;
  list<tElem>::iterator it;
  rec.num=8; rec.name="Vlado";rec.mark=5.70;
  mylist.push_back (rec);
  rec.num=5; rec.name="Bobi";rec.mark=4.50;
  mylist.push_back (rec);
   rec.num=3; rec.name="Asen";rec.mark=5.50;
  mylist.push_back (rec);

  mylist.sort(cmp2);

  cout << "mylist contains:"<<endl;
  for (it=mylist.begin(); it!=mylist.end(); it++)
    cout << it->num<<" " <<it->name<<" "<<it->mark<<endl;
  cout << endl;
  system("pause");
  return 0;
}


Следващи възможности за усъвършенстване на програмата са : създаване на шаблон за сортираща функция и сортиране по два признака едновременно.

13.03.2009 iv_2007

Profile

user: hristov_b

как да се направи функция за сравнение

Следващият код е от интернет и сортира създадения конкретен списък по два начина: като се вземе под внимание изписването на буквите и без този параметър. За повече подробности може да се посети този сайт: http://www.cplusplus.com/reference/stl/list/sort.html

#include <iostream>
#include <list>
#include <string>
#include <cctype>
using namespace std;

// comparison, not case sensitive.
bool compare_nocase (string first, string second)
{
  unsigned int i=0;
  while ( (i<first.length()) && (i<second.length()) )
  {
    if (tolower(firstIdea)<tolower(secondIdea)) return true;
    else if (tolower(firstIdea)>tolower(secondIdea)) return false;
    ++i;
  }
  if (first.length()<second.length()) return true;
  else return false;
}

int main ()
{
  list<string> mylist;
  list<string>::iterator it;
  mylist.push_back ("Ani");
  mylist.push_back ("ani");
  mylist.push_back ("Anton");

  mylist.sort();

  cout << "mylist contains:";
  for (it=mylist.begin(); it!=mylist.end(); ++it)
    cout << " " << *it;
  cout << endl;

  mylist.sort(compare_nocase);

  cout << "mylist contains:";
  for (it=mylist.begin(); it!=mylist.end(); ++it)
    cout << " " << *it;
  cout << endl;
  system("pause");
  return 0;
}

А следващата функция определя нарастващ ред на сортиране само на числовото поле. Според мен може да се настрои и за поле от клас string.

bool compi(const tElem &p, const tElem &q)
{
     if (p.num<q.num) return true;
     if (p.num>q.num) return false;
     return false;
    
 }