Автор Тема: Езикът C  (Прочетена 14052 пъти)

spookyboy

  • Бил знаел какво е Мехатроника!
  • *****
  • Публикации: 103
    • Профил
Езикът C
« -: Август 19, 2007, 02:21:19 am »
Поради излишък от свободно време (обикновенно предназначено за сън) реших и аз да изцапам форума с малко информация :) Тази тема е с цел да ви даде начална скорост в програмирането на C и да ви спести хамалщината по издирване на компилатор и инсталацията му :)
Have Fun!

Какво ще ви е нужно за да започнете работа?
1. Най-важното нещо е редактор на текст :) Него можете да си го избирате по собствен вкус и предпочитания, започвайки от NotePad, та чак до MS Visual C++ (който напоследък ползвам само като редактор, поради лични причини от сорта на това, че ме дразни с правенето на куп излишни файлове). Предимството на MSVC++ пред NotePad главно е, че оцветява кода по специален начин, така че ви е по-лесно да го четете.

2.След като си изберете текстов редактор и си натракате кода, определено ще ви трябва компилатор (ако го чувате за първи път може да ви звучи смешно :) ). Повечето компилатори вървят в комплект с текстов редактор (или по-скоро някои текстови редактори вървят в комплект с компилатори :) ), което разбира се не означава че ако пишете на определен редактор, трябва задължително да компилирате с неговия компилатор. Лично ви препоръчвам DJGPP за да се озорите и вие като мен :P А сега сериозно, по принцип компилатора който ползва DJGPP е последна версия и програмата която ще създаде компилацията има по-голяма стабилност. Лошото е настройката, която лично мен ме изнерви, но с малко упоритост става.

Как да инсталираме DJGPP?

Ще карам накратко:
-Дърпате инсталационния файл от тук
-Стартирате дръпнатия файл :)
-Натискате Browse
-Избирате C:
-Натискате Make New Folder
-Въвеждате DJGPP за име
-Натискате OK
-Натискате Install

Готови сте с инсталацията на DJGPP! (за жалост не можете да компилирате на него много просто, но като стигнем до там ще обясня, имайте търпение!! :) )

Най-накрая е време да напишем някой и друг ред код.
Първо да поговорим за синтаксиса на C.

Всеки source код (нещото което се компилира) на C започва с няколко реда в който описвате библиотеките с функций, които мислите да ползвате. По принцип, ако не решите да ползвате библиотека създадена от вас, (а аз няма да ви кажа как да си създадете, за да не решавате да ползвате такава :) ) няма нужда да се притеснявате къде се намират тези библиотеки. Важното е да знаете имената на най-честоизползваните такива, а в C те са: stdio.h, string.h, conio.h и math.h. Сигурно се чудите, "Защо тия имена имат точки вътре, пък и h-ове на всичкото отгоре?!" Това е защото .h всъщност е разширението на библиотечните файлове и идва от header, както ги наричат някои, които знаят английски :) Хедърите/библиотеките се добавят по следния начин:#include <име на библиотека>
Такам. В първите ви програмистски пориви на C ще ви е нужно само още едно нещо. Това е заглавната функция main(), която трябва да присъства във всяка програма.
"Какво е функция? Защо main? Защо ()? Защо заглавна?"
Функциите в C са гръбнакът на всяка програма. Трябва да имате поне една такава функция за да ви работи програмата (да, това е main()) Функциите имат тип, приемат аргументи и връщат стойност от типа от който е функцията. Можете да извиквате функции във други функции и така указвате тяхното изпълнение, но това за сега не ви е нужно.
Синтаксисът на една функция е следния:тип име(тип1 аргумент1, тип2 аргумент2, ...)
{
   операция1;
   операция2;
   .
   .
   .
   return стойност_за_връщане;
}


