C nasıl, başlangıç, programlama, yeni başlayanlar için...

Başlatan Veli B., 09 Haziran 2011, 12:46:35

Veli B.

Bu makale/yazıyı hazırlayan Bunalmış Üstad' a ve emeği geçen arkadaşlara teşekkür ederim.

Alıntı yapılan: bunalmis - 08 Haziran 2011, 16:01:21
Eger C ye henuz giris yapiyorsaniz Borland TC 3.0 yuklemenizi oneririm. Simdiki isletim sistemlerinde calisir mi bilemem.

Bununla dogrudan PC uzerinde pratik yapabilirsiniz. C yi mikrolar uzerinde ogrenmek bence dogru değil. Programi derle flasa yukle vs vs
ayak bagi olacak cok sey var. TC ile pratik yaptiktan sonra mikrolarla calismaya gecebilirsiniz.

Sonuclari printf ile ekrana basip cok hizli yaz bozlar yaparak ogrendiklerinizi kendi kendinize test edebilirsiniz.

Alıntı yapılan: Analyzer - 08 Haziran 2011, 16:05:25
Selam,

Ben de TC++ 3.0 ile C++ öğrenenlerdenim. O zamanlar Windows 98 ve Ms-Dos vardı. İkisi de tarih oldu tabi. Ancak ben de OOP arayüzlerine ve mcu'larda C dilini öğrenmeye karşıyım, kullanmaya değil tabi.

Analyzer

Alıntı yapılan: MC_Skywalker - 08 Haziran 2011, 16:06:54
Turbo C++ 3.0 msdos 6.22 üzerinde ilk C öğrenme çablarım geldi aklıma

şu adresten download edebilirsiniz
http://www.bestfreewaredownload.com/freeware/t-free-turbo-c--freeware-flggsdpz.html

Şu adrestende 64bit vista win 7 üzerine nasıl kuracağınız hakkında bilgi alabilirsiniz
http://blog.bestsoftware4download.com/2010/02/how-to-install-turbo-c-on-windows-7-64bit/

Şimdi  Basic le mukayese edeceğim de hangi Basic ile sorusu muamma. Bir Basic'deki yapı bir diğer Basic'dekine uymayabilir.
Genede Basic Basic'dir Benim Basic kurallarimla  ilgili yazacaklarıma itiraz etmeden kabul ederseniz dallanmaya gerek kalmaz.

Basic de programımız, ilk satırdan itibaren işletilir.
C de programımız void main(void) benzeri kisacasi main yazan bolgeden itibaren.

Soyle de dusunebilirsiniz.

Basicde Main satiri 1. satirdir.
Eger kodlarimiz 1. satirdan itibaren değil de etiketi Basla olan satirdan itibaren baslasin istersek

ilk satira goto Basla yazariz.

C de boyle bir seye gerek yok.

void main(void)
{
}

gibi bir satiri programin neresine yazarsaniz yazin Programin baslayacagi yer
iste bu main olan satirin oldugu bolgedir. Bolgedir dedim satir demedim. Neden satir demiyorum sonra anlayacaksiniz.

Basic de Komut sonlarini : ile sonlandiririz.

C de komut sonlarini ; ile sonlandiririz.

Basicde ayni satira birden fazla kod yazmayacaksak en saga: koymak zorunda değiliz.
C de her komutun sonuna ; koymak zorundayiz.

Ornegin

Basic de A=A+1: B=B+1 Burada A=A+1 sonunda : sart, fakat B=B+1 sonunda : sart değil
C de a=a+1; b=b+1; Burada ; kullanmak sart

C de isimlendirmelerde kucuk harf tercih edilir. Basic de ise genellikle buyuk harf.
Fakat bu sadece bir tercih, zorunluluk değil.

Basicde herhangi bir satirin isletilmesini istemiyorsak satirin basina REM yada ' yazariz.
C herhangi bir satirin isletilmesini istemiyorsak satirin basina // yazariz.

Alt alta 3 satiri iptal edelim.

REM Basicde burasi iptal edilen 1.satir
REM Basicde burasi iptal edilen 2.satir
REM Basicde burasi iptal edilen 3.satir

// C de burasi iptal edilen 1.satir
// C de burasi iptal edilen 2.satir
// C de burasi iptal edilen 3.satir

