Temel C++ 3. Gün: Fonksiyonlar, Girdi/Çıktı, İşaretçiler

Fonksiyonlar

Fonksiyonlar (Diğer adıyla metodlar) programları bölümlere ayırmaya yarar. Böylelikle proje büyükte sorun çıkarmaya başlayacak olan kod tekrarlarını da minimuma indirir. Yine de projenizi iyi tasarlamalısınız, aksi halde yararından çok zararı olur. Fonksiyonlar;

"geri döndüreceği veri tipi" "fonksiyon adı"(1. parametre, 2. parametre, n. parametre) şeklinde tanımlanır.

Örnek: int topla(int sayi1, int sayi2) int tipinde topla adında, sayi1 ve sayi2 olmak üzere iki parametresi olan bir fonksiyondur.

Fonksiyonlar konusunu basit bir örnek üzerinde göstermek en doğrusu olacaktır sanırım. Basit bir hesap makinesi örneğiyle hem önceki konuları pekiştirelim hem de fonksiyonların mantığını anlayalım.

Hesap Makinesi:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#include <iostream>

using namespace std;

// void tipinde yani geri deger dondurmeyecek
// int tipinde s1 ve s2 olmak uzere iki parametre alan
// topla isimli bir fonksiyon tanimladik.
void topla(int s1, int s2)
{
cout << "Toplama islemini sectiniz. ";
cout << "Iki sayi toplanip ekrana yazilacak." << endl;

cout << "Toplam sonucu: " << s1 + s2 << endl;
}

// geriye int tipinde bir deger dondurecek olan
// cikar isimli, iki parametreli fonksiyonumuz
int cikar(int s1, int s2)
{
cout << "Cikarma islemini sectiniz. ";
cout << "Buyuk sayidan kucuk sayi cikartilacak." << endl;

if(s1 > s2)
return (s1 - s2);
else if (s2 > s1)
return (s2 - s1);
else
return 0;
}

// topla fonksiyonunun carpma islemi icin degistirilmis hali
// geriye deger dondurmeyen carp isimli fonksiyonumuz
void carp(int s1, int s2)
{
cout << "Carpma islemini sectiniz. ";
cout << "Iki sayi carpilip ekrana yazilacak." << endl;

cout << "Carpim sonucu: " << s1 * s2 << endl;
}

// geriye int tipinde bir deger dondurecek olan fonksiyonumuz
int bol (int s1, int s2)
{
cout << "Bolme islemini sectiniz. ";
cout << "Buyuk sayi kucuk sayiya bolunecek." << endl;

if (s1 > s2)
return (s1 / s2);
else if (s2 > s1)
return (s2 / s1);
else
return 1;
}

int main()
{
int secim = 0, sayi1 = 0, sayi2 = 0;
cout << "Hesap makinesine hosgeldiniz. Iki sayi giriniz: " << endl;
cin >> sayi1 >> sayi2; // kullanicidan iki sayi aldik.

// menumuz.
cout << "" << endl;
cout << "Islem Listesi: \n";
cout << "Toplama icin 1, \n";
cout << "Cikarma icin 2, \n";
cout << "Carpim icin 3, \n";
cout << "Bolum icin 4, \n";
cout << "ve cikis icin -1 girin; \n";

// yanlis secim icin geri donus noktasi.
secimAsamasi:

cout << "Seciminiz: ";
cin >> secim;

switch(secim)
{
case -1:
cout << "Cikisi sectiniz." << endl;
break;
case 1:
// aldigimiz degerleri topla fonksiyonumuza yolladik.
topla(sayi1, sayi2);
break;
case 2:
// degerleri cikar fonksiyonumuza yollayip donen degeri yazdik.
cout << "Cikarma sonucu: " << cikar(sayi1, sayi2) << endl;
break;
case 3:
// degerleri carp fonksiyonumuza yolladik.
carp(sayi1, sayi2);
break;
case 4:
// degerleri bol fonksiyonumuza yollayip donen degeri yazdik.
cout << "Bolum sonucu: " << bol(sayi1, sayi2) << endl;
break;
default:
cout << "Hatali secim yaptiniz. Lutfen tekrar secin." << endl;
// hatali secim yapilmasi halinde secimAsamasi isimli
// alana donulmesini belirttik.
goto secimAsamasi;
break;
}
return 0;
}

Girdi / Çıktı İşlemleri (Dosyalar)