Така вие ще създадете функция от тип тип, която се казва име, приема аргументи аргумент1 от тип тип1, аргумент2 от тип тип2 и т.н. и връща стойност стойност_за_връщане, която евентуално функцията е генерирала и която е от тип тип.
Аргументите се намират между 2 кръгли скоби ( '(' и ')' ) и са отделени със запетайки ( ',' ) един от друг, като пред всеки се пише и неговия тип, а когато функцията не приема аргументи тези скоби пак са там, ама са залепени една до друга и между тях няма нищо.
Мястото между фигурните скоби ( '{' и '}' ) се нарича тяло на функцията. В него тя върши каквото върши и накрая (не винаги накрая) се очаква да върне стойност, което пък се осъществява с оператора return. Много е важно да не забравяте, че в края на всяка операция, (обикновенно всяка такава е на отделен ред) има точка и запетайка ( ';' ).
последно нещо което е хубаво да се знае: '//' се използва за коментар. Т.е. всичкият текст на същия ред след '//' не се чете от компилатора, а служи на програмиста за да се ориентира по-лесно в кода, както и за забележки към четящия (четящия кода :) ).

И вече наистина да съберем всичко това и да видим какво получаваме. Следната програма принтира(изкарва) текстът "Hello World!" (нямате идея каква информационна вълна ще ви затрупа ако го издирите из гугъл) на "стандартния изход" - вашият монитор :) проблем при обикновенната реализация на тази програма е, че ако я стартирате през Виндовс ® искача нещо черно и отшумява преди да сте се осетили какво става. За целта ще използваме функция която изчаква вход от клавиатурата, за да продължи изпълнението на програмата. Ето и кода на цялата работа:
#include <stdio.h>     //да не се бърка със studio.h !!
#include <conio.h>    

int main ()
{
     printf ("Hello World!\n");
     getch ();
     return 0;
}


Да анализираме написаното. Първо декларираме, че ще използваме двете библиотеки stdio.h и conio.h (може да забележите и моя малък коментар, породен от честа грешка :) )
След това дефинираме функцията main() от тип int (няма ограничение за типа на main() но е прието той да е или int или void (за типовете по-късно). Който е внимавал по-рано може да забележи че main() няма аргументи. В повечето от простите програми, не са ни нужни такива.
Следва извикването на функцията printf() която е дефинирана в библиотеката stdio.h. Тази функция преобразува аргументите си в текст и ги отпечатва на екрана (ще видите как). В случая аргументите му са "Hello World!\n". Двойните кавички по правило заграждат текст. \n се третира като специaлен символ и значи нов ред.
Следва извикването на функцията getch(), която е дефинирана в conio.h. Тя е отговорна за това, че виждате отпечатания текст, защото иначе той би отленял в небитието, непосредствено след отпечатването си.

и накрая операторът return прекъсва функцията main() и тя връща стойността 0 (на кой я връща няма значение, за това се грижи някой друг :) )

Дотук добре. Имаме вече код, за който се надяваме че работи. Как ще се убедим? Трябва да го компилираме. Да предположим че сте го запазили в директорията C:\test.c (.c, защото е код написан на езика C, но и test.txt дa го кръстите няма значение).

Сега става опасно. Съществуват два начина за компилация с DJGPP, един, които е сложен всеки път, и друг който е сложен само първия път :)
Ето първия:

-Натискате Start->Run.. и пишете в прозореца дето изскача cmd
после изскача още един черен прозорец който може да ви изглежда малко зловещо, но иначе нищо лошо няма да ви стори. Наричаме го конзола.
-Пишете заклинанието
c:\djgpp\bin\setdjgpp c:\djgpp c:/djgpp конзолата общо взето нищо не прави, освен че изкарва нов ред. Пишете още едно заклинаниеC:\djgpp\bin\gcc -Wall -lm c:\test.c -o c:\test.exe

Готови сте!! Сега влизате в C: и си пускате test.exe

Ето и втория начин:

-Отваряте NotePad и в него въвеждате двете заклинанияCALL c:\djgpp\bin\setdjgpp c:\djgpp c:/djgpp
C:\djgpp\bin\gcc -Wall -lm %1.c -o %1.exe