Asagida C nin bir kolayligi var. /*  ve */ arasinda ne var ne yok hepsi iptal olunur.

/*
C de burasi iptal edilen 1.satir
C de burasi iptal edilen 2.satir
C de burasi iptal edilen 3.satir
*/

Simdilik  bukadar. Bu yazi gibi en fazla 3 yazi daha yazarsam tum BASIC kullanicilari artik C ile yazmaya baslayabilir.
Yukaridaki bilgicikler cok fazla değil. Bunlari anlamadan bu yaziya gecmeyin.

Basicde array tanimlamalari haric hic bir degisken tanimlamasi yapmadan programi paldir kuldur yazmaya baslayabilirsiniz. Gerci bu, kullanilan Basic e gore degisiklik gosterse de bosverin dedigim gibi olsun.

Ornegin Basicde daha ilk satira A=A+1 yazabilirsiniz.

C de muhakkak kullanilacak degiskenler tek tek tanimlanmalidir.

Burada onemli bir noktaya geldik. C de degiskenler nasil tanimlanir?

Ayrintiya girmeden Global degiskenler ve Lokal degiskenler seklinde 2 degisken tanimlama sansimiz oldugunu kabul edin.

Bu konuyu izah etmekte zorlanacagim cunku C de fonksiyon denen kavramdan henuz haberdar değiliz.
Fakat global degiskenleri hemen aciklayayim.

Basic de A=A+1 gibi bir satir yazdigimizda A ve B global iki ayri  degiskendir.
Hangi satirda yada Gosubla gidilen hangi alt satirda A ve B derseniz deyin hep ayni A ve B degiskeninden bahsedilir.

BASIC de


GOSUB MAIN ' Burasi basic programimizin ilk baslayacagi satir
END

MAIN:
A=1
GOSUB HESAPLA
PRINT B
RETURN

HESAPLA:
B=A
RETURN

gibi bir program parcasi dusunelim.

Buradaki A ve B Global iki degiskendir.

C de ayni islemi su sekilde yazariz. (Diyelimki A ve B 16 bit integer degisken)

//Burasi C programimizin en tepesi


int a;  // a degiskeni integerdir.
int b;  // b degiskeni integerdir.
// int a,b;   istersek boyle de yazarark a ve b nin integer oldugunu bildirebilirdik.

void hesapla(void)
{
    b=a;
}

void main(void)
{
     a=1;
     hesapla();
     prnt(a);
}


Yukaridaki C program ile hemen ustundeki Basic program   bire bir aynidir.

Dikkat ederseniz

int a,b; seklinde tanimi main ve hesapla bolgesinin disinda tanimladik.
Bu a ve b degiskenlerinin programin her yerinden okunup degistirilebilecegi anlamina gelir. Iste bu tip degiskenlere global degisken deriz.

Basicde Hesaplama ve MAIN alt programini GOSUB ile cagirmistik.

Hesapla ve MAIN rutininin sonunda da RETURN komutu var.

BASIC'de GOSUB ile cagirdigimiz program parcasinin C deki adina  fonksiyon diyoruz.

void hesapla(void)   // Burasi Basic deki.HESAPLA: etiketine karsilik geliyor.

{  fonksiyonun basladigini gosteriyor.
} RETURN  un ta kendisi.

/*-----------------------------------------------------------------------------------------------------------------------------------------------------

Bu asamada Global degisken nedir, fonksiyon nedir, main satiri nedir cok iyi bildiginizi varsayiyorum

-----------------------------------------------------------------------------------------------------------------------------------------------------*/

Gelelim statik degiskenlere.

C programin tepesinde int a,b;   seklinde bir tanim yaparak a ve b nin integer tipinde global degiskenler oldugunu
derleyiciye bildirmistik.

Simdi bu satiri silip main ve hesapla fonksiyonlarinin icine kopyalayalim.




void hesapla(void)
{
int a,b;

    b=a;
}

void main(void)
{
int a,b;

     a=1;
     hesapla();
}


Iste buradaki a ve b artik lokal iki degisken haline geldi. Fakat artik maindeki a ile hesapladaki a ayni a değil.
Isimleri ayni gorunuyor ama hic alakalari yok.

BASIC de bunun bildigim kadariyla karsiligi yok.

