Jump to content

C (gjuhë programimi)

Nga Wikipedia, enciklopedia e lirë
(Përcjellë nga Gjuha C)
C

Gjuha programuese C , Brian Kernighan and Dennis Ritchie, edicioni origjinal që shërbeu për disa vite si një burim jo formal i gjuhës.
Paradigmaimperativ (procedural) gjuhë implementimi për sistemë
E projektuar ngaDennis Ritchie
ZhvilluesiDennis Ritchie & Bell Labs
Doli më1972
Emetimi i funditC99 / mars 2000
Tipi i disciplinësstatic, weak
ImplementimiGCC, MSVC, Borland C, Watcom C
Ndikuar ngaB (BCPL,CPL), ALGOL 68, Assembly
Ndikoi nëawk, csh, C++, C#, Objective-C, BitC, D, Concurrent C, Java, JavaScript, Limbo, Perl,PHP

Gjuha programuese C

[Redakto | Redakto nëpërmjet kodit]

C është një gjuhë programuese me qëllim të përgjithshëm, e krijuar në vitet 1970 nga Dennis Ritchie dhe që vazhdon të mbetet një nga gjuhët më të rëndësishme dhe me ndikim në fushën e teknologjisë. Struktura e saj pasqyron qartë aftësitë e procesorëve që ajo synon të përdorë, duke e bërë ideale për zhvillimin e sistemeve operative (sidomos kernelët), drejtuesve të pajisjeve dhe protokolleve të komunikimit. Megjithatë, përdorimi i saj në zhvillimin e aplikacioneve ka ardhur duke u ulur në vitet e fundit. C gjen përdorim të gjerë në një gamë të madhe arkitekturash kompjuterike, nga superkompjuterët më të fuqishëm deri te mikrokontrolluesit më të thjeshtë dhe sistemet e ngulitura.

Kjo gjuhë është pasardhëse e gjuhës programuese B dhe u zhvillua në laboratorët Bell Labs nga Dennis Ritchie në vitet 1972-1973 për krijimin e mjeteve të nevojshme për sistemin operativ Unix. Një nga arritjet më të mëdha ishte rishkrimi i kernelit të Unix në C. Gjatë viteve 1980, C fitoi një popullaritet të madh dhe u bë një nga gjuhët programuese më të përdorura, me kompilatorë të disponueshëm për pothuajse çdo arkitekturë dhe sistem operativ modern. Libri “The C Programming Language,” i shkruar nga Dennis Ritchie dhe Brian Kernighan, për shumë vite ishte burimi kryesor për të gjithë ata që donin të mësonin këtë gjuhë. Që nga viti 1989, C është standardizuar nga Instituti Amerikan i Standardizimit (ANSI) dhe më pas nga Organizata Ndërkombëtare për Standardizim (ISO) dhe Komisioni Ndërkombëtar Elektroteknik (IEC).

C është një gjuhë procedurale dhe imperativ, që mbështet programimin e strukturuar, hapësirën leksikore të variablave dhe rekursionin, me një sistem tipash statik. Ajo është projektuar për të siguruar qasje të drejtpërdrejtë në kujtesë dhe për t’u përkthyer në mënyrë efikase në udhëzime të procesorit, me mbështetje minimale gjatë ekzekutimit. Pavarësisht aftësive të saj të nivelit të ulët, C inkurajon zhvillimin ndër-platformor. Një program i shkruar mirë dhe me qëllim portabilitetin mund të përpilohet dhe ekzekutohet në shumë platforma të ndryshme me pak ose aspak ndryshime në kodin burimor.

Që prej vitit 2000, C ka qëndruar vazhdimisht ndër katër gjuhët programuese më të përdorura, sipas indeksit TIOBE, një matës i popullaritetit të gjuhëve programuese.

Gjuha programuese C është një gjuhë procedurale dhe imperative që ndjek traditën e gjuhëve të familjes ALGOL. Kjo gjuhë u projektua për të qenë efikase dhe për të ofruar akses të drejtpërdrejtë në burimet e kompjuterit, si memoria dhe procesori. C përdor një sistem tipash statik, që do të thotë se të gjitha të dhënat kanë një tip të caktuar gjatë kohës së kompilimit, por është gjithashtu fleksibël, pasi lejon konvertime automatike midis tipeve kur është e nevojshme.

Në C, gjithë kodi i ekzekutueshëm është i përfshirë në funksione. Parametrat e funksioneve kalohen sipas vlerës (pass-by-value), por kur përdoren array-t, ato kalohen si tregues (pointer) në adresën e elementit të parë të array-t. Për të simuluar kalimin sipas referencës (pass-by-reference), përdoren tregues për të kaluar adresën e një objekti, duke i dhënë mundësi funksionit të modifikojë direkt të dhënat origjinale.

Zhvillimet e Hershme dhe Origjina e Gjuhës C

[Redakto | Redakto nëpërmjet kodit]

Gjuha C ka origjinën e saj të lidhur ngushtë me zhvillimin e sistemit operativ Unix, i cili fillimisht u implementua në gjuhën asembler në një PDP-7 nga Dennis Ritchie dhe Ken Thompson në vitet 1970. Në atë kohë, për të përmirësuar funksionalitetin dhe portabilitetin e Unix, ata vendosën ta bartnin sistemin në një PDP-11, por assembleri ishte i kufizuar për projektimin afatgjatë.

Gjuha B: Hapi i Parë

[Redakto | Redakto nëpërmjet kodit]

Ken Thompson krijoi një gjuhë të thjeshtuar, të quajtur B, bazuar në gjuhën BCPL. Synimi ishte zhvillimi i mjeteve për Unix-in e ri. Megjithatë, B nuk përfitonte nga veçoritë specifike të PDP-11 si adresimi me byte, gjë që e kufizoi përdorimin e saj për mjetet më të avancuara.

Kalimi në C: Evolucioni nga B

[Redakto | Redakto nëpërmjet kodit]

Në vitin 1971, Dennis Ritchie përmirësoi gjuhën B duke shtuar mbështetje për tipe të dhënash të reja si karakteret dhe treguesit (pointers). Kjo gjuhë e re u quajt fillimisht New B (NB), dhe më vonë mori emrin C. Në këtë fazë, Ritchie shtoi tregues, varëse të ndryshueshme, dhe array që mund të manipuloheshin në mënyrë efektive.

Rikonstruksioni i Kernelit Unix në C

[Redakto | Redakto nëpërmjet kodit]

Në vitin 1973, me versionin e katërt të Unix, kernel-i i tij u rikonstruktua gjerësisht në C. Ky ishte një moment historik, duke qenë një nga sistemet e para operative që nuk ishte i implementuar ekskluzivisht në asembler. Përveç Unix, edhe sisteme të tjera si Multics dhe MCP përdorën gjuhë të nivelit të lartë për kernelët e tyre.

K&R C dhe Botimi i Parë i "The C Programming Language"

[Redakto | Redakto nëpërmjet kodit]

Në vitin 1978, Brian Kernighan dhe Dennis Ritchie publikuan librin e parë mbi C, të titulluar "The C Programming Language", i cili njihet si K&R C. Ky libër për shumë vite shërbeu si specifikimi i pashkruar i gjuhës dhe popullarizoi versionin e parë të standardizuar.