Запазвате го като Compile.bat
След това премествате Compile.bat в директорията в която е файлът който ще компилирате (в нашия случай C:)

Пак натискате Start->Run.. и пишете в прозореца дето изскача cmd
След това пишете cd <директорията със Console.bat и сорсовете>в случаяcd C:
след това пишете Compile test

и сте готови :)

Това беше моя кратък урок за първа програма на C. Ако още четете, значи имате здрави нерви и много инат. Надявам се темата да ви е харесала, защото положих доста труд (има - няма 2 часа :) ) докато успея да я създам.
HF и ако имате въпроси - Feel Free to Ask :)
Станьо - 20г. - извън чужбина

INF1n1t

  • Бил знаел какво е Мехатроника!
  • *****
  • Публикации: 139
    • Профил
Езикът C
« Отговор #1 -: Август 29, 2007, 09:32:45 am »
Динамично заделяне на памет в С:
 Става много лесно. Трябва обаче да сте запознати с указателите в С. Всъщност, ако не сте запознати с указателите - губите много. Та, използваме функциите malloc() и free().

Първо, нека дефинираме един указател към char:


 char *ptr;


Сега нека заделим динамично памет за 10 char елемента:


ptr = (char *) malloc(sizeof(char)*10);


Допълнение: слагаме (char *) преди malloc(), защото функцията връща void*. Трябва да извършиме преобразуване на типовете, иначе компилаторът ще изписка - при моя дава Warning. (зависи от настройките).

Правиме нещо с елементите, примерно:


ptr[0] = 'a';
ptr[1] = 'z';
ptr[2] = 0;
printf("%s\n", ptr);


И най-накрая освобождаваме паметта, която бяхме заделили. Паметта трябва да се освобождава за да знае операционната система, че тази памет е свободна и може да се ползва наново.


free(ptr);


 Динамичното заделяне на памет е адски важно. Понякога големината на масив може да варира според потребителските предпочитания. Единия вариант е да дефинираме толкова огромен масив (статично заделяне), че каквото и да въведе потребителя, да е по-малко от големината на масива. Другия вариант е динамично да заделиме желаната големина и да оперираме с нея.
Иван Занев - град София

spookyboy

  • Бил знаел какво е Мехатроника!
  • *****
  • Публикации: 103
    • Профил
Езикът C
« Отговор #2 -: Октомври 06, 2007, 01:11:46 am »
Типове
C е функционален език, тоест език базиран на функции. Грубо казано програмите на него вървят, като последователно се извикват въведени от програмиста функции. Функиите приемат аргументи, които може да са променливи или константи и връщат стойности. Константите, променливите и върнатите стойности имат тип, който може да е сред няколко основни типа. Това са int, short,  long, char, float, double.

int (идва от integer / цяло число)
Типът int се използва за цели числа. В по-новите компилатори неговата големина е 4B (байта) или 32bit (бита). Това означава че може да приема 2^32 или 4294967296 различни стойности. По подразбиране int има знак (+ или -) и съответно може да приема стойности от -2147483648 до +2147483647 (защо не до +2147483648 ще ми кажете вие :) ).
Върху променливи от тип int могат да се използват следните аритметични операции: +, -, *, /, %. При +, - и * няма нищо странно, извършват се както очаквате. / в случая се нарича целочислено делене. Когато разделим две променливи от тип int a и b резултатът е цялата част на a/b, например 5/2 = 2.5, 8/3 = 2.(6). % се нарича сравняване по модул или остатък при деление. Тоест 11/3 = 3(2) (3 и остатък 2, защото 3*3 + 2 = 11) => 11%3 = 2 (остатъка).

short (идва от short (да не повярва човек), което значи къс)
short също е целочислен тип. С тази разлика че паметта която заема е 2B или 16bit. Тоест може да приема 65536 различни стойности, и ако има знак това значи от -32768 до +32767. Аритеметичните операции, които могат да се прилагат са същите, като при int.