Yukaridaki programda main fonksiyonu a=1 yapip hesapla() ile hesapla rutinini cagirdiginda hesapla rutinindeki a tanimsiz bir degerdir.
Cunku bu a ya herhangi bir atama yapilmamistir.

Su anda statik olarak tanimlanmis degiskenlerin sadece icinde bulundugu fonksiyondaki program satirlari tarafindan kullanilabildigini anlamis olduk.

Peki main fonksiyonundaki  a degerini hesapla fonksiyonuna  nasil aktaracagiz?

Iste bu soru void olarak yazilmis ve su ana kadar anlatilmamis kelimeninin ne anlama geldigini de cevap verecek.
Malesef lokal degisken tanimini anlatabilmek icin bu voide el atip aciklamak zorundayim.

void hesapla(void)
{
   b=a;
}

yesil voidi kaldiriyorum ve yerine int x yaziyorum

void hesapla(int x).

boyle yazdiktan sonra artik bu fonksiyonu hesapla() olarak değil hesapla(12) yada hesapla(a) gibi cagirmak zorunda kaliriz

hesapla(12) demek hesapla fonksiyonuna int 12 degerini gonder demektir.

peki 12 sayisinin int oldugunu nerden anladim? Hemen fonksiyonun yazildigi satira bakalim.
void hesapla(int x) yaziyor. parantez icinde int x yaziyor. iste buradaki int den  dolayi 12 sayisinin int oldugunu anladik.

eger hesapla(a) demis olsaydik bu durumda hesapla fonksiyonuna a'nin degeri gidecekti.

Simdi main ve hesapla fonsiyonlarini asagidaki gibi yaziyorum.

void hesapla(int x)
{
int a,b;
    b=x;
}

void main()
{
int a,b;

a=1;
hesapla(a);
prnt(b)
}


void hesapla(int x) de neden int x yazdim da x yerine a yazmadim?
ne isterseniz yazabilirsiniz. ben x yazdim ve fonskiyon icinde de b=x dedim. siz int y yazin  b=y diyin.

Peki simdi a=1 ardindan hesapla(a) ile hesapla fonksiyonuna geldik b=x yaptik. Aslinda !!!! b = maindeki a degiskeni oldu. !!!!
ve } ile gerisin geriye mainde kaldigimiz yere geldik. Peki main fonksiyonundaki b degeri acaba hesapla fonksiyonunda bulunan yani b=a degerimi?

Tabiki hayir.

Cunku bunlar lokal degiskenler ve sadece icinde tanimlandiklari fonksiyon icinde anlam ifade ederler.
main fonksiyonundaki b degeri hesapla(a) isleminden hic etkilenmez.

ne yapabiliriz?

Cozum 1.

int b;

void hesapla(int x)
{
    b=x;
}

void main()
{
int a;

a=1;
hesapla(a);
prnt(b)
}[/color]

Bu cozum b degiskenini global yapma esasina dayanir.

Cozum 2.


int hesapla(int x)
{
    b=x;
    return(b);
}

void main()
{
int a,b;

a=1;
b=hesapla(a);
prnt(b)
}[/color]

Bu cozum de ise hesaplanin solunda kalan void kelimesini int yaparak yani fonskiyonun kendisini cagiran fonksiyona return degeri ile integer deger gonderecegini bildirme esasina dayanir.

Dikkat ederseniz main fonksiyonunda b=hesapla(a) ile hesapla fonksiyonunun geri gonderdigi return degerini yakalamis olduk.

Su anda void main(void) de voidlerin ne anlama geldigini

int hesapla(void) de void ve int in ne anlama geldigini

void hesapla(int x) de ne anlama geldigini int x de x in ne oldugunu anladiginizi saniyorum.