Futja e bibliotekës standarde për hyrje/dalje (I/O).

Tipe të dhënash të reja si long int dhe unsigned int.

Operatorët e kombinuar të formës op= (p.sh., +=, -=).

Mbështetje për deklarime funksionesh që nuk kthejnë vlera (void).

Standardizimi i C: Nga C89 te C23

Me kalimin e viteve, u bënë përpjekje për standardizimin e gjuhës për të përmirësuar portabilitetin dhe për të eleminuar paqartësitë:

C89/C90 – Standardi i parë i pranuar nga ANSI dhe ISO.

C99 – Shtoi funksione të reja si deklarata fleksibël në blloqe dhe variabla të përkufizuara në çdo pjesë të kodit.

C11 – Shtoi multithreading dhe veçori të reja për sigurinë e kodit.

C17 dhe C18 – Përmirësime të vogla në stabilitetin dhe përputhshmërinë.

C23 (i planifikuar për vitin 2024) – Prurje të reja për të thjeshtuar zhvillimin modern dhe mbështetje më të mirë për embedded systems.

Artikulli kryesor: ANSI C

[Redakto | Redakto nëpërmjet kodit]

Gjatë fundit të viteve 1970 dhe fillimit të viteve 1980, versionet e gjuhës C u implementuan për një gamë të gjerë kompjuterësh, duke filluar nga mainframe, minikompjuterët dhe mikrokompjuterët, përfshirë IBM PC, ndërsa popullariteti i saj u rrit ndjeshëm.

Standardizimi nga ANSI

[Redakto | Redakto nëpërmjet kodit]

Në vitin 1983, Instituti Amerikan i Standardeve Kombëtare (ANSI) krijoi komitetin X3J11 për të vendosur një specifikim standard të gjuhës C. Ky komitet bazoi standardin në implementimin e gjuhës C të përdorur në Unix, ndërsa pjesët jo të lëvizshme të bibliotekës Unix C u kaluan tek grupi i punës IEEE 1003, që më vonë u bë baza për standardin POSIX në vitin 1988. Në vitin 1989, standardi u ratifikua si ANSI X3.159-1989, i njohur si ANSI C, Standard C ose C89.

Standardizimi nga ISO

[Redakto | Redakto nëpërmjet kodit]

Në vitin 1990, standardi ANSI C (me disa ndryshime në formatim) u miratua nga Organizata Ndërkombëtare e Standardizimit (ISO) si ISO/IEC 9899:1990, i njohur gjithashtu si C90. Prandaj, termat C89 dhe C90 përdoren për të referuar të njëjtën gjuhë.

Qëllimi i Standardizimit

[Redakto | Redakto nëpërmjet kodit]

Një nga synimet kryesore të procesit të standardizimit ishte përfshirja e veçorive jozyrtare të cilat ishin futur më vonë në C. Për shembull:

Prototipet e funksioneve nga C++

Pointer-at void

Mbështetje për sete ndërkombëtare të karaktereve dhe lokaleve

Përmirësime në preprocesor

Edhe pse sintaksa e deklarimit të parametrave u zgjerua për të përfshirë stilin e përdorur në C++, deklarimet në stilin K&R mbetën të lejuara për të ruajtur përputhshmërinë me kodin ekzistues.

Në fund të viteve 1990, standardi u rishikua përsëri dhe u publikua ISO/IEC 9899:1999, i njohur si C99. Disa nga përmirësimet kryesore ishin:

Funksionet inline

[Redakto | Redakto nëpërmjet kodit]

Komentet me një rresht //

Mbështetje për tipe të reja të të dhënave, si long long int dhe numrat kompleksë.

Mbështetje për makro variadike (makro me numër të ndryshueshëm argumentesh).

Makroja STDC_VERSION ka vlerën 199901L, duke treguar mbështetjen për C99.

Puna për përditësimin e radhës filloi në vitin 2007 dhe rezultoi në publikimin e ISO/IEC 9899:2011, i njohur si C11. Ky standard prezantoi:

Operacionet atomike

Mbështetje për multithreading

Makro të përgjithshme të tipeve

Mbështetje të përmirësuar për Unicode

Makroja STDC_VERSION merr vlerën 201112L për këtë standard.

C17 (ISO/IEC 9899:2018) ishte një përditësim i vogël që solli korrigjime teknike pa veçori të reja të gjuhës. Makroja STDC_VERSION ka vlerën 201710L.

C23 (ISO/IEC 9899:2024) është publikimi i fundit në tetor 2024 dhe makroja është 202311L. Ky version sjell përmirësime si mbështetje për nullptr, bool, dhe makro static_assert.

C2Y dhe Embedded C

[Redakto | Redakto nëpërmjet kodit]

C2Y është versioni i ardhshëm që do të publikohet pas C23, dhe është planifikuar për publikim në fund të viteve 2020.

Embedded C është një version i gjuhës C i përshtatur për zhvillim në pajisje me burime të kufizuara, me mbështetje

për aritmetikë fikse dhe qasje të drejtpërdrejtë në harduer.

Gjuha C dhe Karakteristikat e Saj

[Redakto | Redakto nëpërmjet kodit]

Gramatika dhe Komentet

[Redakto | Redakto nëpërmjet kodit]

Gjuha C ka një gramatikë formale të specifikuar nga standardi i C-së. Përfundimi i rreshtave zakonisht nuk ka rëndësi në C, por gjatë fazës së përpunimit paraprak kufijtë e rreshtave kanë rëndësi. Komentet mund të shfaqen në dy forma: midis kufijve /* dhe */, ose (që nga standardi C99) pas // deri në fund të rreshtit. Komentet që kufizohen me /* dhe */ nuk mund të ndërthuren, dhe këto karaktere nuk interpretohen si kufij komentesh nëse shfaqen brenda stringjeve ose literaleve të karaktereve.

Struktura e Skedarëve të Burimit

[Redakto | Redakto nëpërmjet kodit]

Skedarët burimorë të C-së përmbajnë deklarata dhe përkufizime funksionesh. Përkufizimet e funksioneve përmbajnë deklarata dhe instruksione. Deklaratat mund të përcaktojnë lloje të reja duke përdorur fjalë kyçe si struct, union, dhe enum, ose t'u caktojnë lloje dhe t'u rezervojnë hapësirë të re variablave duke shkruar llojin përpara emrit të variablit. Fjalë kyçe si char dhe int përcaktojnë llojet e ndërtuara. Pjesët e kodit kufizohen me kllapa { dhe }, të quajtura ndonjëherë "kllapa kaçurrele", për të kufizuar fushën e deklaratave dhe për të vepruar si një njësi e vetme për strukturat e kontrollit.

Instruksionet dhe Kontrolli i Fluksit të Ekzekutimit

[Redakto | Redakto nëpërmjet kodit]

Si një gjuhë imperativë, C përdor instruksione për të specifikuar veprime. Instruksioni më i zakonshëm është instruksioni i shprehjes, i cili përbëhet nga një shprehje për t'u vlerësuar, e ndjekur nga një pikëpresje (;). Si efekt anësor i vlerësimit, mund të thirren funksione dhe t'u caktohen vlera të reja variablave.