long (идва от long/ дълъг)
long е третият целочислен тип в C, макар че заедно с short могат да се смятат за разновидности на int. Има големина 4B и е напълно идентичен с int. Смъсъла от него е, че ако не сте сигурни дали компилатора ви е 16 битов или 32 битов (т.е. дали подразбиращата се големина на int е 2B или 4B) така се подсигурявате :).

char (идва от character / писмен знак)
char е по-интересен тип. Големината му е само 1B или 8bit което значи че може да приема само 256 стойности, и ако има знак това са целочислените стойности от -128 до +127. На всяка стойност обаче отговаря определен знак, според известната ASCII таблица (тя е 7 битова, което значи че имаме още 128 стойности който липсват в нея. Те за жалост са различни на различните машини.) Първите 31 символа са контролни знаци. Останалите са printable или визуални знаци. Знаците които лично аз си правя труда да помня са 32 = 'празно място', 48-57 = 0-9, 97-122 = a-z, но не е наложително, понеже винаги може да се погледне в таблицата :). Повече за нея тук или на английската версия (по-подробна е) ето тук.

float (идва от floating point / плаваща точка)
float е тип който се използва за десетични дроби. Неговата големина е 4B. Десетичните дроби във float са представени с мантиса и експонента. Манисата се мени от 0 до 1, а експонентата е степен на която се вдига 10 и се умножава по мантисата. Например 12.5 има мантиса 0.125 и експонента 2 (0.125 * 10^2 = 12.5) и 0.03 има мантиса 0.3 и експонента -1 (0.3 * 10^(-1) = 0.3 * 0.1 = 0.03). Когато ги използвате обаче, това не трябва да ви интересува, защото могат да се използват и както сме свикнали, (0.03 не е грешно, но може да бъде записано и като 0.3е+1). Точността на float обикновенно е прибилизтелно 3 знака след десетичната точка. Приблизително, защото понякога се получават малки отклонения, като например вместо 3.0 получите 2.999.
Върху променливи от тип float могат да се използват следните операции: +, -, *, /. Всички те са еквивалентни на това, което очакваме. 2.0 + 3.2 = 5.2. 4.1 - 1.4 = 2.7. 3.1 * 0.3 = 0.93. 5.0/2.0 = 2.5.

double (идва от double / двоен)
double също е тип за десетични дроби. Неговата големина е 8B или 64bit, и точността му е 2 пъти по-голяма от тази на float. Аритметичните операции са същите, като при float.

Как се декларират променливи от определен тип?
Пише се името на типа, и след него името на променливите, които искаме да декларираме от този тип. (декларирането е нужно, ако искаме да ползваме някоя променлива). Ето пример:short age, height;
double weight;
char gender;

Могат да се добавят и допълнителни запазени думи пред променливите, които ги променят. Например запазената дума unsigned променя диапазона на стойности които може да приема променливата, като го прави такъв че да съдържа само положителни стойности. Например променлива от тип unsigned short ще приема стойности от 0 до 65535 вместо от -32768 до +32767.
Запазената дума const превръща променливата в константа. Това означава, че програмата не може да я променя. Ако искате да създадете константа е нужно при декларирането и да я ициализирате, което става с операторът =.const double PI = 3.14169265;Можете ако желаете да инициализирате и променливи, което става по идентичен начин. Запазената дума long служи за 'разширяване на типа'. Можете да я ползвате само с double и long. long long e целочислен тип с големина 8B или 64bit, а long double е десетична дроб, заемаща памет 12B или 96bit.

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

Операции върху променливите
Операциите се извършват както обичайно. ако искате да съберете две променливи и да запишете резултата в трета трябва да направите следното:
int a = 3,b,c;//декларирате a, b и c и инициализирате а със стойност 3
b = 6; //присвоявате на b стойността 6.
c = a + b; //присвоявате на c стойността на a + b.