C deki return(XXX) degeri int func( deki int kismi ile alakalidir.

eger return olmayacaksa fonksiyon yazilimi da void func( seklinde donusur.
Lokal degiskenimiz dogrudan ramin stack alaninda tutulur.
static on eki ile statik hale getirdigimizde bu degisken de global degisken gibi ramda tutulmaya baslanir. Fakat diger fonksiyonlar erisemez.

Sadece 2 dersde

main fonksiyonunun anlami,
Lokal degisken, Statik degisken, Global degisken,
Degisken tanimlama,
fonksiyon tanimlama,
fonksiyona parametre gonderme,
fonksiyondan return degeri alma,

gibi temel taslari ogrendik.

Simdi degisken tiplerine bakalim.

karakterlerle yada isaretli byte tipi verilerle ugrasmak icin char
integer isaretli sayilarla degerlerle ugrasmak icin int
isaretsiz integer sayilarla ugrasmak icin unsigned int

Ornek olarak asagidaki main fonksiyonu girisindeki degisken tanimlamalarina bakalim

void main(void)
{
unsigned int a;
int b=1;
char c;
unsigned char d[5]={'D','E','R','S',0x00}
int sayilar[10];
.....
.....

unsigned integer tipinda a degiskenimiz var. Bu durumda a=0....65535 araliginda deger alabilecek.
int b tipinde degiskenimiz main satirina girer girmez 1 degerini almis. -32768..+32767 araliginda deger alabilecek
signed char tipinde c degiskenimizle -128..+127 araliginda deger alabilecek
char tipinde c degiskenimizle 0..255 araliginda deger alabilecek
unsigned char tipinde d degiskenimiz bir karakter array ve icine DERS kelimesi yazilmis.
int tipinde 10 tane eleman yerlestirilebilen array'imiz var

(String tipi verilerle simdilik calismayacagiz.)

Artik denemeler yapabilecek konuma geldik. Yapacagimiz islemlerin sonuclarini ekranda gorebilmek icin (PC de Borland TC 3.00 ile calistigimizi varsayiyorum) printf komutunu detaylandirmadan kisaca ogrenelim.

printf("%d",a);     a sayisini decimal formatta print et.
printf("%d\n",a);  a sayisini decimal formatta print et ardindan satir atlat.
printf("%4x",a);   a sayisini hexadecimal formatta print et.
printf("Sonuc:%d\n",a);  Sonuc: 123 benzeri olsun.
printf("Sonuc1:%d   Sonuc2:%d\n",a,b);  Sonuc1: 123  Sonuc2:456  benzeri olsun.
printf("Merhaba");

Yukaridaki printf orneklerini inceleyerek komutu kavrayabilirsiniz.

a=a+1;
b=b-1;
c=a/b;
d=a*d;

4 isleme ait ornekler.

a=a+1; yerine a++;
a=a-1; yerine a--;

a=a+2 yerine  a+=2;

yazabilirsiniz.

printf komutunu kullanabilmek icin programin tepesine
#include <stdio.h>

yazmamiz gerekir.

Bu satir stdio.h dosyasinin programimiza dahil edilmesini saglar. Aksi halde printf komutu calistirilamaz.

Kendi kendinize denemeler yapmak icin lazim olacak ilave iki komut if karsilastirmasi ve for dongusu olacak.

Daha once and or xor not mantiksal islemlerine bakalim.

a=0x10; //   10 Hex sayisina karsi gelir.

void main()
{
int a,b,c;

     a=0x01; b=0x02;

     c=a|b;  // c= a or b
     c=a&b; // c= a and b
     c=a^b; // c= a xor b
     c=~a;   // c= not a
}

if karsilastirmasi

Basicdeki ornegimiz if a=10 then print "a esittir 10"   C deki ornegimiz if (a==10) printf("a esittir 10");

Basicdeki ornegimiz if a<>10 then print "a esitdeğil 10"   C deki ornegimiz if (a!=10) printf("a esit değil 10");

if (a=1) and (b<>2) then x=1    if ((a==1) && (B!=2))  x=1;

if (a=1) or (b<>2) then x=1    if ((a==1) || (B!=2))  x=1;

if (a==1)
  {
//  a=1 ise burdaki komutlar calistirilir.
  }
else
  {
// a<>1 ise burdakiler calisir
  }


Gelelim for dongusune

for i=0 to 9 step 2   for (i=0;i<10;i=i+2)

Eger Basicde program yazabiliyorsaniz bu dersden itibaren C ile  basit denemeler yapabileceginizden eminim.

Simdi de pointer kavramina bakalim.

pontere neden ihtiyac varla baslayalim.

Asagidaki gibi bir fonksiyon dusunelim.

void hesapla(int a, int b)
{
int x,y,z,w;
    x=a+b;
    y=a-b;
    z=a*b;
    w=a/b;     
}

peki hesaplanan x,y,z,w degerlerini cagiran fonksiyona nasil iletebiliriz?  (malesef int int int int hesapla(int a, int b) yazamiyoruz)

Cozum 1. Global degisken kullanmak

int x,y,z,w;

void Hesapla(int a,b)
{
    x=a+b;
    y=a-b;
    z=a*b;
    w=a/b;     
}

Cozum 2

void Hesapla(int a, int b, int* x, int* y, int* z, int* w)
{
    *x=a+b;
    *y=a-b;
    *z=a*b;
    *w=a/b;     
}

Burada int *x,  gelen veri, x degiskeninin degeri değil adresidir demek.

*X = a+b; demek a+b islemini yap ve sonucu adresi verilen alana yaz demek.

Peki bu fonksiyonu cagirirken nasil adres verecegiz?

main void()  // burada parantez icine void yazacaksak yazmayabilme serbestligimiz var
{
int a,b,c,d;

        Hesapla (4, 5, &a, &b, &c, &d);) // Buradaki &a, a degiskeninin adresinin sayisal degeri demektir.
}


-------------------------------------------------------------------------------

pointeri anlamak icin bir baska ornek

void main()
{
int a,b;        //  a ve b integer iki degisken
int* p          //  p,  integer degiskenlerin adresini saklayabilen bir degisken, yani bir pointer

       p=&a    //   a degiskeninin adresini p ye yukledik
       a=1;     //   a=1 yaptik
       b=*p;   //  p degiskenindeki adresdeki veriyi b ye yazdik. (b=a oldu)
}

Pointer denen sey de bundan ibaret.

O halde bir fonksiyondan istedigimiz kadar sonuc geri dondurebiliriz. Daha dogrusu, bir fonksiyondan, istedigimiz kadar degiskenin icine deger yazmasini isteyebiliriz.


Gordugunuz gibi ortalikta bir tane bile global degisken yok.

Basic de tum degiskenler global degisken

Basic deki global degiskenlerin zarari ne? Neden C de de global degiskenleri dayayip gecmiyoruz? Adresmis pointermis kendimizi sikintiya sokuyoruz?

Global degisken rama yapistimi suluk gibi kalan bir degiskendir. Yani ramdan yer tirtiklar.

x=a+b;
y=a-b;
z=a*b;
w=a/b;

hesaplandiktan ve kullanildiktan sonra artik x,y,z,w nin ramda yer kaplamasinin anlami yok.

Bunlar uzun programlarda hissedilir sekilde ramda yer kaybina neden olurlar. Bu nedenle de global degisken kullanimi pek tercih edilmez.
Fakat mikrolar artik buyuk ram kapasitelerine sahip olduklarindan bu konuya cok da dikkat etmeyebilirsiniz.

Eger

x=a+b;
y=a-b;
z=a*b;
w=a/b;

hesaplanan x,y,z,w sonuclari,  pek cok fonksiyonda girdi olarak kullanilacaksa bunlarin global olmasinda fayda vardir. Aksi takdirde
fonksiyon cagirimlarinda zirt pirt bunlarin adreslerinin fonksiyona gonderilmesi gerekir ki bu da bu kez romdan kaybetmek anlamina gelir.

Goruldugu gibi C de BASIC teki basit yapidan adim adim uzaklasiyoruz.

Bu detaylar kotumu? Elbette hayir.....
Biraz da Basicde olmayan saga sola kaydirmaya bakalim.

Basic ile 8 bit degiskenin bitlerini 8 ayri degiskene yerlestiren program yazalim.


       DIM S[8]

                 A=137 ' olsun BUNU PARCALASIN

                 B=1;
                 FOR I=1 TO 8
                     IF (A AND B) <>0 THEN C=1 ELSE C=0
                     B=B+B;
                     S[I]=C
                 NEXT I

                 END

Ayni programi C de yazalim (bir suru yolu var yukaridaki mantigi aynen de kullanabilirsiniz)

void main()
{
char s[8];
char i,a,b;
               a=137;
               b=1;
               for(i=0;i<8;i++)
                   {
                      s[i]=((a&b) ? 1:0)       // ? operatorunun solundaki islem sonucu dogru ise   : nin solundakini,       
                      b<<=1                        // yanlis ise : nin sagindakini al demek
                   }
}



b=b<<1 demek b yi bir bit sola kaydir demek
b=b>>1 demek b yi bir bit saga kaydir demek
------------------------------------------------------------------------------------------------------------------------
C de her yapilan islemin dogru yada yanlis sonucu vardir.

ornegin

      if (a+b)  c=1;  // isleminde c=1 olabilmesi icin a+b sonucunun 0 dan farkli olmasi gerekir.
     
      if (c=(a+b))  d=1; //  c=a+b islemini yap; eger sonuc 0 dan farkliysa d=1 olsun demektir

sonucun 0 olmasi yanlis, sonucun 0 dan farkli cikmasi dogru anlamina da gelir.

Ozel  komutlar icin (ornegin stringlerle oynamaya yarayan strcpy , sprintf, strcmp vs)  derleyicinin help menusune muracat edebilirsiniz.

Son olarak da structure ve union tanimlamarina deginip sizi C ile basbasa birakiyorum.
Ciplak C bu kadar. (while ve do ya siz bakarsiniz)

Standart veri tiplerinin disinda veri tipleri olusturmak icin struct deyimiden yarlaniyoruz.

Mesela A degiskeninin bir integer bir de karakter bileseni olsun.
A nin integer bilesenine 1234 hex degeri aktaralim, karakter bilesenine de 'Z' olsun diyebiliriz.

Bunun icin tanimlanmasi gereken structure;

struct Ozel
{
   int IntBileseni;
   char CharBileseni;
};

Boyle bir tanim ardindan mesela A degiskenine bu ozelligi atayalim.

struct Ozel A;

Artik A degiskenimizin icine deger atayabiliriz.

void main{
    A.IntBileseni=0x1234;
    A.CharBileseni='Z'

//  A nin CharBileseni  'X' mi diye bakmak istersek

    if (A.CharBileseni=='Z')
      {
          // Anin Char bileseni Z imis
      }
}


Simdi de union tanimlamasina bakalim.

Bunun icin bir ornek yapacagim.

struct Ozel_Integer{
   char H;
   char L;
};

// Burada yaptigim, adlari H ve L olan char tipinde 2 tane bilesenden olusan, Ozel_Integer adini verdigim  char bir degisken tanimlamak oldu.


union Ister16_Ister8_8 {
   int Bir_Kerede_16_Bit_Yukle;
   struct Ozel_Integer Sekiz_Bit_Yukle;
};

// Burada yaptigim ise Bir kerede 16 bit deger yuklenebilen integer tipinde ve adini Bir_Kerede_16_Bit_Yukle koydugum degisken ile;
// Daha once tanimladigim Ozel_Integer adindaki structurla ayni yapidaki  Sekiz_Bit_Yukle degiskenimi ayni adrese oturtmak oldu.
// Bu ozellige de Ister16_Ister8_8 adini verdim.

union Ister16_Ister8_8   Ozel_Degiskenime;

// Burada ise adini Ozel_Degiskenime koydugum bir degisken tanimlamak ve buna da Ister16_Ister8_8 adini koydugum union ozelligi vermek oldu.

void main (void)
{
   Ozel_Degiskenime.Bir_Kerede_16_Bit_Yukle=0x7890;
   Ozel_Degiskenime.Sekiz_Bit_Yukle.H=0x12;
   Ozel_Degiskenime.Sekiz_Bit_Yukle.L=0x34;
}


Son olarak bir uyari

main satirinin en sonuna sonsuz dongu koymayi unutmayin. Aksi takdirde C elinizden kacar gider.
Cunku buranin BASIC'deki RETURN'a karsilik geldigini soylemistim.

Operatorlerin kullanımında, tum diller icin gecerli olmak uzere cevaplarsam olay operatorleri iyi tanimaktan ziyade 2 li sayi sisteminin inceliklerini iyi bilmekten geciyor.

Temel kural: Carpma ve bolmeden sakin. Bunun yerine kaydir topla/cikarta yonel.




qeek

güzel yazı olmuş bende hep merak ederdim basic ne nasıl diye :D

oooben

çok güzel anlatmışsın eline sağlık
ben basic yazıyorum c ye geçmek istiyorum ama geçemiyordum eline sağlık.
bunun gibi bi kaç bişey daha yazan olursa veya devam ederseniz bizde geçebiliriz tşkler...
bülent