C ofron disa instruksione të kontrollit të fluksit për të ndryshuar rendin normal të ekzekutimit:

Kushtëzimet: if ... [else] për ekzekutim të kushtëzuar.

Përsëritjet: do ... while, while, dhe for për ekzekutim iterativ. Instruksioni for përmban inicializim, testim dhe riinicializim, ku cilido prej tyre mund të mos specifikohet.

Instruksione të tjera: break dhe continue përdoren brenda cikleve për të dalë ose për të kaluar te iterimi tjetër. Instruksioni goto mundëson kalimin në një etiketë të caktuar brenda funksionit.

switch: Përzgjedh një rast për t'u ekzekutuar bazuar në vlerën e një shprehjeje numerike. Në dallim nga shumë gjuhë të tjera, kontrolli kalon në rastin e radhës nëse nuk ndërpritet nga break.

Operatorët dhe Pikë Sekuence

[Redakto | Redakto nëpërmjet kodit]

Shprehjet mund të përdorin një sërë operatorësh të ndërtuar dhe mund të përmbajnë thirrje funksionesh. Rendi i vlerësimit të argumenteve të funksioneve dhe operandeve të operatorëve nuk është i specifikuar. Megjithatë, të gjitha efektet anësore (p.sh., ruajtja në variabla) do të ndodhin para pikës së radhës së sekuencës, që përfshin:

Fundin e një instruksioni shprehjeje.

Hyrjen dhe daljen nga thirrjet e funksioneve.

Vlerësimin e operatorëve si &&, ||, ?:, dhe operatori i presjes (,).

Kjo fleksibilitet i lejon përpiluesit të optimizojnë kodin e objektit, por kërkon kujdes nga programuesit për të shmangur rezultate të papritura.

Shenja dhe Karakteret

[Redakto | Redakto nëpërmjet kodit]

Kompleti bazë i shenjave të burimit në C përfshin:

Shkronja të mëdha dhe të vogla të alfabetit latin: a-z, A-Z.

Shifra dhjetore: 0-9.

Karaktere grafike: ! " # % & ' ( ) * + , - . / : ; < = > ? [ \ ] ^ _ { | } ~.

Hapësira të bardha: hapësirë, tab horizontal, tab vertikal, ushqim faqe, dhe rresht i ri.

Karakteri i rreshtit të ri (\n) përdoret për të treguar fundin e një rreshti teksti, edhe pse nuk përfaqëson gjithmonë një karakter të vetëm. Për përdoruesit që kanë nevojë për karaktere të koduara shumëbyte, standardi C11 lejon përdorimin e karaktereve Unicode me formatin \uXXXX ose \UXXXXXXXX.

Fjalët e Rezervuara

[Redakto | Redakto nëpërmjet kodit]

Fjalët e rezervuara në C janë fjalë kyçe që nuk mund të përdoren për qëllime të tjera. Standardi C89 përmban 32 fjalë të tilla. Këto përfshijnë fjalë si:

Kontrolli i fluksit: if, else, while, for, switch.

Deklarimi: int, char, struct, enum.

Të tjera: return, break, continue, goto.

Operatorët në C dhe C++

[Redakto | Redakto nëpërmjet kodit]

Gjuha C mbështet një grup të pasur operatorësh, të cilët janë simbole të përdorura brenda një shprehjeje për të specifikuar manipulimet që do të kryhen gjatë vlerësimit të saj. C ka operatorë për:

Aritmetikë: +, -, *, /, %

Përdoren për operacione bazë matematike si mbledhje, zbritje, shumëzim, pjesëtim dhe modulo (mbetja e pjesëtimit).

Caktim: =

Përdoret për të caktuar një vlerë një variabli.

Caktim i avancuar: +=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>=

Kombinojnë një operacion dhe caktimin në një operator të vetëm, p.sh., x += 5 është e barasvlershme me x = x + 5.

Logjikë bitwise: ~, &, |, ^

Kryejnë operacione logjike në nivel biti: negacion (~), AND (&), OR (|) dhe XOR (^).

Zhvendosje bitesh: <<, >>

Zhvendosin bitet e një variabli në të majtë ose në të djathtë.

Logjikë Boolean: !, &&, ||

Përdoren për operacione logjike si negacioni (!), AND logjik (&&) dhe OR logjik (||).

Vlerësim kushtor: ? :

Shprehja kushtore përdoret për të zgjedhur një vlerë bazuar në një kusht, p.sh., x = (a > b) ? a : b.

Testimi i barazisë: ==, !=

Kontrollojnë nëse dy vlera janë të barabarta (==) ose të ndryshme (!=).

Thirrja e funksioneve: ( )

Përdoret për të thirrur funksione dhe për të kaluar argumente.

Inkrementimi dhe dekrementimi: ++, --

Rrit ose ul një vlerë me 1, p.sh., x++ është e barasvlershme me x = x + 1.

Përzgjedhja e anëtarëve: ., ->

Përdoren për të aksesuar anëtarët e strukturave ose treguesve.

Madhësia e objektit: sizeof

Jep madhësinë në byte të një objekti ose tipi.

Lloji: typeof, typeof_unqual (shtuar në standardin C23)

Jep llojin e një shprehjeje ose variabli.

Relacione rendi: <, <=, >, >=

Krahasojnë dy vlera për të parë nëse njëra është më e vogël, më e vogël ose e barabartë, më e madhe, ose më e madhe ose e barabartë me tjetrën.

Referencimi dhe dereferencimi: &, *, [ ]

Operatorët & dhe * përdoren për të marrë adresën ose për të aksesuar vlerën e një treguesi. Kllapat katrore [ ] përdoren për akses në elementet e një vargu.

Lejon vlerësimin e shumë shprehjeve në rend, duke kthyer vlerën e shprehjes së fundit.

Grupimi i nënshprehjeve: ( )

[Redakto | Redakto nëpërmjet kodit]

Përdoren për të ndryshuar rendin e vlerësimit të operatorëve.

Konvertimi i llojit: (typename)

[Redakto | Redakto nëpërmjet kodit]

Përdoret për të kthyer një vlerë në një tip të caktuar.

Veçori dhe Kujdes i Veçantë në Përdorimin e Operatorëve

Në C, operatori = (i cili në matematikë përdoret për të treguar barazi) përdoret për caktimin e vlerave, duke ndjekur precedentin e gjuhëve si Fortran dhe PL/I. Për të testuar barazinë, përdoret operatori ==. Ngjashmëria mes këtyre operatorëve shpesh çon në gabime, si përdorimi i = në vend të ==. Për shembull, shprehja if (a = b + 1) në vend të if (a == b + 1) do të caktojë vlerën b + 1 te a dhe do të kthejë gjithmonë të vërtetë, përveçse nëse a bëhet 0.

Precedenca e operatorëve në C nuk është gjithmonë intuitive. Për shembull, operatori == ka precedencë më të lartë sesa operatorët & dhe |. Kështu, shprehja x & 1 == 0 duhet të shkruhet si (x & 1) == 0 për të shmangur konfuzionin dhe për të siguruar funksionalitetin e synuar.