Освен аритметичните, можете да извършвате още булеви/логически или побитови операции. Булевите/логическите оператори, които можете да прилагате върху променливи са грубо казано сравнения. Булевите оператори са < (по-малко), > (по-голямо), <=(по-малко или равно), >=(по-голямо или равно), ==(логическо равно (да не се бърка с =)), !=(различно от или не-равно). Логическите оператори се използват като обикновенни и връщат стойност 0 или 1 съответно 1 при вярно и 0 при невярно. Напримерint a, b = 3, c = 4;
a = b > c; //тук на а се присвоява стойност 0, защото b не е по голямо от c
a = b <=c; //а = 1, защото b е по-малко или равно на c;
a = b == c; //a = 0, защото b не е равно на c;
a = b != c; //a = 1, по същата причина
Още две логически операции са || и &&. За разлика от останалите те могат да се използват върху булеви изрази или това което правехме преди 2 реда. || или логическо OR връща 1 ако един от двата израза е 1, а другия 0 или ако и двата са 1 и 0 ако и двата са 0. && или логическото AND връща 1 ако и двата израза са 1 и 0 ако поне един от тях е 0. Пример: int a, b = 3, c = 3;
a = b >= c && b <= c; //един изватен начин да проверите дали b е равно на c, ако b e по-голямо или равно на c и същевременно е по-малко или равно на c то b = c :)
a = b < c || b > c; //това пък е изватен начин да проверите дали b e различно от c


Побитовите операции, могат да ви се сторят странни и излшни в началото.Те са <<, >>, &, |, ^, ~.
<< премества битовете на променливата от лявата му страна на ляво с толкова колкото е променливата от дясната страна.
>> e идентично, само че надясно. Пример:
int a = 7;
a = a << 1; // вече а е 14. 7 в двоична бройна система е 111. Като изместим битовете на ляво с 1 се получава 1110, което е 14.
а = а >> 2; // вече а е 3. досега е било 1110, като преместим битовете на дясно с 2 се получава 11, което е 3.
Ако сте внимавали може да сте забелязали че с това преместване на битовете всъщност умножаваме или делим едно число със степен на 2. Това всъщност е много по-бързо от колкото ако използваме операторът *, поради простата причина че "компютеро работи с еденици и нули', както всички знаят ;).
| побитовото OR (не трябва да се бърка с логическото || OR)
скужи за OR-ване на две числа :) по-лесно се обяснява с пример.
Имаме 00001111 и 0111100, като ги OR-нем, там където има 1 поне при едното число получаваме 1 в резултата. А ако и 2-те са 0-и се получава 0.
Та OR-ваме и получаваме
00001111
 0111100

00111111

& побитовото AND (и то не трябва да се бърка с логическото && AND) служи за AND-ване на 2 числа. Там където има 0 поне при едното число получаваме 0 в резултата, иначе 1. Ако AND-нем пак същите числа ще получим:
00001111
 0111100

00001100

^ побитово XOR, него за жалост няма с какво да го сбъркате :)
служи за (познайте) XOR-ване на 2 числа. Там където има 0 и 1 или 1 и 0 резултатът е 1, а където има 0 и 0 или 1 и 1 е 0. XOR-ваме:
00001111
 0111100

00110011

~ тилда, обръща битовете на 1 число. ~111100 = 11..11000011. Единиците в началото са обърнатите 'невидими' нули на 111100. общо 1-ците и обърнатата 'видима' част от числото са толкова на брой, колкото е и големината на типа в битове. Тоест ако 111100 е от тип int (32 bit) -> 111111111111111111111111111111000011.

Толкова за типовете, променливите и другите такива работи :)
Ето една примерна програмка, която можете да си реализирате:#include <stdio.h>
const double PI = 3.14169265;
int main () {
   int r;
   scanf ("%d", &r);
   double S = PI * r * r;
   printf ("%lf", S);
   return 0;
}
'Програмата' чете от клавиатурата радиуса на една окръжност и пресмята лицето й. Новото тук е функцията scanf, за нея в следващия пост.

Поупражнявайте се с наученото и ако имате въпроси да питате.
Модератор: Темата беше разчистена с цел да се запази четливостта.
Станьо - 20г. - извън чужбина