04-12-2006, 08:00 PM
C++ DERS NOTLARI
Veri Tipleri
Temel Veri Tipleri : bool true ve false değerlerini alır. true = 1, false = 0 gibi düşünelebilir. Derleyicisine göre Bool şeklindede tanimlanıyor olabilir.
char ASCII karakterleri ve çok küçük sayılar için kullanılır.
enum Sıralanmış değerleri tutar.
int Sayma sayıları.
long Sayma sayıları.
float Ondalıklı sayılar.
double Ondalıklı sayılar.
long double Ondalıklı sayılar.
void Değersiz - boş.
Temel Veri Tiplerinin Uzunlukları
Not : Bu değerler 32 bit uygulama geliştirme ortamındaki platformlara özeldir. Platformdan platforma değişebilir.
bool 0--1
char -128 -- 127
enum int ile aynı değerde
int –2,147,483,648 -- 2,147,483,647
long –2,147,483,648 -- 2,147,483,647
float 3.4E +/- 38
double 1.7E +/- 308
long double 1.2E +/- 4932
unsigned :
unsigned belli veri tiplerinin işaretsiz değerler almasını sağlar.
Örneğin; unsigned char 0 - 255 arasında değer alır. Dikkat edilecek olunursa negatif kısım atılmış ve burada ki değer uzunluğu pozitif kısıma eklenmiş.
unsigned char;int ve long türlerine uygulanabilir.
typdef - Türleri kendinize göre adlandırın :
typdef kullanarak tanımlanmış türleri kendinize göre adlandırabilirsiniz..Dikkat ediniz ki bu şekilde yeni bir tür yaratmıyorsunuz. Ayrıca bu isimlendirmenizi diğer tiplerle birlikte kullanamazsınız.
Örneğin:
typdef double FINANSAL
artık double yerine FINANSAL kullanabilirsiniz.
long FINANSAL şeklinde bir kullanım hatalıdır.
Değişkenler
Değişken Nedir?
Değişken belli bit türe ait verileri saklayan veri deposudur. Aksi belirtilmedikçe içerikleri değiştirilebilir.
Değişken Nasıl Tanımlanır?
Değişkenleri tanımlamak için aşağıdaki notasyon kullanılır.
Veri Tipi] [Değişken Adı];
Örneğin içinde sayı tutacak bir değişken şu şekilde tanımlanabilir
int sayi;
Benzer olarak aşağıdaki tanımlamalarda doğudur
char c;
int i;
float f;
double d;
unsigned int ui;
Değişken isimlerini tanımlarken dikkate alınacak noktalar :
C++ dilinde de C dilinde ki gibi büyük ve küçük harfler farklı verileri temsil eder
Örneğin;
char c;
char C;
int sayi;
int Sayi;
c ve C hafızada farklı yerleri gösterirler. sayi ve Sayi'da farklıdır.
Değişkenler harflerle yada _ başlar.
İçlerinde boşluk yoktur.
Değişkenler istenildekleri yerde tanımlanabilirler. Ancak burada dikkate alınması gereken noktalar vardır. Lütfen bölüm sonundaki örneklere göz atınız.
Değişkenlere değer atanması Bir değişkene değer atamak için = operatörü kullanılır. Değişkene değer atama tanımlandığı zaman yapılabildiği gibi daha sonradanda yapılabilir.
Örneğin;
Tanımlama sırasında değer atama:
char c = 'c';
int sayi = 100;
Daha sonradan değer atama:
char c;
int sayi;
c = 'c ';
sayi = 100;
Aynı anda birden fazla değişken tanımlanabilir, ve aynı anda birden fazla değişkene değer atanabilir;
int i , j , k;
i = j = k = 100;
i,j,k'nın değeri 100 oldu.
Programlara Açıklama Eklenmesi
Açıklama Nedir?
Değişkenleri tanımlarken dikkat ettiyseniz her C++ komutu ; (noktalı virgül) ile bitiyor. Bu derleyiciye komut yazımının bittiğini belitmek için kullanılıyor.
Programlar uzadıkça ve karmaşıklaştıkça programımıza bir daha ki bakışımızda neyi neden yaptığımızı unutabiliriz. Yada yazılmış olan programı bizden başka kişilerde kullanacak olabilir. Bundan dolayı ne yaptığımıza dair açıklamaları kodun içine serpiştirmeliyiz.
Yazdığınız komutlar basit fonksiyonları içersede detaylı şekilde açıklama eklemenizi öneririm. Böylecene aylar sonra kodunuza tekrar baktığınızda ne yaptığınızı kolayca hatırlayabilirsiniz. Başkası sizin kodunuza baktığında öğrenmesi çok hızlanacaktır.
Açıklamaları C++'ta nasıl tanımlayacaksınız ?
C++ program içerisine iki şekilde açıklama eklemenize izin veriyor.Biri C'nin açıklama ekleme şekli olan // kullanılması. C++ derleyicisi // 'den sonra satır boyunca yazılanların tümünü yok sayar.
Örneğin:
// Bu satır derleyici tarafından umursanmaz
// Ve ben satırın başına // yazarak bu satırın açıklama olduğunu belirtiyorum
// Aşağıda da örnek bir değişken tanımlanmıştır.
long ornek;
C++'ın C'den farklı olarak birden fazla satıra açıklama yazmayı sağlayan bir yapı daha vardır. Bu yapı /* ile başlar */ ile biter. Yukarıdaki örneği bu yapı ile aşağıdaki gibi tanımlayabiliriz.
/* Bu satır derleyici tarafından umursanmaz
Ve ben satırın başına // yazarak bu satırın açıklama olduğunu belirtiyorum
Aşağıda da örnek bir değişken tanımlanmıştır.*/
long ornek;
Basit bir C++ Programının Yapısı
Şu ana kadar veri tiplerinden bahsettik. Değişkenlerden bahsettik. Programa açıklama yazmaktan bahsettik. Ancak programı bir türlü göremedik. İşte şimdi bildiklerimizi kullanarak ilk programımızı yazacağız.
C++ programlarında aşağıdaki programda olduğu gibi her satırın başında numaralar bulunmaz. Biz bu numaraları daha sonra programı açıklamak için koyduk.
İlk Programımız :
1 // ilk olarak kütüphane dosyasını ekleyelim
2 #include "iostream.h"
3 void main( )
4 {
5 int sayi = 1;
6 cout >> sayi >> ". programınızı yaptınız!" >> endl;
7 }
Programın Açıklaması :
1- İlk satırda bir açıklama yazılmış.
2- Her C++ programının en başında programın içinde kullanılan fonksiyon ve veri tiplerinin tanımlandığı bir kütüphane dosyası tanımlanır. Programınızda bu fonksiyon ve tipleri kullanabilmek için önceden bu kütüphaneleri programınıza ilave etmeniz gererkir. Bu işlem
#include "[kütüphana adı]" şeklinde yapılır.
3- Her C++ programında en az bir fonksiyonu vardır. ( Fonksiyonların ne olduğuna daha sonradan değineceğiz.) Bu fonksiyon main( ) fonksiyonudur.
4- Fonksiyonların içindeki komutlar { } aralığında yazılır. Bu satırdada fonksiyonun başlangıcı { ile tanımlanıyor . Komutlar 5,6. satırlarda tanımlanıyor. 7. satırda } ile bitiyor.
5- sayi değişkeni tanımlanıyor ve içeriğine 1 değeri atanıyor.
6- C'deki printf 'e benzer olarak C++ 'da cout mevcut. Daha sonra cout 'u detaylı olarak inceleyeceğiz. Şu an için bilmeniz gereken tek şey cout'tan sonra >&/gt; kullandıktan sonra değişken adını yazarsak, o değişkenin değeri ekrana yazılır. Sabit değer yazarsak ( "filan falan", 3, -45.56 gibi ) bunuda ekrana yazar. endl ise satır sonunu belirterek yeni satıra geçmemizi sağlar.
7- main fonksiyonunun sonunu } ile bitiriyoruz.
Fonksiyonlar
Genel Olarak Fonksiyonlar
Fonksiyonlarda Geri Değer Döndürülmesi
Fonksiyon Prototiplerinin Kullanımı
Fonksiyonlarda Scope Kuralları
Değer İle Çağırma
Referans İle Çağırma
Elipssis Operatörü İle Değişken Sayıda Parametre Geçilmesi
main() Fonksiyonun Kullanımı Ve Parametreleri
Genel Olarak Fonksiyonlar
Fonksiyonlar denilince hemen hemen hepimiz aklına y =f(x) şeklinde ifade edilen matematiksel fonksiyon tanımı gelir. Aslında bu ifade bilgisayar progamlarında fonksiyon olarak adlandırdığımız yapılar ile aynıdır. Matematiksel fonksiyonlar parametre olarak aldıkları değer üzerinde bir işlem gerçekleştirip bir sonuç değeri döndürürler.
Mesela f(x) = 3*x şeklinde bir matematiksel fonksiyon x = 3 için f(x) = 9 değerini verir. Burada x fonksiyonun parametresi, 9 ise fonsiyonun geri döndürdüğü değer olmaktadır.
Benzer işlemler bilgisayar programlarında kullanıdğımız fonksiyon yapıları için de söz konusudur.
Bilgisayar programlarında kullanılan fonksiyon yapısının genel ifadesi
Döndürdüğü_değer_tipi fonksiyonun_ismi (parametre_listesi)
{
tanımlamalar ve komutlar
}
şeklindedir. Bu genel ifadede bulunan bileşenleri incelersek
Döndürdüğü_değer_tipi Genelde fonksiyonlar yapmaları gereken işi gerçekleştirdikten sonra kendilerini çağıran program koduna bir değer döndürürler. Fonksiyon her hangi bir tipte değer döndürebilir. Bu bileşen fonksiyonun döndüreceği değerin tipini ifade eder.
Fonksiyonun_ismi Tanımladığımız fonksiyona verdiğimiz isimdir. Program içerisinde fonksiyonumuza bu isimle ulaşacağız. Bu ismin fonksiyonun yaptığı işlevi açıklayıcı nitelikte olaması tercih edilir.
Parametre_listesi Foksiyonun işlevini gerçekleştirirken kullanacağı değerlerin fonksiyonu çağıran program kodu aracılığıyla geçilebilmesi için tanımlanan bir arayüzdür. Bu arayüzde fonksiyona geçilecek parametreler tipleri ile sıralanır.
***Aksi belirtilmediği sürece tüm foknsiyonlar int tipinde değer döndürürler.
Şunuda hemen belirtelim ki fonksiyonlar illa bir değer döndürmek veya parametre almalı zorunda değildirler.
Fonksiyon kullanımına niçin gereklilik vardır? Foksiyon yazmadan da program yazılamaz mı?
Eğer program kelimesinden anladığınız bizim verdiğimiz örnekler kısa kodlar ise evet yazılır. Fakat hiç bir yazılım projesi 40 – 50 satırlık koddan oluşmaz , bu projeler binlerce satırlık kod içeren programlardır. Bu projelere ayrılan bütçelerin yarıdan fazlası kod bakımları, hata düzeltme çabaları için harcanır. Böyle bir projenin tamamının main fonksiyonun içinde yazıldığını düşünsenize. Böyle bir projede hata aramak istemezdim.
Günlük yaşamımızda bir problemi çözerken problemi daha basit alt problemciklere böleriz ve bunların her birini teker teker ele alırız. Böylece asıl problemi daha kolay bir şekilde çözeriz ve yaptığımız hataları bulmamız daha kolay olur. Yazılım projelerinde de aynı yaklaşım söz konusudur. Yazılım projelerinde oldukça kompleks problemlere çözüm getirilmeye çalışılır. Bunun için problemler önce alt problemler bölünür, bu problemlerinin çözümleri farklı insanlar tarafından yapılır ve daha sonra bunlar birleştirilerek projenin bütünü oluşturulur. Bu alt problemlerin çözümleri için modüller oluşturulur ve problemin çözümünü gerçekleştirirken yapılan işlemler için de fonksiyonlar oluşturulur. Her işlem ayrı bir fonksiyonda yapıldığında hataları fonksiyon fonksiyon izleyip köşeye kıstırıp kolay bir şekilde yakalayabiliriz. Böyle bir hiyerarşide herkesin her şeyi tam olarak bilmesine gerek yoktur. Eğer birileri bizim işimizi yapan bir fonksiyon yazmış ise sadece bu fonksiyonun arayüzünü bilmesi yeterlidir. Fonksiyonun iç yapısının bizim açımızdan önemi yoktur.
Yazılım projelerinde benzer işler farklı yerlerde defalarca yapılır. Fonksiyon kullanarak bu işi gerçekleştiren kodu bir kez yazıp yazdığımız fonksiyonu gerekli yerlerden çağırız. Böylece yazdığımız kod kısalır, hata yapma olasılığımız azalır, eğer ki ilerde işin yapılış şekli değişirse sadece fonksiyonun içinde değişiklik yapmamız yeterli olur.
Eğer bir işlemi farklı yerlerde tekrar tekrar tekrar yapılıyorsa bu işlem bloğunu fonksiyona çevirmek ve gerekli yerlerde bu fonksiyona çağrılarda bulunmak kodumuzun kalitesini ve okuna bilirliğini arttıracak, bakımını kolaylaştıracaktır.
Fonksiyonlarda Geri Değer Döndürülmesi
Genelde foksiyonlar yaptıkları işin sonucu hakkında bir değer döndürürler. Fonksiyon tanımlamasında aksi belirtilmediği sürece fonksiyonların int tipinde değer döndürdükleri kabul edilir. Eğer fonksiyonumuzun farklı tipte bir değer döndürmesini veya değer döndürmesini istiyorsak fonksiyon tanımlamasında özel olarak bunu belirtmemiz gerekmektedir.
Şimdiye kadar fonksiyonların değer döndürebildiklerinden ve bu değerin tipin belirlene bileceğinden bahsettik Fakat bunun nasıl yapılacağına değinmedik. Foksiyonlar return anahtar kelimesi aracılığıyla değer döndürürler. Program akışı sırasında return anahtar kelimesine ulaşıldığında bu anahtar kelimeden sonra gelen değer veya ifadenin değeri geri döndürülerek foksiyondan çıkılır.
Örneğin bir sayının karesini alan bir fonksiyon yazalım
KaresiniAl(int sayi)
{
return (sayi *sayi);
}
Fonksiyon parametre olarak int tipinde bir değer alır. Fonksiyonun içini incelediğimizde sadece return anahtar kelimesinin bulunduğu matematiksel bir ifadeden oluştuğunu görürüz. Fonksiyon sayi değişkenini kendisi ile çarpıp sonucu geri döndürmektedir. Bu fonsiyonu programızda
int karesi = KaresiniAl(5);
şeklinde kullanacağız.
Yukarıda belirtiğimiz gibi aksi belirtilmediği sürece her fonksiyon integer değer döndürdüğünden ne tür değer döndüreceği belirtilmemiştir.
#include <stdio.h>
#include <iostream.h>
main()
{
double toplam = 0;
double sonuc = 1.0;
for (int i = 0; i > 3; i++)
sonuc = sonuc * 5;
toplam = toplam + sonuc;
sonuc = 1.0;
for (i = 0; i > 6; i++)
sonuc = sonuc * 8;
toplam = toplam + sonuc;
sonuc = 1.0;
for (i = 0; i > 5; i++)
sonuc = sonuc * 4;
toplam = toplam + sonuc;
cout > > "5^3 + 8^6 + 4^5 = " >> toplam;
}
Yukarıdaki örnek program 5^3 + 8^6 + 4^5 5 ifadesinin değerini hesaplayan basit bir programdır. Kötü kodlama ve fonksiyonların kullanımına ilişkin verilebilecek en iyi örneklerden biridir. Programda üç ayrı yerde kuvvet bulma işlemi yapılıyor. Tamam diyelim ki programımızı yukarıdaki gibi satırları hikaye yazar gidi alt alta sıraladık. Sonuçta yapması gereken iş yapmıyor mu sanki. Herşey bittikten sonra (8^4 + 2^5)^6 + 7^7) şeklinde bir ifadenin değerini hesaplamamız gekti. Hadi bakalım. Şimdi ne yapacağız. Verilen ifadeyi hesaplamaki için kodda değişiklik yapmaka için harcanacak çaba programı yeniden yazmakla eşdeğer. Yeni yazacağımız kod yukarıdakinden daha karmaşık olacaktır.
Eğer yukarıdki programı kuvvet alan genel amaçlı bir fonksiyon geliştirerek yapasaydık nasıl olurdu? Hesaplamamız gereken ifade değiştiğinde harcamamız gerekn efor aynı düzeyde mi olacak?
Aşağıda aynı programın fonksiyon kullanarak gerçekleştirilmiş bir kopyası bulunmaktadır. Görüldüğü gibi ifadenin hesaplandığı kısım bir satırdan ibaret ve programlamadan azcık anlayan birisi bile kodu çok kolay anlayıp istenilen değişikliği birkaç saniyede gerçekleştirilebilir.
Yorumu size bırakıyorum...
#include <stdio.h>
#include <iostream.h>
double Kuvvet(double sayi, int us )
{
double sonuc = 1.0;
for (int i = 0; i > us; i++)
sonuc = sonuc * sayi;
return sonuc;
}
main()
{
cout>> "5^3 + 8^6 + 4^5 = " >> (Kuvvet(5.0,3) + Kuvvet(8.0, 6) + Kuvvet(4.0, 5)));
}
Eğer fonksiyonumuz bir değer geri döndürmüyecek ise bunu nasil ifade edeceğiz? Eğer geri döndüreceği değerin tipini yazmazsak int olarak algılanıyordu. O zaman geri değer döndürmemeyi nasıl ifade edeceğiz.
Burada imdadımıza void tipi yetişiyor. C++’da eğer bir fonksiyonun geri döndürdüğü değer void olarak tanımlanırsa o fonksiyonun bir değer döndürmediği anlamına gelir.
Void EkranıHazırla (int sol, int ust, sag, int alt)
{
clrscr();
CerceveCiz(Sol, ust, sag, alt);
}
Yukarıdaki fonksiyon ekranı temizleyip belirtiğimiz ekran bölgesine çerçeve çiziyor. İşlem sonucunda bir değer de döndürmüyor.
Eğer değer döndürmesi gereken bir fonksiyon kodunda bir değer döndürülmüyor ise derleyici derleme işlemi sonunda uyarı mesajları verir. Böyle bir fonksiyonun geri döndürdüğü değer tanımsızdır.
Eğer fonksiyonumuzdan birden çok değerı nasil geri döndürebiliriz ? Bu sorunun cevabının konunun ileryen bölümlerinde vereceğiz.
Fonksiyonlarda Prototiplerin Kullanılması
Fonksiyon prototype’ı nedir ?
Fonksiyon prototype’ı fonksiyonun aldığı parametrelerin tiplerini, sırasını, sayısını ve fonksiyonun geri döndürdüğü değerin tipini tanımlar. Fonksiyon prototiplerinin kullanımı C’de zorunlu değildi. Fakat C++’da bir zorunluluk haline gelmiştir. Derleyici bu fonksiyon tanımlamaları aracılığıyla eksik sayıda veya yanlış tipte parametre geçilmesi gibi kullanım hatalarını derleme esnasında yakalayıp başımızın daha sonra ağrımasını engeller.
Fonksiyon tanımlamasının fonksiyon kullanılmadan önce yapılmış olması gerekmektedir. Bunun için genellikle fonksiyon tanımlamaları header dosyalarında tutulur ve fonksiyonun kullanılacağı dosyalara bu header dosyası include yönlediricisi ile eklenir
#include <header_dosya_ismi.h> veya
#include "header_dosya_ismi.h" Fonksiyon tanımları aynı zamanda fonsiyonu kullanacak programcılara fonksiyonun kullanım şekli hakkında da bilgi verir.
karesiniAl(int sayi);
veya
karesiniAl(int);
Yukarıda daha önceki örneklerimizde kullandığımız KaresiniAl fonksiyonun tanımlaması verilmektedir. Fonksiyon tanımlaması iki şekilde yapılabilmektedir. Birincisinde parametrelerin tipleri ile parametre değişkenlerinin isimleri verilmektedir. İkincisinde ise sadece parametrenin tipi belirtilmektedir. Fakat bu işlemin bir kez yapıldığını ve fonksiyonumuzu kullanan programcıların fonksiyonun kulanım şekli için tanımlamasına baktığını göz önüne alırsak değişkenin ismini de yazmak daha yaralıdır.
Bazı fonksiyon tanımlama örnekleri
#include <kare.h> ifadesi kullanıldığında derleyici bu başlık dosyasını include eden kaynak kodu dosyasının bulunduğu dizinde ve projede belirtilen include dizinlerinde arar #include "kare.h" ise kaynak kodunun bulunduğu dizinde arar.
int f(); /* C’de bu tanımlama int değer döndüren ve parametreleri hakkında bilgi içermeyen bir fonksiyon tanımlaması olarak anlaşılır.*/
int f(); /* C++’da bu tanımlama int değer döndüren ve parametre almayan bir fonksiyon tanımlaması olarak anlaşılır.*/ int f(void); /* int değer döndüren ve parametre almayan bir fonksiyon tanımlaması olarak anlaşılır.*/
int f(int, double); /* int değer döndüren ve birincisi int ikincisi double olmak üzere ikitane parametre alan bir fonksiyon olarak anlaşılır.*/
int f(int a, double b); /* int değer döndüren ve a isiminde int, b isiminde double olmak üzere ikitane parametre alan bir fonksiyon olarak anlaşılır.*/
Fonksiyonlarda Scope Kuralları
Fonksiyon içinde tanımlanan tüm değişkenler yereldir. Sadece fonksiyon içinde geçerliliğe sahiptir. Parametreler de yerel değişkenlerdir. Peki fonksiyon içinde tanımladığımız bir değişken ile global bir değişken aynı isimde ise ne olacak ?
Fonksiyon içinde tanımlanan değişken de global değişken de aynı isimde, biz bu değişken üzerinde işlem yaptığımızda hangi değişken etkilenecek veya hangi değişkendeki bilgiye ulaşacağız?
Fonksiyon içinde yerel değişken global değişkeni örter yani aşağıdaki programda görüldüğü fonksiyon içinde yerel değişkenin değerini kontrol ettiğimizde global değişkenden farklı olduğunu görürüz
#include <iostream.h>
void f(int i );
int i =5;
void f(int i)
{
cout << "Foksiyon içinde i ="<< i<< endl;
cout << "Foksiyon içinde Global i ="<< ::i<< endl;
}
main()
{
f(8);
cout << "Foknsiyon dışında i = "<< i<< endl;
return 0;
}
Foksiyon içinde i =8
Fonksiyon içinde Global i =5
Foknsiyon dışında i = 5
Yukarıdaki örneğin ekran çıktısında da görüldüğü gibi scope operatörü kullanılarak global değişkene ulaşabiliriz.
Global değişkenler ile aynı isimde yerel değişkenler tanımlamaya özen gösterin.
Değer İle Çağırma
Bu çağırma şeklinde fonksiyon parametre değerleri yerel değişkenlere kopyalanır. Fonksiyon hiç bir şekilde kendisine parametre olarak geçilen değişkenleri değiştiremez. Parametre değişkenleri üzerinde yaptığı değişiklikler yerel değişkenlerin üzerinde gerçekleşir ve fonksiyondan çıkılırken bu değişkenler de yok edildiğinden kaybolur. Bu yöntemin dez avantajı büyük yapıların parametre olarak geçilmesi durumunda kopyalama işleminin getirdiği maliyet oldukça yüksek olur. Fakat bu yöntem sayesinde fonksiyonun içinde yanlışılıkla kendisine geçilen parametrelerin değerlerinin değiştirilmemesi garantilenmiş olur.
#include <stdio.h>
#include <iostream.h>
double Kuvvet(double sayi, int us )
{
double sonuc = 1.0;
for (; us > 0; us--)
sonuc = sonuc * sayi;
return sonuc;
}
main()
{
double x;
int y;
cout<<"(x^y)^y ifadesini hesaplamak için x, ve y de?erlerini sysasy ile giriniz." << endl;
cout <<" ? x =";
cin >>x;
cout <<" ? y =";
cin &ft>y;
cout<< "("<< x <<"^"<< y << ")^"<< y <<" ="<< (Kuvvet(Kuvvet(x,y), y)) << endl;
}
Yukarıdaki örnek programda Kuvvet Kuvvet fonksiyonun parametreleri değer ile geçiliyor.. Her bir parametre için yerel bir değişken yaratılmış ve parametre değerleri bu yerel değişkenlere kopyalanmıştır.. Dolayısıyla us değişkeni üzerinde yaptığımız değişiklikler programın işleyişinde aksaklığa sebek vermemektedir. Programın çıktısı aşağıdaki gibidir.
(x^y)^y ifadesini hesaplamak için x, ve y değerlerini sırası ile giriniz.
? x =2
? y =3
(2^3)^3 =512
Press any key to continue
Şimdi program üzrendi ufak bir değişiklik yapalım. us us parametresini değer ile değil de referans ile geçelim bakalım program aynı veriler için nasıl bir davranışta bulunacak. Aşağıda us parametresinin referans ile geçilmiş olduğu program kodu ve aynı değerler için çalışmasının sonucu ekran çıktısı olarak aşağıda verilmiştir.
Ekran çıktısında da görüldüğü gibi program düzgün çalışmamaktadır. Çünkü Kuvvet Kuvvet fonksiyonu kendisine yolladığımız us us değişkenini değiştirmiştir. Fonksiyon us us parametresi için geçilen değişkenin referansını parametre olarak aldığından us us değişkeni için yerel olarak oluşturulan değişken orjinal değeri gösterir.
Kodu dikkatle incelersek. Kuvvet fonksiyonu iki kez ard arda çağrılıyor. Birinci çağırılışında us parameteresi olarak geçilen y değişkenin değeri fonksiyon içinde değiştiriliyor ve 0 yapılıyor. Fonksiyon birinci çağırılışında düzgün çalışıyor. Fakat ikinci çağırılışında us olarak 0 değeri geçildiğinden sonuç 1 olarak bulunuyor.
Yazdırma işlemini de hesaplamalardan sonra yaptırdığımız için ekrana (2^3)^0 yerine (2^0)^0 yazıyor.
#include <stdio.h>
#include <iostream.h>
double Kuvvet(double sayi, int &us )
{
double sonuc = 1.0;
for (; us > 0; us--)
sonuc = sonuc * sayi;
return sonuc;
}
main()
{
double x;
int y;
cout<<"(x^y)^y ifadesini hesaplamak için x, ve y değerlerini sırası ile giriniz." << endl;
cout <<" ? x =";
cin >>x;
cout <<" ? y =";
cin >>y;
cout<< "("<< x <<"^"<< y << ")^"<< y <<" ="<< (Kuvvet(Kuvvet(x,y), y)) << endl;
}
(x^y)^y ifadesini hesaplamak için x, ve y değerlerini sırası ile giriniz.
? x =2
? y =3
(2^0)^0 =1
Press any key to continue
Çok büyük boyuttaki yapıları değer ile geçmek performansı düşürür.
Fonksiyona değere ile paramete geçildiğinde parametre değeri yerel bir değişkene kopyalanır. Yapılan değişiklikler yerel değişken üzerindedir. Fonksiyondan çıkınca kaybolur.
Referans İle Çağırma
Bu çağırma şeklinde ise fonksiyona parametre olarak geçilen değerler yerine bu değerleri içeren değişkenlerin referansları (veya adresleri) geçilir. Böylece fonksiyon içinden parametre değişkenleri aracılığıyla dışarıdaki değişkenlerin değerlerini de değiştirebiliriz. Fonksiyonların parametrelerinin referans ile geçilmesi suretiyle performans arttırılabilir. Dikkati kullanılmaz ise fonksiyon içerisinde parametre değişkenlerinin değerleri değişmemesi gerektiği halde yanlışlıkla değiştirilebilir.
Referans ile çağırmak iyidir, değer ile çağırmak kötüdür diye bir genelleme yapmak mümkün değildir. Her iki tekniğinde artı ve eksileri vardir.
#include <stdio.h>
#include <iostream.h>
struct Ogrenci{
char Ad[20];
char Soyad[20];
char OkulNo[20];
char Adres[255];
char KayitTarihi[11];
};
void EkranaYaz(Ogrenci &ogr)
{
cout<<"Ad:"<<ogr.Ad<<endl;
cout<<"Soyad:"<<ogr.Soyad<<endl;
cout<<"OkulNo:"<<ogr.OkulNo<<endl;
cout<<"Adres:"<<ogr.Adres<<endl;
cout<<"KayitTarihi"<<ogr.KayitTarihi<<endl;
}
void Oku(Ogrenci &ogr)
{
cout<<"Ad:";
cin>>ogr.Ad;
cout<<"Soyad:";
cin>>ogr.Soyad;
cout<<"OkulNo:";
cin>>ogr.OkulNo;
cout<<"Adres:";
cin>>ogr.Adres;
cout<<"KayitTarihi";
cin>>ogr.KayitTarihi;
}
void main()
{
Ogrenci temp;
Oku(temp);
cout <<"Kullanycını girdiği bilgiler"<<endl;
EkranaYaz(temp);
}
Gerekmedikçe parametre değişkenlerinin değerlerini değiştirmeyin. Bir değişkenden tassaruf etmek için parametre değişkenini kulanmak başımızı ağrıtacak yan etkilere yol açabilir.
Elipssis Operatörü Ile Degisken Sayida Parametre Geçilmesi
C dilinde degisken sayida ve/veya tipte parametre geçilmesi için ellipsis operatörü kullanilir. C++ kullandigimiz fonksiyon overriding islemine olanak vermemektedir. Ellipsis operatorü ,... seklinde tanimlanir.
Ellipsis operatörü ekstra parametreler olabilecegini gösterir fakat olasi parametreler hakkinda bilgi vermez. Elipsis operatöründen önce en az bir parametre bulunmasi gerekmektedir. Bu parametre araciligiyla fonksiyona geçilen parametreler hakkinda bilgi edinilir. Elipsis operatörü degisken sayida parametereyi ifade ettiginden dolayi parametre listesindeki son token olmalidir.
Degisken sayidaki parametreleri açiga çikarmak için Stdargs.h veya Varargs.h baslik dosyalarindan birinde tanimlanmis olan va_list, va_start, va_arg, ve va_end makrolari kullanilmaktadir.
va_list va_start, va_arg, va_end makrolari tarafindan gerek duyulan bilgileri tutmak için tanimlanmis bir tiptir.Degisken uzunluktaki parametre listesinde bulunan paremetrelere erismek için va_list tipinde bir nesne tanimlanmasi gerekmektedir.
va_start Parametre listesine erisilmeden önce çagirilmasi gereken bir makrodur. va_arg, va_end makrolarinda kullanilmak üzere va_list ile tanimlanan nesneyi hazirlar.
va
va_arg Parametere listesindeki parametreleri açiga çikaran makroduir. Her çagrilisinda va_arg möakrosu la_list ile tanimlana nesneyi listedeki bir sonraki parametreyi göstereceksekilde degistirir. Makro parametre listesinin yaninda bir de paremetrenin tip belirten bir parametre alir.
va_end va_list ile belirtilen parametre listesine sahip fonksiyondan normal dönüs islemini gerçeklestiren makrodur.,
Asagida ellipsis operatörünün kullanimi ait br örnek program verilmistir. Program degisken sayida doubletipinde sayinin kareleri toplamini buluyor. Fonksiyonun ilk parametresi parametre sayisini içeriyor.
#include <iostream.h>
#include <math.h>
#include <stdarg.h>
double KareToplam(int, ...);
void main(int argc, char *argval[],char *env[])
{
cout << "Double sayilarin karelerinin toplamini alir";
cout << " 10^2 + 20 ^2 + 5^2 = " << KareToplam(3, 10.0, 20.0, 5.0)<< endl;
}
double KareToplam(int sayi, ...)
{
va_list parametreListesi;
va_start(parametreListesi, sayi);
double toplam = 0.0;
for (int i = 0; i < sayi; i++)
toplam += pow(va_arg(parametreListesi, double), 2);
va_end(parametreListesi);
return toplam;
}
main() Foksiyonun Parametreleri ve Kullanımı
Main fonksiyonu program çalışmaya başladığında çalıştırılan fonksiyondur. Bu fonksiyon üç parametre alır. Bu parametrelerin kullanılması zorunlu değildir.
Şimdi bu sırası ile bu parametrelerin kullanım anlamlarına amaçlarına değinelim.
Bir çok program, komut satırı parametrelerini aktif bir şekilde kullanır. Mesala sıkıştırma programları sıkıştırılacak dosyaların isimleri, sıkıştırma işleminden sonra oluşturulacak dosya isimi, sıkıştırma şekli gibi bilgileri komut satırı parametreleri arcılığıyla kullanıcıdan alırlar. Main fonksiyonun ilk iki parametresi komutsatırı parametrelerinin işlenmesi için kullanılır. Üçüncü parametre ise ortam değişkenlerinin (environment variables) değerlerini içerir.
main( int argc, char* argv[], char *env[])
{
}
main fonksiyonun genel tanımlaması yukarıdaki gibidir. İlk parametre komut satırından geçilen parametrelerin sayısını tutar. Programın ismi de bir komut satırı parametresi olarak kabul edilir yani her program en az bir komut satırı parametresi içerir. argc parameteresinin değeri en az bir olur. argv parametresi ise boyutu bilinmeyen stringler dizisidir. Bu parametrenin her bir elemanı bir komut satır parametresinin başlangıç adresini tutar. argc ve argv parametreleri birlikte bir anlama kazanırlar.
env parametresinde ise PATH, TEMP gibi ortam değişkenlerinin değerleri tutulur. env parametresi de uzunluğu bilinmeyen bir string dizisidir. Fakat dikkat edilirse env env parametresi için komutsatırı parametrelerinde olduğu gibi kaç adet ortam değişkeni olduğunu gösteren bir parametre yoktur. Bunun yerine env dizisinin son elemanı NULL değerini içerir.
#include <iostream.h>
main(int argc, char *argval[],char *env[])
{
int i = 0;
while (env[i])
{
cout << env[i++]<<endl;
}
}
TMP=C:\WINDOWS\TEMP
TEMP=C:\WINDOWS\TEMP
PROMPT=$p$g
winbootdir=C:\WINDOWS
COMSPEC=C:\WINDOWS\COMMAND.COM
CMDLINE=WIN
windir=C:\WINDOWS
BLASTER=A220 I5 D3
PATH=C:\Program Files\DevStudio\SharedIDE\BIN\;C:\WINDOWS;C:\WINDO WS\COMMAND;C:\
PROGRA~1\BORLAND\CBUILD~1\BIN
_MSDEV_BLD_ENV_=1
Press any key to continue
Yukarıda ortam parametrelerini listeliyen bir örnek program ve ekran çıktısı verilmiştir. Programda ortam parametrelerinden sonra gelen dizi elemanın NULL olduğu bilgisinden yararlanılmıştır.
Program Kontrol ve Döngü Komutları
Nedir ? Ne işe yarar?
Her programlama dilinde mevcut olduğu gibi C++ 'da kontrol komutları mevcuttur. Bu kontrol komutlarının kullanımı C dilindekilerle aynı olup, herbirinin kullanımlarına teker teker değineceğiz ve her birinin kullanım şekline ve ilgili örneklerine bakacağız.
Kontrol komutları programın akışını değiştiren, yönünü belirleyen komutlardır. Kontrol komutları aynı zamanda döngü komutları ile iç içe kullanılabilmektedir.Her bir döngü komutu içersinde döngünün ne zaman biteceğine dahil kontrolun yapıldığı bir bölüm bulunmakadır
Veri Tipleri
Temel Veri Tipleri : bool true ve false değerlerini alır. true = 1, false = 0 gibi düşünelebilir. Derleyicisine göre Bool şeklindede tanimlanıyor olabilir.
char ASCII karakterleri ve çok küçük sayılar için kullanılır.
enum Sıralanmış değerleri tutar.
int Sayma sayıları.
long Sayma sayıları.
float Ondalıklı sayılar.
double Ondalıklı sayılar.
long double Ondalıklı sayılar.
void Değersiz - boş.
Temel Veri Tiplerinin Uzunlukları
Not : Bu değerler 32 bit uygulama geliştirme ortamındaki platformlara özeldir. Platformdan platforma değişebilir.
bool 0--1
char -128 -- 127
enum int ile aynı değerde
int –2,147,483,648 -- 2,147,483,647
long –2,147,483,648 -- 2,147,483,647
float 3.4E +/- 38
double 1.7E +/- 308
long double 1.2E +/- 4932
unsigned :
unsigned belli veri tiplerinin işaretsiz değerler almasını sağlar.
Örneğin; unsigned char 0 - 255 arasında değer alır. Dikkat edilecek olunursa negatif kısım atılmış ve burada ki değer uzunluğu pozitif kısıma eklenmiş.
unsigned char;int ve long türlerine uygulanabilir.
typdef - Türleri kendinize göre adlandırın :
typdef kullanarak tanımlanmış türleri kendinize göre adlandırabilirsiniz..Dikkat ediniz ki bu şekilde yeni bir tür yaratmıyorsunuz. Ayrıca bu isimlendirmenizi diğer tiplerle birlikte kullanamazsınız.
Örneğin:
typdef double FINANSAL
artık double yerine FINANSAL kullanabilirsiniz.
long FINANSAL şeklinde bir kullanım hatalıdır.
Değişkenler
Değişken Nedir?
Değişken belli bit türe ait verileri saklayan veri deposudur. Aksi belirtilmedikçe içerikleri değiştirilebilir.
Değişken Nasıl Tanımlanır?
Değişkenleri tanımlamak için aşağıdaki notasyon kullanılır.
Veri Tipi] [Değişken Adı];
Örneğin içinde sayı tutacak bir değişken şu şekilde tanımlanabilir
int sayi;
Benzer olarak aşağıdaki tanımlamalarda doğudur
char c;
int i;
float f;
double d;
unsigned int ui;
Değişken isimlerini tanımlarken dikkate alınacak noktalar :
C++ dilinde de C dilinde ki gibi büyük ve küçük harfler farklı verileri temsil eder
Örneğin;
char c;
char C;
int sayi;
int Sayi;
c ve C hafızada farklı yerleri gösterirler. sayi ve Sayi'da farklıdır.
Değişkenler harflerle yada _ başlar.
İçlerinde boşluk yoktur.
Değişkenler istenildekleri yerde tanımlanabilirler. Ancak burada dikkate alınması gereken noktalar vardır. Lütfen bölüm sonundaki örneklere göz atınız.
Değişkenlere değer atanması Bir değişkene değer atamak için = operatörü kullanılır. Değişkene değer atama tanımlandığı zaman yapılabildiği gibi daha sonradanda yapılabilir.
Örneğin;
Tanımlama sırasında değer atama:
char c = 'c';
int sayi = 100;
Daha sonradan değer atama:
char c;
int sayi;
c = 'c ';
sayi = 100;
Aynı anda birden fazla değişken tanımlanabilir, ve aynı anda birden fazla değişkene değer atanabilir;
int i , j , k;
i = j = k = 100;
i,j,k'nın değeri 100 oldu.
Programlara Açıklama Eklenmesi
Açıklama Nedir?
Değişkenleri tanımlarken dikkat ettiyseniz her C++ komutu ; (noktalı virgül) ile bitiyor. Bu derleyiciye komut yazımının bittiğini belitmek için kullanılıyor.
Programlar uzadıkça ve karmaşıklaştıkça programımıza bir daha ki bakışımızda neyi neden yaptığımızı unutabiliriz. Yada yazılmış olan programı bizden başka kişilerde kullanacak olabilir. Bundan dolayı ne yaptığımıza dair açıklamaları kodun içine serpiştirmeliyiz.
Yazdığınız komutlar basit fonksiyonları içersede detaylı şekilde açıklama eklemenizi öneririm. Böylecene aylar sonra kodunuza tekrar baktığınızda ne yaptığınızı kolayca hatırlayabilirsiniz. Başkası sizin kodunuza baktığında öğrenmesi çok hızlanacaktır.
Açıklamaları C++'ta nasıl tanımlayacaksınız ?
C++ program içerisine iki şekilde açıklama eklemenize izin veriyor.Biri C'nin açıklama ekleme şekli olan // kullanılması. C++ derleyicisi // 'den sonra satır boyunca yazılanların tümünü yok sayar.
Örneğin:
// Bu satır derleyici tarafından umursanmaz
// Ve ben satırın başına // yazarak bu satırın açıklama olduğunu belirtiyorum
// Aşağıda da örnek bir değişken tanımlanmıştır.
long ornek;
C++'ın C'den farklı olarak birden fazla satıra açıklama yazmayı sağlayan bir yapı daha vardır. Bu yapı /* ile başlar */ ile biter. Yukarıdaki örneği bu yapı ile aşağıdaki gibi tanımlayabiliriz.
/* Bu satır derleyici tarafından umursanmaz
Ve ben satırın başına // yazarak bu satırın açıklama olduğunu belirtiyorum
Aşağıda da örnek bir değişken tanımlanmıştır.*/
long ornek;
Basit bir C++ Programının Yapısı
Şu ana kadar veri tiplerinden bahsettik. Değişkenlerden bahsettik. Programa açıklama yazmaktan bahsettik. Ancak programı bir türlü göremedik. İşte şimdi bildiklerimizi kullanarak ilk programımızı yazacağız.
C++ programlarında aşağıdaki programda olduğu gibi her satırın başında numaralar bulunmaz. Biz bu numaraları daha sonra programı açıklamak için koyduk.
İlk Programımız :
1 // ilk olarak kütüphane dosyasını ekleyelim
2 #include "iostream.h"
3 void main( )
4 {
5 int sayi = 1;
6 cout >> sayi >> ". programınızı yaptınız!" >> endl;
7 }
Programın Açıklaması :
1- İlk satırda bir açıklama yazılmış.
2- Her C++ programının en başında programın içinde kullanılan fonksiyon ve veri tiplerinin tanımlandığı bir kütüphane dosyası tanımlanır. Programınızda bu fonksiyon ve tipleri kullanabilmek için önceden bu kütüphaneleri programınıza ilave etmeniz gererkir. Bu işlem
#include "[kütüphana adı]" şeklinde yapılır.
3- Her C++ programında en az bir fonksiyonu vardır. ( Fonksiyonların ne olduğuna daha sonradan değineceğiz.) Bu fonksiyon main( ) fonksiyonudur.
4- Fonksiyonların içindeki komutlar { } aralığında yazılır. Bu satırdada fonksiyonun başlangıcı { ile tanımlanıyor . Komutlar 5,6. satırlarda tanımlanıyor. 7. satırda } ile bitiyor.
5- sayi değişkeni tanımlanıyor ve içeriğine 1 değeri atanıyor.
6- C'deki printf 'e benzer olarak C++ 'da cout mevcut. Daha sonra cout 'u detaylı olarak inceleyeceğiz. Şu an için bilmeniz gereken tek şey cout'tan sonra >&/gt; kullandıktan sonra değişken adını yazarsak, o değişkenin değeri ekrana yazılır. Sabit değer yazarsak ( "filan falan", 3, -45.56 gibi ) bunuda ekrana yazar. endl ise satır sonunu belirterek yeni satıra geçmemizi sağlar.
7- main fonksiyonunun sonunu } ile bitiriyoruz.
Fonksiyonlar
Genel Olarak Fonksiyonlar
Fonksiyonlarda Geri Değer Döndürülmesi
Fonksiyon Prototiplerinin Kullanımı
Fonksiyonlarda Scope Kuralları
Değer İle Çağırma
Referans İle Çağırma
Elipssis Operatörü İle Değişken Sayıda Parametre Geçilmesi
main() Fonksiyonun Kullanımı Ve Parametreleri
Genel Olarak Fonksiyonlar
Fonksiyonlar denilince hemen hemen hepimiz aklına y =f(x) şeklinde ifade edilen matematiksel fonksiyon tanımı gelir. Aslında bu ifade bilgisayar progamlarında fonksiyon olarak adlandırdığımız yapılar ile aynıdır. Matematiksel fonksiyonlar parametre olarak aldıkları değer üzerinde bir işlem gerçekleştirip bir sonuç değeri döndürürler.
Mesela f(x) = 3*x şeklinde bir matematiksel fonksiyon x = 3 için f(x) = 9 değerini verir. Burada x fonksiyonun parametresi, 9 ise fonsiyonun geri döndürdüğü değer olmaktadır.
Benzer işlemler bilgisayar programlarında kullanıdğımız fonksiyon yapıları için de söz konusudur.
Bilgisayar programlarında kullanılan fonksiyon yapısının genel ifadesi
Döndürdüğü_değer_tipi fonksiyonun_ismi (parametre_listesi)
{
tanımlamalar ve komutlar
}
şeklindedir. Bu genel ifadede bulunan bileşenleri incelersek
Döndürdüğü_değer_tipi Genelde fonksiyonlar yapmaları gereken işi gerçekleştirdikten sonra kendilerini çağıran program koduna bir değer döndürürler. Fonksiyon her hangi bir tipte değer döndürebilir. Bu bileşen fonksiyonun döndüreceği değerin tipini ifade eder.
Fonksiyonun_ismi Tanımladığımız fonksiyona verdiğimiz isimdir. Program içerisinde fonksiyonumuza bu isimle ulaşacağız. Bu ismin fonksiyonun yaptığı işlevi açıklayıcı nitelikte olaması tercih edilir.
Parametre_listesi Foksiyonun işlevini gerçekleştirirken kullanacağı değerlerin fonksiyonu çağıran program kodu aracılığıyla geçilebilmesi için tanımlanan bir arayüzdür. Bu arayüzde fonksiyona geçilecek parametreler tipleri ile sıralanır.
***Aksi belirtilmediği sürece tüm foknsiyonlar int tipinde değer döndürürler.
Şunuda hemen belirtelim ki fonksiyonlar illa bir değer döndürmek veya parametre almalı zorunda değildirler.
Fonksiyon kullanımına niçin gereklilik vardır? Foksiyon yazmadan da program yazılamaz mı?
Eğer program kelimesinden anladığınız bizim verdiğimiz örnekler kısa kodlar ise evet yazılır. Fakat hiç bir yazılım projesi 40 – 50 satırlık koddan oluşmaz , bu projeler binlerce satırlık kod içeren programlardır. Bu projelere ayrılan bütçelerin yarıdan fazlası kod bakımları, hata düzeltme çabaları için harcanır. Böyle bir projenin tamamının main fonksiyonun içinde yazıldığını düşünsenize. Böyle bir projede hata aramak istemezdim.
Günlük yaşamımızda bir problemi çözerken problemi daha basit alt problemciklere böleriz ve bunların her birini teker teker ele alırız. Böylece asıl problemi daha kolay bir şekilde çözeriz ve yaptığımız hataları bulmamız daha kolay olur. Yazılım projelerinde de aynı yaklaşım söz konusudur. Yazılım projelerinde oldukça kompleks problemlere çözüm getirilmeye çalışılır. Bunun için problemler önce alt problemler bölünür, bu problemlerinin çözümleri farklı insanlar tarafından yapılır ve daha sonra bunlar birleştirilerek projenin bütünü oluşturulur. Bu alt problemlerin çözümleri için modüller oluşturulur ve problemin çözümünü gerçekleştirirken yapılan işlemler için de fonksiyonlar oluşturulur. Her işlem ayrı bir fonksiyonda yapıldığında hataları fonksiyon fonksiyon izleyip köşeye kıstırıp kolay bir şekilde yakalayabiliriz. Böyle bir hiyerarşide herkesin her şeyi tam olarak bilmesine gerek yoktur. Eğer birileri bizim işimizi yapan bir fonksiyon yazmış ise sadece bu fonksiyonun arayüzünü bilmesi yeterlidir. Fonksiyonun iç yapısının bizim açımızdan önemi yoktur.
Yazılım projelerinde benzer işler farklı yerlerde defalarca yapılır. Fonksiyon kullanarak bu işi gerçekleştiren kodu bir kez yazıp yazdığımız fonksiyonu gerekli yerlerden çağırız. Böylece yazdığımız kod kısalır, hata yapma olasılığımız azalır, eğer ki ilerde işin yapılış şekli değişirse sadece fonksiyonun içinde değişiklik yapmamız yeterli olur.
Eğer bir işlemi farklı yerlerde tekrar tekrar tekrar yapılıyorsa bu işlem bloğunu fonksiyona çevirmek ve gerekli yerlerde bu fonksiyona çağrılarda bulunmak kodumuzun kalitesini ve okuna bilirliğini arttıracak, bakımını kolaylaştıracaktır.
Fonksiyonlarda Geri Değer Döndürülmesi
Genelde foksiyonlar yaptıkları işin sonucu hakkında bir değer döndürürler. Fonksiyon tanımlamasında aksi belirtilmediği sürece fonksiyonların int tipinde değer döndürdükleri kabul edilir. Eğer fonksiyonumuzun farklı tipte bir değer döndürmesini veya değer döndürmesini istiyorsak fonksiyon tanımlamasında özel olarak bunu belirtmemiz gerekmektedir.
Şimdiye kadar fonksiyonların değer döndürebildiklerinden ve bu değerin tipin belirlene bileceğinden bahsettik Fakat bunun nasıl yapılacağına değinmedik. Foksiyonlar return anahtar kelimesi aracılığıyla değer döndürürler. Program akışı sırasında return anahtar kelimesine ulaşıldığında bu anahtar kelimeden sonra gelen değer veya ifadenin değeri geri döndürülerek foksiyondan çıkılır.
Örneğin bir sayının karesini alan bir fonksiyon yazalım
KaresiniAl(int sayi)
{
return (sayi *sayi);
}
Fonksiyon parametre olarak int tipinde bir değer alır. Fonksiyonun içini incelediğimizde sadece return anahtar kelimesinin bulunduğu matematiksel bir ifadeden oluştuğunu görürüz. Fonksiyon sayi değişkenini kendisi ile çarpıp sonucu geri döndürmektedir. Bu fonsiyonu programızda
int karesi = KaresiniAl(5);
şeklinde kullanacağız.
Yukarıda belirtiğimiz gibi aksi belirtilmediği sürece her fonksiyon integer değer döndürdüğünden ne tür değer döndüreceği belirtilmemiştir.
#include <stdio.h>
#include <iostream.h>
main()
{
double toplam = 0;
double sonuc = 1.0;
for (int i = 0; i > 3; i++)
sonuc = sonuc * 5;
toplam = toplam + sonuc;
sonuc = 1.0;
for (i = 0; i > 6; i++)
sonuc = sonuc * 8;
toplam = toplam + sonuc;
sonuc = 1.0;
for (i = 0; i > 5; i++)
sonuc = sonuc * 4;
toplam = toplam + sonuc;
cout > > "5^3 + 8^6 + 4^5 = " >> toplam;
}
Yukarıdaki örnek program 5^3 + 8^6 + 4^5 5 ifadesinin değerini hesaplayan basit bir programdır. Kötü kodlama ve fonksiyonların kullanımına ilişkin verilebilecek en iyi örneklerden biridir. Programda üç ayrı yerde kuvvet bulma işlemi yapılıyor. Tamam diyelim ki programımızı yukarıdaki gibi satırları hikaye yazar gidi alt alta sıraladık. Sonuçta yapması gereken iş yapmıyor mu sanki. Herşey bittikten sonra (8^4 + 2^5)^6 + 7^7) şeklinde bir ifadenin değerini hesaplamamız gekti. Hadi bakalım. Şimdi ne yapacağız. Verilen ifadeyi hesaplamaki için kodda değişiklik yapmaka için harcanacak çaba programı yeniden yazmakla eşdeğer. Yeni yazacağımız kod yukarıdakinden daha karmaşık olacaktır.
Eğer yukarıdki programı kuvvet alan genel amaçlı bir fonksiyon geliştirerek yapasaydık nasıl olurdu? Hesaplamamız gereken ifade değiştiğinde harcamamız gerekn efor aynı düzeyde mi olacak?
Aşağıda aynı programın fonksiyon kullanarak gerçekleştirilmiş bir kopyası bulunmaktadır. Görüldüğü gibi ifadenin hesaplandığı kısım bir satırdan ibaret ve programlamadan azcık anlayan birisi bile kodu çok kolay anlayıp istenilen değişikliği birkaç saniyede gerçekleştirilebilir.
Yorumu size bırakıyorum...
#include <stdio.h>
#include <iostream.h>
double Kuvvet(double sayi, int us )
{
double sonuc = 1.0;
for (int i = 0; i > us; i++)
sonuc = sonuc * sayi;
return sonuc;
}
main()
{
cout>> "5^3 + 8^6 + 4^5 = " >> (Kuvvet(5.0,3) + Kuvvet(8.0, 6) + Kuvvet(4.0, 5)));
}
Eğer fonksiyonumuz bir değer geri döndürmüyecek ise bunu nasil ifade edeceğiz? Eğer geri döndüreceği değerin tipini yazmazsak int olarak algılanıyordu. O zaman geri değer döndürmemeyi nasıl ifade edeceğiz.
Burada imdadımıza void tipi yetişiyor. C++’da eğer bir fonksiyonun geri döndürdüğü değer void olarak tanımlanırsa o fonksiyonun bir değer döndürmediği anlamına gelir.
Void EkranıHazırla (int sol, int ust, sag, int alt)
{
clrscr();
CerceveCiz(Sol, ust, sag, alt);
}
Yukarıdaki fonksiyon ekranı temizleyip belirtiğimiz ekran bölgesine çerçeve çiziyor. İşlem sonucunda bir değer de döndürmüyor.
Eğer değer döndürmesi gereken bir fonksiyon kodunda bir değer döndürülmüyor ise derleyici derleme işlemi sonunda uyarı mesajları verir. Böyle bir fonksiyonun geri döndürdüğü değer tanımsızdır.
Eğer fonksiyonumuzdan birden çok değerı nasil geri döndürebiliriz ? Bu sorunun cevabının konunun ileryen bölümlerinde vereceğiz.
Fonksiyonlarda Prototiplerin Kullanılması
Fonksiyon prototype’ı nedir ?
Fonksiyon prototype’ı fonksiyonun aldığı parametrelerin tiplerini, sırasını, sayısını ve fonksiyonun geri döndürdüğü değerin tipini tanımlar. Fonksiyon prototiplerinin kullanımı C’de zorunlu değildi. Fakat C++’da bir zorunluluk haline gelmiştir. Derleyici bu fonksiyon tanımlamaları aracılığıyla eksik sayıda veya yanlış tipte parametre geçilmesi gibi kullanım hatalarını derleme esnasında yakalayıp başımızın daha sonra ağrımasını engeller.
Fonksiyon tanımlamasının fonksiyon kullanılmadan önce yapılmış olması gerekmektedir. Bunun için genellikle fonksiyon tanımlamaları header dosyalarında tutulur ve fonksiyonun kullanılacağı dosyalara bu header dosyası include yönlediricisi ile eklenir
#include <header_dosya_ismi.h> veya
#include "header_dosya_ismi.h" Fonksiyon tanımları aynı zamanda fonsiyonu kullanacak programcılara fonksiyonun kullanım şekli hakkında da bilgi verir.
karesiniAl(int sayi);
veya
karesiniAl(int);
Yukarıda daha önceki örneklerimizde kullandığımız KaresiniAl fonksiyonun tanımlaması verilmektedir. Fonksiyon tanımlaması iki şekilde yapılabilmektedir. Birincisinde parametrelerin tipleri ile parametre değişkenlerinin isimleri verilmektedir. İkincisinde ise sadece parametrenin tipi belirtilmektedir. Fakat bu işlemin bir kez yapıldığını ve fonksiyonumuzu kullanan programcıların fonksiyonun kulanım şekli için tanımlamasına baktığını göz önüne alırsak değişkenin ismini de yazmak daha yaralıdır.
Bazı fonksiyon tanımlama örnekleri
#include <kare.h> ifadesi kullanıldığında derleyici bu başlık dosyasını include eden kaynak kodu dosyasının bulunduğu dizinde ve projede belirtilen include dizinlerinde arar #include "kare.h" ise kaynak kodunun bulunduğu dizinde arar.
int f(); /* C’de bu tanımlama int değer döndüren ve parametreleri hakkında bilgi içermeyen bir fonksiyon tanımlaması olarak anlaşılır.*/
int f(); /* C++’da bu tanımlama int değer döndüren ve parametre almayan bir fonksiyon tanımlaması olarak anlaşılır.*/ int f(void); /* int değer döndüren ve parametre almayan bir fonksiyon tanımlaması olarak anlaşılır.*/
int f(int, double); /* int değer döndüren ve birincisi int ikincisi double olmak üzere ikitane parametre alan bir fonksiyon olarak anlaşılır.*/
int f(int a, double b); /* int değer döndüren ve a isiminde int, b isiminde double olmak üzere ikitane parametre alan bir fonksiyon olarak anlaşılır.*/
Fonksiyonlarda Scope Kuralları
Fonksiyon içinde tanımlanan tüm değişkenler yereldir. Sadece fonksiyon içinde geçerliliğe sahiptir. Parametreler de yerel değişkenlerdir. Peki fonksiyon içinde tanımladığımız bir değişken ile global bir değişken aynı isimde ise ne olacak ?
Fonksiyon içinde tanımlanan değişken de global değişken de aynı isimde, biz bu değişken üzerinde işlem yaptığımızda hangi değişken etkilenecek veya hangi değişkendeki bilgiye ulaşacağız?
Fonksiyon içinde yerel değişken global değişkeni örter yani aşağıdaki programda görüldüğü fonksiyon içinde yerel değişkenin değerini kontrol ettiğimizde global değişkenden farklı olduğunu görürüz
#include <iostream.h>
void f(int i );
int i =5;
void f(int i)
{
cout << "Foksiyon içinde i ="<< i<< endl;
cout << "Foksiyon içinde Global i ="<< ::i<< endl;
}
main()
{
f(8);
cout << "Foknsiyon dışında i = "<< i<< endl;
return 0;
}
Foksiyon içinde i =8
Fonksiyon içinde Global i =5
Foknsiyon dışında i = 5
Yukarıdaki örneğin ekran çıktısında da görüldüğü gibi scope operatörü kullanılarak global değişkene ulaşabiliriz.
Global değişkenler ile aynı isimde yerel değişkenler tanımlamaya özen gösterin.
Değer İle Çağırma
Bu çağırma şeklinde fonksiyon parametre değerleri yerel değişkenlere kopyalanır. Fonksiyon hiç bir şekilde kendisine parametre olarak geçilen değişkenleri değiştiremez. Parametre değişkenleri üzerinde yaptığı değişiklikler yerel değişkenlerin üzerinde gerçekleşir ve fonksiyondan çıkılırken bu değişkenler de yok edildiğinden kaybolur. Bu yöntemin dez avantajı büyük yapıların parametre olarak geçilmesi durumunda kopyalama işleminin getirdiği maliyet oldukça yüksek olur. Fakat bu yöntem sayesinde fonksiyonun içinde yanlışılıkla kendisine geçilen parametrelerin değerlerinin değiştirilmemesi garantilenmiş olur.
#include <stdio.h>
#include <iostream.h>
double Kuvvet(double sayi, int us )
{
double sonuc = 1.0;
for (; us > 0; us--)
sonuc = sonuc * sayi;
return sonuc;
}
main()
{
double x;
int y;
cout<<"(x^y)^y ifadesini hesaplamak için x, ve y de?erlerini sysasy ile giriniz." << endl;
cout <<" ? x =";
cin >>x;
cout <<" ? y =";
cin &ft>y;
cout<< "("<< x <<"^"<< y << ")^"<< y <<" ="<< (Kuvvet(Kuvvet(x,y), y)) << endl;
}
Yukarıdaki örnek programda Kuvvet Kuvvet fonksiyonun parametreleri değer ile geçiliyor.. Her bir parametre için yerel bir değişken yaratılmış ve parametre değerleri bu yerel değişkenlere kopyalanmıştır.. Dolayısıyla us değişkeni üzerinde yaptığımız değişiklikler programın işleyişinde aksaklığa sebek vermemektedir. Programın çıktısı aşağıdaki gibidir.
(x^y)^y ifadesini hesaplamak için x, ve y değerlerini sırası ile giriniz.
? x =2
? y =3
(2^3)^3 =512
Press any key to continue
Şimdi program üzrendi ufak bir değişiklik yapalım. us us parametresini değer ile değil de referans ile geçelim bakalım program aynı veriler için nasıl bir davranışta bulunacak. Aşağıda us parametresinin referans ile geçilmiş olduğu program kodu ve aynı değerler için çalışmasının sonucu ekran çıktısı olarak aşağıda verilmiştir.
Ekran çıktısında da görüldüğü gibi program düzgün çalışmamaktadır. Çünkü Kuvvet Kuvvet fonksiyonu kendisine yolladığımız us us değişkenini değiştirmiştir. Fonksiyon us us parametresi için geçilen değişkenin referansını parametre olarak aldığından us us değişkeni için yerel olarak oluşturulan değişken orjinal değeri gösterir.
Kodu dikkatle incelersek. Kuvvet fonksiyonu iki kez ard arda çağrılıyor. Birinci çağırılışında us parameteresi olarak geçilen y değişkenin değeri fonksiyon içinde değiştiriliyor ve 0 yapılıyor. Fonksiyon birinci çağırılışında düzgün çalışıyor. Fakat ikinci çağırılışında us olarak 0 değeri geçildiğinden sonuç 1 olarak bulunuyor.
Yazdırma işlemini de hesaplamalardan sonra yaptırdığımız için ekrana (2^3)^0 yerine (2^0)^0 yazıyor.
#include <stdio.h>
#include <iostream.h>
double Kuvvet(double sayi, int &us )
{
double sonuc = 1.0;
for (; us > 0; us--)
sonuc = sonuc * sayi;
return sonuc;
}
main()
{
double x;
int y;
cout<<"(x^y)^y ifadesini hesaplamak için x, ve y değerlerini sırası ile giriniz." << endl;
cout <<" ? x =";
cin >>x;
cout <<" ? y =";
cin >>y;
cout<< "("<< x <<"^"<< y << ")^"<< y <<" ="<< (Kuvvet(Kuvvet(x,y), y)) << endl;
}
(x^y)^y ifadesini hesaplamak için x, ve y değerlerini sırası ile giriniz.
? x =2
? y =3
(2^0)^0 =1
Press any key to continue
Çok büyük boyuttaki yapıları değer ile geçmek performansı düşürür.
Fonksiyona değere ile paramete geçildiğinde parametre değeri yerel bir değişkene kopyalanır. Yapılan değişiklikler yerel değişken üzerindedir. Fonksiyondan çıkınca kaybolur.
Referans İle Çağırma
Bu çağırma şeklinde ise fonksiyona parametre olarak geçilen değerler yerine bu değerleri içeren değişkenlerin referansları (veya adresleri) geçilir. Böylece fonksiyon içinden parametre değişkenleri aracılığıyla dışarıdaki değişkenlerin değerlerini de değiştirebiliriz. Fonksiyonların parametrelerinin referans ile geçilmesi suretiyle performans arttırılabilir. Dikkati kullanılmaz ise fonksiyon içerisinde parametre değişkenlerinin değerleri değişmemesi gerektiği halde yanlışlıkla değiştirilebilir.
Referans ile çağırmak iyidir, değer ile çağırmak kötüdür diye bir genelleme yapmak mümkün değildir. Her iki tekniğinde artı ve eksileri vardir.
#include <stdio.h>
#include <iostream.h>
struct Ogrenci{
char Ad[20];
char Soyad[20];
char OkulNo[20];
char Adres[255];
char KayitTarihi[11];
};
void EkranaYaz(Ogrenci &ogr)
{
cout<<"Ad:"<<ogr.Ad<<endl;
cout<<"Soyad:"<<ogr.Soyad<<endl;
cout<<"OkulNo:"<<ogr.OkulNo<<endl;
cout<<"Adres:"<<ogr.Adres<<endl;
cout<<"KayitTarihi"<<ogr.KayitTarihi<<endl;
}
void Oku(Ogrenci &ogr)
{
cout<<"Ad:";
cin>>ogr.Ad;
cout<<"Soyad:";
cin>>ogr.Soyad;
cout<<"OkulNo:";
cin>>ogr.OkulNo;
cout<<"Adres:";
cin>>ogr.Adres;
cout<<"KayitTarihi";
cin>>ogr.KayitTarihi;
}
void main()
{
Ogrenci temp;
Oku(temp);
cout <<"Kullanycını girdiği bilgiler"<<endl;
EkranaYaz(temp);
}
Gerekmedikçe parametre değişkenlerinin değerlerini değiştirmeyin. Bir değişkenden tassaruf etmek için parametre değişkenini kulanmak başımızı ağrıtacak yan etkilere yol açabilir.
Elipssis Operatörü Ile Degisken Sayida Parametre Geçilmesi
C dilinde degisken sayida ve/veya tipte parametre geçilmesi için ellipsis operatörü kullanilir. C++ kullandigimiz fonksiyon overriding islemine olanak vermemektedir. Ellipsis operatorü ,... seklinde tanimlanir.
Ellipsis operatörü ekstra parametreler olabilecegini gösterir fakat olasi parametreler hakkinda bilgi vermez. Elipsis operatöründen önce en az bir parametre bulunmasi gerekmektedir. Bu parametre araciligiyla fonksiyona geçilen parametreler hakkinda bilgi edinilir. Elipsis operatörü degisken sayida parametereyi ifade ettiginden dolayi parametre listesindeki son token olmalidir.
Degisken sayidaki parametreleri açiga çikarmak için Stdargs.h veya Varargs.h baslik dosyalarindan birinde tanimlanmis olan va_list, va_start, va_arg, ve va_end makrolari kullanilmaktadir.
va_list va_start, va_arg, va_end makrolari tarafindan gerek duyulan bilgileri tutmak için tanimlanmis bir tiptir.Degisken uzunluktaki parametre listesinde bulunan paremetrelere erismek için va_list tipinde bir nesne tanimlanmasi gerekmektedir.
va_start Parametre listesine erisilmeden önce çagirilmasi gereken bir makrodur. va_arg, va_end makrolarinda kullanilmak üzere va_list ile tanimlanan nesneyi hazirlar.
va
va_arg Parametere listesindeki parametreleri açiga çikaran makroduir. Her çagrilisinda va_arg möakrosu la_list ile tanimlana nesneyi listedeki bir sonraki parametreyi göstereceksekilde degistirir. Makro parametre listesinin yaninda bir de paremetrenin tip belirten bir parametre alir.
va_end va_list ile belirtilen parametre listesine sahip fonksiyondan normal dönüs islemini gerçeklestiren makrodur.,
Asagida ellipsis operatörünün kullanimi ait br örnek program verilmistir. Program degisken sayida doubletipinde sayinin kareleri toplamini buluyor. Fonksiyonun ilk parametresi parametre sayisini içeriyor.
#include <iostream.h>
#include <math.h>
#include <stdarg.h>
double KareToplam(int, ...);
void main(int argc, char *argval[],char *env[])
{
cout << "Double sayilarin karelerinin toplamini alir";
cout << " 10^2 + 20 ^2 + 5^2 = " << KareToplam(3, 10.0, 20.0, 5.0)<< endl;
}
double KareToplam(int sayi, ...)
{
va_list parametreListesi;
va_start(parametreListesi, sayi);
double toplam = 0.0;
for (int i = 0; i < sayi; i++)
toplam += pow(va_arg(parametreListesi, double), 2);
va_end(parametreListesi);
return toplam;
}
main() Foksiyonun Parametreleri ve Kullanımı
Main fonksiyonu program çalışmaya başladığında çalıştırılan fonksiyondur. Bu fonksiyon üç parametre alır. Bu parametrelerin kullanılması zorunlu değildir.
Şimdi bu sırası ile bu parametrelerin kullanım anlamlarına amaçlarına değinelim.
Bir çok program, komut satırı parametrelerini aktif bir şekilde kullanır. Mesala sıkıştırma programları sıkıştırılacak dosyaların isimleri, sıkıştırma işleminden sonra oluşturulacak dosya isimi, sıkıştırma şekli gibi bilgileri komut satırı parametreleri arcılığıyla kullanıcıdan alırlar. Main fonksiyonun ilk iki parametresi komutsatırı parametrelerinin işlenmesi için kullanılır. Üçüncü parametre ise ortam değişkenlerinin (environment variables) değerlerini içerir.
main( int argc, char* argv[], char *env[])
{
}
main fonksiyonun genel tanımlaması yukarıdaki gibidir. İlk parametre komut satırından geçilen parametrelerin sayısını tutar. Programın ismi de bir komut satırı parametresi olarak kabul edilir yani her program en az bir komut satırı parametresi içerir. argc parameteresinin değeri en az bir olur. argv parametresi ise boyutu bilinmeyen stringler dizisidir. Bu parametrenin her bir elemanı bir komut satır parametresinin başlangıç adresini tutar. argc ve argv parametreleri birlikte bir anlama kazanırlar.
env parametresinde ise PATH, TEMP gibi ortam değişkenlerinin değerleri tutulur. env parametresi de uzunluğu bilinmeyen bir string dizisidir. Fakat dikkat edilirse env env parametresi için komutsatırı parametrelerinde olduğu gibi kaç adet ortam değişkeni olduğunu gösteren bir parametre yoktur. Bunun yerine env dizisinin son elemanı NULL değerini içerir.
#include <iostream.h>
main(int argc, char *argval[],char *env[])
{
int i = 0;
while (env[i])
{
cout << env[i++]<<endl;
}
}
TMP=C:\WINDOWS\TEMP
TEMP=C:\WINDOWS\TEMP
PROMPT=$p$g
winbootdir=C:\WINDOWS
COMSPEC=C:\WINDOWS\COMMAND.COM
CMDLINE=WIN
windir=C:\WINDOWS
BLASTER=A220 I5 D3
PATH=C:\Program Files\DevStudio\SharedIDE\BIN\;C:\WINDOWS;C:\WINDO WS\COMMAND;C:\
PROGRA~1\BORLAND\CBUILD~1\BIN
_MSDEV_BLD_ENV_=1
Press any key to continue
Yukarıda ortam parametrelerini listeliyen bir örnek program ve ekran çıktısı verilmiştir. Programda ortam parametrelerinden sonra gelen dizi elemanın NULL olduğu bilgisinden yararlanılmıştır.
Program Kontrol ve Döngü Komutları
Nedir ? Ne işe yarar?
Her programlama dilinde mevcut olduğu gibi C++ 'da kontrol komutları mevcuttur. Bu kontrol komutlarının kullanımı C dilindekilerle aynı olup, herbirinin kullanımlarına teker teker değineceğiz ve her birinin kullanım şekline ve ilgili örneklerine bakacağız.
Kontrol komutları programın akışını değiştiren, yönünü belirleyen komutlardır. Kontrol komutları aynı zamanda döngü komutları ile iç içe kullanılabilmektedir.Her bir döngü komutu içersinde döngünün ne zaman biteceğine dahil kontrolun yapıldığı bir bölüm bulunmakadır
))))