Operatorët në C janë një komponent i fuqishëm dhe fleksibël, por kërkojnë kujdes gjatë përdorimit për të shmangur gabime të paqëllimshme

Shembulli "Hello, world"

Programi klasik "hello, world", i krijuar nga Brian Kernighan (1978), është bërë modeli bazë për programet hyrëse në shumicën e librave mësimorë të programimit. Ky program shtyp tekstin "hello, world" në daljen standarde, e cila zakonisht është terminali ose ekrani.

Versioni origjinal ishte:

main()

{

    printf("hello, world\n");

}

Një version që i përmbahet standardeve moderne është:

#include <stdio.h>

int main(void)

{

    printf("hello, world\n");

}

Shpjegimi i Kodit

Direktiva e Parapërpunimit (#include)

Rreshti i parë është një direktivë parapërpunimi e treguar nga #include. Kjo shkakton që kompajluesi ta zëvendësojë atë rresht me të gjithë tekstin e skedarit të kokës stdio.h, i cili përmban deklarata për funksione standarde si printf dhe scanf. Bracket-at këndorë < > tregojnë se ky skedar kërkohet nga biblioteka standarde e gjuhës C. Nëse përdoren thonjëzat " ", zakonisht do të përfshiheshin skedarë të vendosur lokalisht ose në projekte specifike.

Funksioni Kryesor (main)

[Redakto | Redakto nëpërmjet kodit]

Deklarata e funksionit:

Rreshti i dytë tregon që po definohet një funksion i quajtur main. Ky funksion ka një qëllim të veçantë në programet C: mjedisi i ekzekutimit e thërret atë për të nisur ekzekutimin e programit.

Specifikuesi i tipit:

Tipi int tregon se funksioni main kthen një vlerë të tipit integer (numër të plotë).

Lista e parametrave:

Fjala kyçe void si parametër nënkupton që funksioni nuk pranon argumente.

Hapja e Kllapave ( { )

Kllapa hapëse tregon fillimin e kodit që përcakton funksionin main.

Thirrja e funksionit:

Rreshti i tretë thërret funksionin printf, i cili vjen nga një bibliotekë standarde e sistemit.

Argumenti:

printf pranon një argument të vetëm, që është adresa e karakterit të parë të vargut literal "hello, world\n".

Vargu literal:

Ky varg është një varg anonim që përmban elemente të tipit char dhe përfundon me karakterin NULL (\0). Karakteri \n është një sekuencë shpëtimi që përfaqëson një rresht të ri në dalje.

Rezultati:

Funksioni printf kthen një vlerë të tipit int, e cila zakonisht përdoret për të kontrolluar suksesin e thirrjes, por në këtë rast nuk përdoret.

Mbyllja e Kllapave ( } )

Kllapa mbyllëse tregon fundin e kodit të funksionit main. Sipas specifikimit C99 dhe më të rinjve, funksioni main kthen automatikisht një vlerë 0 nëse nuk specifikohet ndryshe, duke treguar që programi është ekzekutuar me sukses.

Informacione të Shtuara

[Redakto | Redakto nëpërmjet kodit]

Standarde të Gjuhës C:

Programi i mësipërm përputhet me standardet moderne të gjuhës C (C99, C11 dhe C23).

Zbatimi në Praktikë:

Ky program është një hyrje ideale për të mësuar bazat e programimit, duke përfshirë strukturën e thjeshtë të një programi në C dhe përdorimin e bibliotekave standarde.

Kontrollimi i rezultatit të printf mund të jetë i dobishëm në programe më komplekse për të menaxhuar gabimet e mundshme në dalje.

Llojet e të Dhënave në C

[Redakto | Redakto nëpërmjet kodit]

Sistemi i tipeve në C është statik dhe dobët i tipizuar, duke e bërë atë të ngjashëm me sistemet e tipeve të gjuhëve si ALGOL dhe pasardhësit e tij, si Pascal. C përfshin tipe të ndërtuara në gjuhë për:

Numra të plotë (integer) të madhësive të ndryshme, si të nënshkruar (signed) ashtu edhe të panënshkruar (unsigned).

Numra me presje të lëvizshme (floating-point).

Tipe të enumëruara (enum).

Tipi char përdoret zakonisht për karaktere me një bajt të vetëm.

C99 shtoi një tip të dhënash për logjikën Booleane (_Bool).

Gjithashtu, C mbështet tipe të prejardhura si:

Vargjet (arrays),

Pointerat,

Strukturat (struct),

Unionet (union).

C shpesh përdoret për programim në nivele të ulëta, ku mund të jetë e nevojshme shmangia e kufizimeve të sistemit të tipeve. Kompajluesi përpiqet të sigurojë saktësinë e tipeve në shumicën e shprehjeve, por programuesi mund të anashkalojë këto kontrolle duke:

Përdorur kastimin e tipit (type casting) për të konvertuar një vlerë nga një tip në një tjetër.

Përdorur pointera ose unione për të interpretuar bitet bazë të një objekti si një tip tjetër.

Megjithatë, disa e konsiderojnë sintaksën e deklarimeve në C si jo intuitive, veçanërisht për pointerët e funksioneve. Ideja e Dennis Ritchie ishte që deklarimet të pasqyrojnë përdorimin e tyre: "deklarata reflekton përdorimin".

Konvertimet Aritmetike në C

[Redakto | Redakto nëpërmjet kodit]

Konvertimet aritmetike në C lejojnë gjenerimin e kodit efikas, por ndonjëherë prodhojnë rezultate të papritura. Për shembull, një krahasim midis numrave të nënshkruar dhe të panënshkruar me të njëjtën gjerësi kërkon konvertimin e vlerës së nënshkruar në të panënshkruar, gjë që mund të shkaktojë sjellje të papritura nëse vlera e nënshkruar është negative.

Pointerat janë një tip referimi që regjistron adresën ose vendndodhjen e një objekti ose funksioni në memorje. Nëpërmjet pointerave mund të:

Hynë të dhënat që ndodhen në adresën ku tregojnë pointerat.

Thirren funksionet të cilave pointerat u tregojnë.

Përdorimi dhe Karakteristikat

Manipulimi i Pointerave:
[Redakto | Redakto nëpërmjet kodit]

Pointerat mund të manipulohen nëpërmjet:

Atribuimeve (p.sh., ptr = &var;),

Aritmetikës së Pointerave, e cila shkallëzohet automatikisht sipas madhësisë së tipit të të dhënave që tregojnë.

Përdorimet Kryesore:
[Redakto | Redakto nëpërmjet kodit]

Manipulimi i vargjeve të tekstit nëpërmjet pointerave në vargrrat e karaktereve.

Alokimi dinamik i memorjes me malloc, ku rezultati zakonisht kthehet në tipin e të dhënave përkatëse.

Implementimi i strukturave të dhënash si drunjtë dhe listat e lidhura, duke përdorur pointera për të lidhur objektet struct.

Përdorimi i pointerave të funksioneve për të kaluar funksione si argumente në funksione të tjera (si qsort ose bsearch) ose si "callback".

Një pointer null tregon që nuk ka një vendndodhje të vlefshme. Përpjekja për të hyrë në një adresë null është e papërcaktuar dhe shpesh çon në gabime si segmentation fault.

Pointerat null përdoren për të treguar raste të veçanta, si për shembull fundi i një liste të lidhur ose si tregues i gabimit në funksionet që kthejnë pointera.

Në burim, një pointer null mund të shkruhet si 0, si makroja NULL, ose në C23 me konstanten nullptr. Në kontekste kushtëzuese, vlera null vlerësohet si false, ndërsa të gjitha vlerat e tjera pointer janë true.

Pointerat të tipit void * tregojnë objekte me tip të paspecifikuar dhe përdoren si pointera të përgjithshëm.

Pointerat void * nuk mund të dereferencohen dhe as të përdoren në aritmetikën e pointerave, por mund të konvertohen lehtësisht në çdo tip tjetër pointerash.

Rreziqet dhe Kufizimet
[Redakto | Redakto nëpërmjet kodit]

Përdorimi i pakujdesshëm i pointerave mund të jetë i rrezikshëm, sepse:

Pointerat mund të tregojnë vende të parrezikshme nëse manipulohen gabimisht.

Pointerat e keqmenaxhuar mund të çojnë në:

Pointera që varen në memorje të liruar (dangling pointers).

Pointera të pa inicializuar (wild pointers).

Vlera të pasigurta të dhëna për pointera nëpërmjet kastimit, unionit ose pointerave të korruptuar.

Gjuhët e tjera të programimit shpesh përdorin referenca më kufizuese për të shmangur këto probleme. Në C, kompajluesit ofrojnë opsione për të aktivizuar kontrollet për sigurinë e pointerave, por mbetet përgjegjësi e programuesit të sigurojë përdorimin korrekt të tyre.

Përkufizimi dhe Përdorimi

[Redakto | Redakto nëpërmjet kodit]

Vargrrat në C zakonisht janë me madhësi të fiksuar dhe të specifikuar gjatë kohës së përpilimit (compile time). Standardi C99 prezanton gjithashtu një formë të vargrrave me gjatësi të ndryshueshme (variable-length arrays - VLA). Megjithatë, është gjithashtu e mundur që një bllok memorje me madhësi të përcaktuar në kohën e ekzekutimit (runtime) të alokohet duke përdorur funksionin malloc nga biblioteka standarde dhe të trajtohet si një varg.

Qasja dhe Kufizimet

[Redakto | Redakto nëpërmjet kodit]

Pasi qasja në vargje bëhet nëpërmjet pointerave, zakonisht nuk kryhet kontroll i kufijve të vargut nga kompajluesi. Kjo mund të çojë në:

Shkelje të kufijve të vargjeve (array bounds violations),

Qasje ilegale në memorje,

Korrupsion të të dhënave,

Rrjedhje të tamponit (buffer overruns),

Përjashtime gjatë ekzekutimit (runtime exceptions).

Disa kompajlues ofrojnë kontroll të kufijve si opsion për të adresuar këto probleme.

Vargjet Shumëdimensionale

[Redakto | Redakto nëpërmjet kodit]

C nuk ka një strukturë të veçantë për deklarimin e vargrrave shumëdimensionale. Në vend të kësaj, përdoret rekursioni brenda sistemit të tipeve për të krijuar varg vargjesh, që praktikisht kryen të njëjtën funksion.

Vlerat e indekseve në një varg shumëdimensional mund të mendohen si rritje sipas radhës së rreshtave (row-major order). Vargjet shumëdimensionale përdoren shpesh në algoritme numerike, sidomos në algebrën lineare, për të ruajtur matrica.

Në versionet e hershme të C, kufijtë e vargjeve duhej të ishin vlera fikse ose të kaloheshin manualisht te çdo funksion që i përdorte. Vargjet me gjatësi të ndryshueshme të prezantuara në C99 adresojnë këtë kufizim.

Shembull me Vargje Shumëdimensionale

Alokimi në Heap (C99 ose më vonë):

int func(int N, int M)

{

    float (*p)[N][M] = malloc(sizeof *p);

    if (p == 0)

        return -1; // Kontrollo alokimin

    for (int i = 0; i < N; i++)

        for (int j = 0; j < M; j++)

            (*p)[i][j] = i + j;

    print_array(N, M, p);

    free(p); // Çlirim i memorjes

    return 1;

}

Përdorimi i VLA (Auto):

int func(int N, int M)

{

    float p[N][M]; // Varg dinamik në stack

    for (int i = 0; i < N; i++)

        for (int j = 0; j < M; j++)

            p[i][j] = i + j;

    print_array(N, M, p);

    return 1; // Nuk ka nevojë për free()

}

Kujdes: Kur përdorni VLAs, sigurohuni që madhësia e vargut të mos tejkalojë kapacitetin e stack-ut të programit.

Shkëmbimi midis Vargjeve dhe Pointerave

[Redakto | Redakto nëpërmjet kodit]

Në C, notacioni i indeksimit x[i] (ku x është një pointer) është një shkurtesë sintaksore për *(x + i). Kompajluesi, duke njohur tipin e pointerit, llogarit adresën duke shtuar i të shumëzuar me madhësinë e një elementi që tregon x. Kështu, x[i] tregon elementin e (i+1)-të të vargut.

Konvertimi Automatik

[Redakto | Redakto nëpërmjet kodit]

Në shumicën e konteksteve të shprehjeve (përjashtim notable: operand i sizeof), një shprehje e tipit varg konvertohet automatikisht në një pointer te elementi i parë të vargut. Kjo nënkupton:

Kalimi i vargjeve te funksionet: Kur një varg kalon si argument, nuk kopjohet e gjithë përmbajtja, por vetëm adresa e elementit të parë. Kjo i bën vargjet efektivisht të kalohen si referencë, ndonëse funksionet në C përdorin semantikën pass-by-value.

Madhësia e Vargut

[Redakto | Redakto nëpërmjet kodit]

Madhësia totale e një vargu x mund të përcaktohet duke përdorur sizeof mbi një shprehje të tipit varg. Për shembull:

size_t total_size = sizeof A; // Madhësia totale e vargut

size_t element_size = sizeof A[0]; // Madhësia e një elementi

size_t num_elements = sizeof A / sizeof A[0]; // Numri i elementeve

Shënim: Nëse vetëm një pointer drejt elementit të parë është në dispozicion (siç ndodh shpesh në kodin C), informacioni mbi tipin e plotë dhe gjatësinë e vargut humbet.

Menaxhimi i memories

[Redakto | Redakto nëpërmjet kodit]

Një nga funksionet më të rëndësishme të një gjuhe programimi është ofrimi i mjeteve për menaxhimin e memories dhe objekteve që ruhen në të. Gjuha C ofron tre mënyra kryesore për alokimin e memories për objektet:

Alokimi statik i memories: Hapësira për objektin sigurohet në binarin e krijuar gjatë kohës së përpilimit; këto objekte kanë një shtrirje (ose jetëgjatësi) aq sa binari që i përmban është i ngarkuar në memorie.

Alokimi automatik i memories: Objektet e përkohshme mund të ruhen në stack, dhe kjo hapësirë lirohet dhe bëhet e ripërdorshme automatikisht pasi blloku ku janë deklaruar del nga ekzekutimi.

Alokimi dinamik i memories: Blloqe memoriesh me madhësi të ndryshme mund të kërkohen gjatë kohës së ekzekutimit duke përdorur funksione të bibliotekës, si p.sh. malloc, nga një rajon memoriesh i quajtur heap. Këto blloqe vazhdojnë të ekzistojnë derisa të lirohen manualisht për ripërdorim duke thirrur funksionet realloc ose free.

Këto tre qasje janë të përshtatshme në situata të ndryshme dhe kanë kompromiset e tyre. Për shembull:

Alokimi statik ka shumë pak ngarkesë për alokim.

Alokimi automatik mund të ketë një ngarkesë pak më të madhe.

Alokimi dinamik mund të ketë ngarkesë të konsiderueshme si gjatë alokimit, ashtu edhe gjatë çalokimit.

Objektet statike janë të dobishme për ruajtjen e informacionit të gjendjes midis thirrjeve të funksioneve. Alokimi automatik është i thjeshtë për t'u përdorur, por hapësira e stack-ut është zakonisht shumë më e kufizuar dhe kalimtare në krahasim me hapësirën statike ose atë të heap-it. Alokimi dinamik, nga ana tjetër, lejon krijimin e objekteve me madhësi të panjohur deri në kohën e ekzekutimit. Shumica e programeve në C përdorin gjerësisht të treja këto qasje.

Kur është e mundur, alokimi automatik ose statik është zakonisht më i thjeshti, pasi menaxhohet nga kompileri, duke i hequr programuesit detyrën e mundimshme dhe të prirur ndaj gabimeve për alokimin dhe lirimin manual të memories. Sidoqoftë, shumë struktura të dhënash ndryshojnë madhësinë gjatë kohës së ekzekutimit, dhe meqë alokimet statike (dhe ato automatike para standardit C99) duhet të kenë një madhësi fikse gjatë përpilimit, ka shumë situata ku është e nevojshme alokimi dinamik. Para standardit C99, tabelat me madhësi të ndryshueshme ishin një shembull i zakonshëm për këtë.

Ndryshe nga alokimi automatik, i cili mund të dështojë gjatë ekzekutimit me pasoja të pakontrolluara, funksionet e alokimit dinamik kthejnë një tregues null (null pointer) kur hapësira e kërkuar nuk mund të alokohet. (Alokimi statik që është shumë i madh zakonisht zbulohet nga lidhësi ose loader-i përpara se programi të fillojë ekzekutimin.)

Nëse nuk specifikohet ndryshe, objektet statike përmbajnë zero ose tregues null gjatë nisjes së programit. Objektet e alokuara automatikisht dhe në mënyrë dinamike inicializohen vetëm nëse u jepet një vlerë fillestare; përndryshe, ato fillimisht kanë vlera të papërcaktuara (zakonisht, çfarëdo modeli bitesh që ndodhet në hapësirën e memories, e cila mund të mos përfaqësojë as një vlerë të vlefshme për atë lloj). Nëse programi përpiqet të aksesojë një vlerë të painicializuar, rezultatet janë të paparashikueshme. Shumë kompilerë modernë përpiqen ta zbulojnë dhe të paralajmërojnë për këtë problem, por mund të ndodhin si pozitive të rreme, ashtu edhe negative të rreme.

Alokimi i memories në heap duhet të sinkronizohet me përdorimin aktual të saj në program për t'u ripërdorur sa më shumë të jetë e mundur. Për shembull:

Nëse treguesi i vetëm drejt një alokimi në heap del jashtë kuadrit të vet ose mbivendoset përpara se të çlirohet manualisht, atëherë ajo hapësirë memorieje nuk mund të rikuperohet më për përdorim të mëvonshëm dhe humbet për programin. Ky fenomen njihet si rrjedhje memorieje (memory leak).

Në të kundërt, është e mundur që hapësira të lirohet dhe më pas të referohet përsëri, duke çuar në rezultate të paparashikueshme.

Zakonisht, simptomat e dështimit shfaqen në një pjesë të programit që nuk lidhet drejtpërdrejt me kodin që shkakton gabimin, gjë që e bën të vështirë diagnostikimin. Këto çështje lehtësohen në gjuhët që kanë mbledhje automatike të plehrave (automatic garbage collection).

Gjuha e programimit C përdor bibliotekat si metodën kryesore të zgjerimit të saj. Në C, një bibliotekë është një grup funksionesh të përfshira brenda një file të vetme "arkive". Çdo bibliotekë zakonisht ka një file header, i cili përmban prototipet e funksioneve të përfshira brenda bibliotekës që mund të përdoren nga një program, si dhe deklarimet e tipeve të veçanta të të dhënave dhe simboleve makro të përdorura me këto funksione. Për të përdorur një bibliotekë, një program duhet të përfshijë file-in header të bibliotekës dhe biblioteka duhet të lidhet me programin, gjë që në shumë raste kërkon përdorimin e flamujve të kompilerit (p.sh., -lm, një shkurtim për "lidh bibliotekën matematikore").

Biblioteka më e zakonshme në C është biblioteka standarde C, e cila specifikohet nga standardet ISO dhe ANSI C dhe është e përfshirë në çdo implementim të C-së (implementimet që synojnë mjedise të kufizuara si sistemet e ngulitura mund të ofrojnë vetëm një nën-pjesë të bibliotekës standarde). Kjo bibliotekë mbështet hyrje dhe dalje me rrjedha, alokimin e memories, matematikën, vargjet e karaktereve dhe vlerat kohore. Disa header-a të veçantë standardë (p.sh., stdio.h) specifikojnë ndërfaqet për këto dhe lehtësira të tjera të bibliotekës standarde.

Një grup tjetër i zakonshëm funksionesh të bibliotekës në C janë ato që përdoren nga aplikacionet specifikisht të targetuara për sistemet Unix dhe ato të ngjashme me Unix, veçanërisht funksionet që ofrojnë një ndërfaqe me kernel-in. Këto funksione janë të detajuara në standarde të ndryshme, si POSIX dhe Single UNIX Specification.

Duke qenë se shumë programe janë shkruar në C, ekziston një shumëllojshmëri e gjerë bibliotekash të tjera të disponueshme. Bibliotekat shpesh shkruhen në C sepse kompilerët e C-së gjenerojnë kod objekti shumë efikas; më pas, programuesit krijojnë ndërfaqe për bibliotekat në mënyrë që rutinat e tyre të mund të përdoren nga gjuhë më të nivelit të lartë si Java, Perl dhe Python.

Mjetet dhe përdorimi i gjuhës C

[Redakto | Redakto nëpërmjet kodit]

Mjetet për gjetjen dhe korrigjimin e gabimeve

[Redakto | Redakto nëpërmjet kodit]

Një numër mjetesh janë zhvilluar për të ndihmuar programuesit e C-së të zbulojnë dhe korrigjojnë deklaratat me sjellje të papërcaktuar ose shprehje potencialisht të gabuara, duke ofruar një rigorozitet më të madh sesa ai i ofruar nga kompileri. Mjeti lint ishte i pari në këtë drejtim, duke i hapur rrugën shumë mjeteve të tjera.

Kontrollimi dhe auditimi i automatizuar i kodit burimor është i dobishëm në çdo gjuhë programimi, dhe për gjuhën C ekzistojnë shumë mjete të tilla, si p.sh. Lint. Praktika e zakonshme është përdorimi i Lint për të zbuluar kod të dyshimtë kur një program shkruhet për herë të parë. Pasi programi kalon testimin me Lint, ai përpilohet duke përdorur kompiluesin e C-së. Gjithashtu, shumë kompilerë mund të ofrojnë opsionalisht paralajmërime për konstrukte sintaksisht të vlefshme që me shumë gjasa janë gabime.

MISRA C është një grup udhëzimesh të pronësuara për të shmangur kodin e dyshimtë, i zhvilluar për sistemet e ngulitura.

Gjithashtu, ekzistojnë kompilerë, biblioteka dhe mekanizma në nivel sistemi operativ për kryerjen e veprimeve që nuk janë pjesë standarde e gjuhës C, si kontrolli i kufijve të tabelave, zbulimi i mbingarkesës së buferit, serializimi, ndjekja dinamike e memories dhe mbledhja automatike e plehrave.

Mjete si Purify ose Valgrind dhe lidhja me biblioteka që përmbajnë versione speciale të funksioneve të alokimit të memories mund të ndihmojnë në zbulimin e gabimeve gjatë kohës së ekzekutimit në përdorimin e memories.

Përdorimi i gjuhës C

[Redakto | Redakto nëpërmjet kodit]

Arsyet për përdorim në programimin e sistemeve

[Redakto | Redakto nëpërmjet kodit]

Gjuha C përdoret gjerësisht për programimin e sistemeve, veçanërisht për zbatimin e sistemeve operative dhe aplikacioneve të sistemeve të ngulitura. Kjo ndodh për disa arsye:

Qasje në hardware dhe memorie: Gjuha C lejon qasjen në harduerin dhe memorien e platformës duke përdorur tregues dhe manipulime të tipeve, kështu që veçoritë specifike të sistemit (p.sh., regjistrat e kontrollit/statusit, regjistrat I/O) mund të konfigurohen dhe përdoren përmes kodit të shkruar në C.

Thjeshtësia e ekzekutimit: Kodi i gjeneruar pas përpilimit nuk kërkon shumë veçori të sistemit dhe mund të thirret lehtësisht nga kodet fillestare të nisjes.

Efikasiteti: Deklaratat dhe shprehjet e gjuhës C zakonisht përkthehen mirë në sekuenca të udhëzimeve për procesorin e synuar, duke ulur kërkesat për burimet e sistemit dhe duke siguruar ekzekutim të shpejtë.

Përshtatshmëria për CPU-të specifike: Me setin e saj të pasur të operatorëve, gjuha C mund të përdorë shumë nga veçoritë e CPU-ve të synuara. Për CPU-të me udhëzime të veçanta, mund të krijohet një variant i gjuhës që shfrytëzon funksione të brendshme për të përfituar nga ato udhëzime.

Manipulimi i strukturave binare: C e bën të lehtë mbivendosjen e strukturave mbi blloqe të dhënash binare, duke lejuar navigimin dhe modifikimin e tyre – e bën të mundur ndërtimin e strukturave të dhënash dhe sistemeve të file-ve.

Operatorë të fuqishëm: Gjuha ofron operatorë për manipulimin e biteve, aritmetikën me numra të plotë dhe logjikën, si dhe tipe të ndryshme të numrave me presje të lëvizshme, duke lejuar përpunimin efektiv të të dhënave të strukturuara në mënyrë të përshtatshme.

Thjeshtësia: C është një gjuhë relativisht e vogël, me vetëm një numër të kufizuar deklaratash dhe pa shumë veçori që gjenerojnë kod të zgjeruar, gjë që e bën të kuptueshme.

Kontroll mbi menaxhimin e memories: C ofron kontroll të drejtpërdrejtë mbi alokimin dhe çalokimin e memories, duke ofruar efikasitet të arsyeshëm dhe kohëzgjatje të parashikueshme për operacionet mbi memorien.

Sistem fleksibël për alokimin e memories: C lejon përdorimin dhe zbatimin e skemave të ndryshme të alokimit të memories, duke përfshirë mekanizma si malloc dhe free, mekanizma më të sofistikuar me zona specifike, ose versione për kernel-in e OS që mund të përshtaten për DMA, përdorim brenda trajtuesve të ndërprerjeve ose integrim me sistemin e memories virtuale.

Ndërveprueshmëria: Kodi C mund të thërrasë biblioteka të shkruara në gjuhën assembler dhe mund të thirret nga kodi assembler. Po ashtu, konventat e thirrjes dhe strukturat e lidhësit (linker) të C-së mundësojnë ndërveprimin me gjuhë të tjera të nivelit të lartë.

Ekosistemi i zhvilluar: Gjuha C ka një ekosistem të pjekur dhe të gjerë që përfshin biblioteka, korniza, kompilues me burim të hapur, mjete debug-uese dhe utilitare, duke qenë standardi de facto. Për më tepër, shumica e drajverëve dhe mjeteve ekzistojnë tashmë në C ose për CPU të ngjashme, duke ulur motivimin për të zgjedhur një gjuhë tjetër.

Përdorimi i gjuhës C për biblioteka me intensitet të lartë llogaritjeje

[Redakto | Redakto nëpërmjet kodit]

Gjuha C mundëson programuesit të krijojnë zbatime efikase të algoritmeve dhe strukturave të të dhënave, për shkak të shtresës së hollë të abstraksionit nga hardueri dhe mbingarkesës së saj të ulët, një kriter i rëndësishëm për programet me kërkesa të larta llogaritjeje. Për shembull, GNU Multiple Precision Arithmetic Library, GNU Scientific Library, Mathematica, dhe MATLAB janë të shkruara tërësisht ose pjesërisht në C. Shumë gjuhë mbështesin thirrjen e funksioneve të bibliotekave në C, për shembull, korniza e bazuar në Python, NumPy, përdor C për aspektet me performancë të lartë dhe ato që ndërveprojnë me harduerin.

C si gjuhë ndërmjetëse

[Redakto | Redakto nëpërmjet kodit]

C përdoret ndonjëherë si gjuhë ndërmjetëse nga implementimet e gjuhëve të tjera. Ky qasje mund të përdoret për portabilitet ose komoditet; duke përdorur C si një gjuhë ndërmjetëse, nuk është e nevojshme të krijohen gjeneratorë shtesë për kod të veçantë për platforma. Gjuha C përmban disa veçori, si direktivat e paraprocesorit me numra linjash dhe presjet opsionale në fund të listave inicializuese, që mbështesin përpilimin e kodit të gjeneruar.

Megjithatë, disa mangësi të C-së kanë nxitur zhvillimin e gjuhëve të tjera të bazuara në C, të dizajnuara posaçërisht për përdorim si gjuhë ndërmjetëse, si p.sh. C--. Për më tepër, përpiluesit bashkëkohorë kryesorë si GCC dhe LLVM përdorin një përfaqësim ndërmjetës që nuk është C, dhe këta përpilues mbështesin gjuhë front-end të ndryshme, përfshirë edhe C-në.

Gjuhët e tjera të shkruara në C

[Redakto | Redakto nëpërmjet kodit]

Një pasojë e disponueshmërisë dhe efikasitetit të gjerë të C-së është se përpiluesit, bibliotekat dhe interpretuesit e gjuhëve të tjera të programimit shpesh janë implementuar në C. Për shembull, implementimet referencë të Python, Perl, Ruby, dhe PHP janë të gjitha të shkruara në C.

Përdorimi historik për zhvillim në ueb

[Redakto | Redakto nëpërmjet kodit]

Historikisht, C është përdorur ndonjëherë për zhvillimin në ueb duke përdorur Common Gateway Interface (CGI) si një "portë" për shkëmbimin e informacionit ndërmjet aplikacionit të uebit, serverit dhe shfletuesit. C mund të jetë zgjedhur mbi gjuhët e interpretuara për shkak të shpejtësisë, stabilitetit dhe disponueshmërisë së saj pothuajse universale. Sot, kjo praktikë nuk është më e zakonshme, dhe ekzistojnë shumë mjete të tjera për zhvillimin në ueb.

Serverët e uebit

[Redakto | Redakto nëpërmjet kodit]

Dy serverët më të njohur të uebit, Apache HTTP Server dhe Nginx, janë të dyja të shkruara në C. Këta serverë ndërveprojnë me sistemin operativ, dëgjojnë në portet TCP për kërkesa HTTP dhe shërbejnë përmbajtje statike ose shkaktojnë ekzekutimin e gjuhëve të tjera për të "renderuar" përmbajtjen, si p.sh. PHP, e cila vetë është kryesisht e shkruar në C. Qasja e afërt e C-së me harduerin mundëson ndërtimin e këtyre sistemeve me performancë të lartë.

Aplikacionet për përdoruesit fundorë

[Redakto | Redakto nëpërmjet kodit]

C është përdorur gjerësisht për të implementuar aplikacione për përdoruesit fundorë. Megjithatë, aplikacione të tilla mund të shkruhen gjithashtu në gjuhë më të reja dhe me nivel më të lartë.

Kufizimet e gjuhës C

[Redakto | Redakto nëpërmjet kodit]

Pavarësisht popullaritetit dhe suksesit të saj të madh, gjuha C ka disa mangësi:

Menaxhimi i memories: Përdorimi i funksioneve standarde si malloc dhe free është i prirur ndaj gabimeve, si rrjedhje e memories kur memoria alokohet, por nuk çlirohet; dhe qasja në memorien që tashmë është çliruar.

Përdorimi i treguesve: Manipulimi i drejtpërdrejtë i memories e bën të mundur korruptimin e memories, për shkak të gabimeve të programuesit ose mungesës së verifikimit të të dhënave të këqija.

Dobësitë në kontrollin e tipeve: Ekziston një kontroll i kufizuar i tipeve, që nuk zbatohet për funksionet variadike dhe mund të anashkalohet lehtësisht.

Mbingarkesa mbi programuesin: Kodi i gjeneruar nga kompileri përmban pak kontrolle, duke ngarkuar programuesin me përgjegjësinë për të trajtuar të gjitha rezultatet e mundshme, për të mbrojtur kundër mbikalimeve të buferit, kontrollit të kufijve të tabelave, mbingarkesës së stekës, dhe situatave konkurruese.

Mangësitë në optimizime: Përdorimi i treguesve dhe manipulimi i tyre në kohën e ekzekutimit krijon mundësi për qasje të njëkohshme në të njëjtat të dhëna (aliasing), gjë që kufizon optimizimet e mundshme.

Për të reduktuar këto kufizime, janë zhvilluar versione të kufizuara të C-së, si MISRA C ose CERT C, dhe mjete të ndryshme për analizë statike dhe zbulim të gabimeve gjatë përpilimit.

Lidhjet e gjuhës C me gjuhët e tjera programuese

[Redakto | Redakto nëpërmjet kodit]

Gjuha C ka pasur një ndikim të madh në zhvillimin e shumë gjuhëve të tjera programuese, duke shërbyer si bazë ose frymëzim për një gamë të gjerë gjuhësh moderne. Shumë gjuhë që u krijuan më vonë huazuan drejtpërdrejt ose tërthorazi struktura kontrolli, sintaksë dhe koncepte nga C, duke përfshirë:

C++ – Një zgjerim i drejtpërdrejtë i C, i cili shton konceptet e orientimit në objekte, polimorfizmit dhe trashëgimisë.

C# – Një gjuhë e zhvilluar nga Microsoft me ndikim nga C dhe C++, e orientuar drejt platformës .NET.

Java – Huazon sintaksën nga C, por është më strikte në tipizim dhe ofron mbledhje automatike të mbeturinave (garbage collection).

JavaScript – Një gjuhë për zhvillimin e aplikacioneve web me sintaksë të ngjashme me C, e përdorur gjerësisht për front-end dhe back-end.

Python dhe Ruby – Gjuhë të nivelit të lartë, të cilat kanë adoptuar strukturat e kontrollit dhe qartësinë e sintaksës së C, por me një fokus më të madh te thjeshtësia dhe lexueshmëria.

PHP dhe Perl – Gjuhë skriptimi të fuqishme për zhvillimin e aplikacioneve web dhe automatizimin e proceseve, me ndikime të dukshme nga C.

Rust dhe Go – Gjuhë moderne që kombinojnë fuqinë dhe kontrollin e C me siguri më të lartë dhe një menaxhim më të mirë të kujtesës.

Objective-C – Një zgjerim i C që shton funksionalitetet e orientimit në objekte, përdorur historikisht për zhvillimin e aplikacioneve për macOS dhe iOS.

Swift – Pasardhës i Objective-C, por më modern dhe më i thjeshtë për përdoruesit, gjithashtu me ndikim nga C.

Verilog dhe SystemVerilog – Gjuhë për përshkrimin e hardware-it (HDL), të cilat kanë adoptuar elemente të sintaksës së C për të lehtësuar modelimin e sistemeve digjitale.

Elementet e përbashkëta:

Sintaksa e ngjashme: Shumë nga këto gjuhë përdorin të njëjtat struktura kontrolli si if, for, while, dhe mënyra të ngjashme për deklarimin e variablave dhe funksioneve.

Operatorët: Operatorët si +, -, *, &&, dhe || janë pothuajse identikë në shumicën e këtyre gjuhëve.

Bllokimi me kllapa: Grupimi i deklaratave me kllapa kurrizore {} është një veçori e përbashkët që buron nga C.

Edhe pse shumë nga këto gjuhë kanë tipare dhe modele të të dhënave që ndryshojnë ndjeshëm nga C, ato vazhdojnë të ruajnë një shije të njohur të sintaksës së saj, duke e bërë të lehtë për programuesit me përvojë në C të kalojnë në gjuhë të tjera.

Ndikimi i C në gjuhët e tjera është i pakrahasueshëm, duke krijuar një familje të gjerë gjuhësh që e kanë bërë programimin më të qasshëm, të fuqishëm dhe të gjithanshëm në fusha të ndryshme, nga zhvillimi i aplikacioneve deri te sistemet e ngulitura dhe dizajni i hardware-it.

Lidhje të jashtme

[Redakto | Redakto nëpërmjet kodit]