Ufak programlar dışındaki çoğu program dosyalar ile çalışır. Dolayısıyla dosya oluşturmak, okumak ve yazmak için belirli fonksiyonlara ihtiyaç vardır. Burada devreye fstream kütüphanesi devreye giriyor. Vektörleri kullanmak için nasıl vector kütüphanesini kullandıysak burada da aynı şekilde fstream kütüphanesini kullanacağız.

Dosyalar şu kurala uygun şekilde programa dahil edilir;

Dosyaya yazmak için: ofstream değişken adı ("dosya adı", açma modu)
Dosyadan okumak için: ifstream değişken adı ("dosya adı", açma modu)

Her iki mod için birer örnek yapalım.

Girdiğiniz adı ve soyadı dosyaya yazan program örneği:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <iostream>
#include <string>
// dosya islemlerini yapabilmek icin
// fstream kutuphanesini programa dahil ettik.
#include <fstream>

using namespace std;

int main()
{
// dYaz -> "dosya.txt" isimli dosyayi
// ios::out modunda aciyoruz.
ofstream dYaz("dosya.txt", ios::out);
// ios::out -> bu modla acilan dosyalara
// daha onceden veri girildiyse eger
// yeni veriler onceki verilerin uzerine yazilir
// yani veri kaybi yasanir.

// diger mod ios::app -> verileri yazmaya
// dosyanin sonundan baslar. veri kaybi olmaz.

string ad, soyad;
cout << "Adiniz: ";
getline(cin, ad);
cout << "Soyadiniz: ";
getline(cin,soyad);

// cout yerine yukarida tanimladigimiz ismi kullaniyoruz.
dYaz << ad << " " << soyad << endl;

// isimiz bittiginde dosyayi kapatiyoruz.
dYaz.close();
return 0;
}

Dosyaya yazdırdığınız adı ve soyadı okuyup ekrana yazan program örneği:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// ios::in modunda "dosya.txt" isimli dosyayi aciyoruz.
ifstream dOku("dosya.txt", ios::in);

string okunanAd, okunanSoyad;

// dosyanin sonuna gelene kadar
// dosyada bulunan tüm verileri okuyabilmek icin
// eof() fonksiyonu kullanilabilir.
while (!dOku.eof())
{
// okuma yapmak icin cin yerine yukarida
// tanimladigimiz ismi kullaniyoruz.
dOku >> okunanAd >> okunanSoyad;
}
// tek verimiz oldugu icin dongu disinda ekrana yazdiriyoruz.
cout << okunanAd << " " << okunanSoyad << endl;

// isimiz bittiginde dosyayi kapatiyoruz.
dOku.close();

İşaretçiler (Pointers)

İşaretçiler, değişkenlerin aksine değer yerine değerin adresini saklarlar. Bellek yönetimi açısından çok önemlidirler. İşletim sistemleri ve oyunlar gibi yazılımlarda çok fazla kullanılırlar. Aynı değişkenler gibi tanımlanırlar tek farkları başlarına * getirilmesidir. Tanımlama örneği;
int *sayi;

Basit örnek:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>

using namespace std;

int main()
{
// int tipinde bir degisken ve isaretci tanimladik.
int sayi = 8, *pSayi;
// & referans operatorünü kullanarak
// sayi degiskeninin adresini
// pSayi isimli isaretciye atadik.
pSayi = &sayi;

// degiskenin kendisini kullanarak
// degerini ve adresini yazdirdik.
cout << "Sayi degiskeninin degeri: " << sayi << endl;
cout << "Sayi degiskeninin adresi: " << &sayi << "\n" << endl;

// isaretciyi kullanarak
// sayi degiskeninin degerini ve adresini yazdirdik.
cout << "Sayi degiskeninin degeri: " << *pSayi << endl;
cout << "Sayi degiskeninin adresi: " << pSayi << endl;
return 0;
}

Bu örnekten sonra neden işaretçilere gerek olduğu konusunda akılda bir soru oluşabilir. Bölüm başında anlattığımız fonksiyonlarda parametre olarak int tipinde değişken alıyorduk ve böyle yaptığımızda değişkeni kopyalamış oluyoruz. Bu da bellekte iki kat daha fazla yer kaplaması anlamına geliyor. Fakat eğer değerleri fonksiyonlara işaretçi yoluyla yollarsak bu sorun ortadan kalkmış oluyor.

İşaretçi konusu genelde yeni başlayanlar tarafından oldukça kafa karıştırıcı bulunur. Bu yüzden en basit şekilde açıklayıp burada bırakmayı doğru buluyorum. Bu konuda daha fazla örneği internet üzerinden bulabilirsiniz.

Sonraki Bölüm: Sınıflar, Nesneler:
Temel C++ - 4. Gün: Sınıflar, Nesneler