Compiler, linker ve loader arasındaki ilişkiyi anlatınız.
Ref: https://www.youtube.com/watch?v=m1UzSfgjA4Y&ab_channel=VijayVishwakarma
Data, heap, code/text, environment segmentlerini tanımlayınız.
Ref: https://www.youtube.com/watch?v=m1UzSfgjA4Y&ab_channel=VijayVishwakarma
Ref: https://www.youtube.com/watch?v=_8-ht2AKyH4&ab_channel=mycodeschool
Ref: https://www.youtube.com/watch?v=m1UzSfgjA4Y&ab_channel=VijayVishwakarma
Method ve function arasındaki fark nedir?
Method: sınıfa bağlı fonksiyon Function: sınıfa bağlı olmayan serbest fonksiyon
Ref: https://www.btkakademi.gov.tr/portal/course/player/deliver/c-ile-programlamaya-giris-20172 (0:30)
"Metodlar nesne sayısı kadar RAM'de yer alır" doğru mudur, açıklayınız?
Nesne sayısı kadar sınıfın özellikleri vardır ancak mehod sayısı 1 olup her method çağrısında hangi nesne için bu methodun çalışacağı bilgisi geçirilir (msg2.yaz()
).
Ref:https://www.youtube.com/watch?v=0jhQBQcGnuM&ab_channel=ThinkAloudAcademy
Aşağıdaki ifadeler neyi verir?
#include <iostream>
using namespace std;
int main() {
int x = 10;
int *p = &x;
// işaretçi ile x'i göstermek
cout << *p; // ??? yazdırır
*p = 20;
cout << &*p; // ??? yazar
cout << p; // ??? yazar
cout << ++*p; // ??? yazar
cout << (*p)++; // ??? yazar
// referans ile x'i göstermek için:
int &r = x;
cout << ++r; // ??? yazar
cout << r++; // ??? yazar
r = 30;
// referansı işaretçi ile göstermek
int *pr = &r;
*pr = 40;
cout << x; // ??
}
int main() {
int x = 10;
int *p = &x;
// işaretçi ile x'i göstermek
cout << *p;// p, x'i gösterir. *p ise x'in değerini yani 10 yazdırır
*p = 20;
cout << &*p; // *p yani x'in değerine 20 atanır
cout << p; // x'in adresini p işaretçisine atadığımız için x'in adresini yazar (Örn. 0x7ffc79aa896c)
cout << ++*p; // x'in değerini önce 1 arttırır sonra yazar (21)
cout << (*p)++; // x'in değeri 21 olduğu için önce yazdırır sonra 1 arttırır (22) ancak yazdırmaz.
// referans ile x'i göstermek için:
int &r = x;
cout << ++r; // x 22 ve r 1 arttırıldığında x'in değeri 23 olur ve yazdırır.
cout << r++; // r'nin değeri olan 23'ü yazdırır sonra 1 arttırır.
r = 30;
// referansı işaretçi ile göstermek
int *pr = &r;
*pr = 40;
cout << x; // x'in değeri 40 olur
}
Aşağıdaki kodda deklaratör ve operatör hangileridir?
double d = 10;
double* dptr = &d;
double& rVal = d;
*dptr++;
double* dptr..
bildirimde kullanıldığı için *
deklaratör, = &d
ifadesinde &
address of operatörü ve *dptr++
ifadesindeki *
dereferencing operatörüdür. *dptr++
ifadesindeki *
, dereferencing için kullanıldığından operatördür. double& rVal...
içindeki & deklaratördür.
En yaygın declarator ler:
*
- pointer - prefix*const
- constant pointer - prefix&
- reference - prefix[]
- array - postfix()
- funtion - postfix
Hangi varlıklar default initialize (varsayılan başlatılamaz) edilemez?
const
nesneler ve r value nesneler
const int x;
x değeri atanmadan başlatılamaz.const
nesneler default initialize ediliemez.double& rvalue;
referanslar default initialize edilemezauto
ile deklare edilen değişkenler
Kaç referans türü vardır, söyleyiniz?
3 referans vardır:
- R value
- L value
- standartların tanımına göre forwarding reference (Scott Meyers'in tanımıyla universal reference)
int x = 10;
// aşağıdaki kodda && ile işaret edilen universal reference olur.
// hem sol taraf referansını hem doğrudan değeri yani sağ taraf referansını atayabildiğimiz için "universal reference" diğer bir adıyla "forwarding reference" diyoruz.
int&& y = x;
int&& z = 5;
"Function returning pointer" diye çağırılan int
türünde bir değeri dönen fonksiyon örneğini işaretçi ve referans dönecek şekilde 2 fonksiyonu da yazınız.
int i = 10;
int* func_p() {
return &i;
}
int& func_ref() {
return i;
}
int main() {
int* p = func_p();
*p = 20;
// ya da
*func_p() = 30;
// referans değer ile ile
func_ref() = 20; // i'nin değerine 20 atanmış olur.
}
Aşağıdaki kod çalışır mı, çıktı ne olur?
int i = 10;
int* func_p() {
return &i;
}
int main() {
cout << ++* func_p();
}
önce fonksiyon operatörü (()
postfix operatörlü func_p()
) çalışır sonra dereferencing operatörü (*
) çalışacak, en sonunda dönen değer 1 artacak ve 11 yazacaktır.
Sol taraf referansı ile neyi amaçlarız?
İşaretçilerde nesneye erişmek için dereferencing (*ptr
) kullanıyorken bunun yerine referans değişken nesneyi doğrudan kullanabilmemizi sağlar.
int x=10;
// pointer kullanarak:
int* ptr = &x;
*ptr++ ;
// yerine aşağıdaki gibi ref kullanabiliriz:
int& ref = x;
ref++ ;
// işaretçiye bağlanmış sağ referans değişkeni şöyle okuyabiliriz:
// "int* tipinde referans değişkeni" > int*&
int*& refForPtr = ptr;
// Ve işaretçiye bağlanmış referans değişkeninin değerini değiştirelim:
*refForPtr = 30; // artık x'in değeri 30 olacaktır.
// Int türünün pointer değişkenini (yani ptr'yi) yeni bir int değişkene olan y'ye atayalım
int y = 40;
refForPtr = &y;
cout << *refForPtr << endl; // 40
Referansları doğrudan başlatabilir miyiz?
Değeri/nesneyi doğrudan atayamayız. Bir R value referansa ancak bir L value referansı atayabiliriz. Ancak değer/nesnenin bağlanmış olduğu bir değişkeni yani L value referansı hem atamayla hem de brace initializiation ile R value referansa bağlayabiliriz.
int x = 10;
// 3 yöntemle de başlatabiliriz (atama, direct, brace)
int& rVal = x;
int& rVal(x);
int& rVal{ x };
#include <iostream>
using namespace std;
int i = 10;
int* func_p() {
return &i;
}
int main() {
cout << *func_p(); // 10
cout << func_p(); // 0x403010
int& r = *func_p(); // int& r = i; ataması gibidir.
r = 12;
cout << "r: " << r << "; i:" << i; //r: 12; i:12
}
int x[5][10][15]{1};
??? = x[5][2];
??? yerine referans tür ifadesi nasıl yazılmalıdır?
int (&r)[15] = x[5][2];
nullptr bir nesne midir? Nesne ise nullptr yerine geçecek referans türünü yazınız.
nullptr nesnedir ve referans ile gösterilebilir.
int* ptr = nullptr
int* &r = ptr;
ptr yerine r referansını kullanabiliriz.
Aşağıdaki kodda yapılan atamaların her satırında x ne değeri alır?
Ve r = y
atamasıyla r referansına y değerini bağlamış olur muyuz?
int x{3};
int& r(x);
cout << x << endl; // ?
r = 10;
cout << x << endl; // ?
++r;
cout << x << endl; // ?
int y = 20;
r = y;
cout << x << endl; // ?
Bir referansı bağlandığı nesneden başka bir nesneye bağlamak mümkün değildir.
int x{3};
int& r(x);
cout << x << endl; // 3
r = 10;
cout << x << endl; // 10
++r;
cout << x << endl; // 11
int y = 20;
r = y;
cout << x << endl; // 20
// referanslar sadece bir kez bağlanabilir (bind) bu yüzden r değeri sadece x yerine geçer ve x'e bind edildikten sonra başka bir değere (y'ye) bağlanamaz.
Aşağıdaki kodda r2 neyi gösterir:
int x(10);
int& r1{x};
int& r2 = r1;
++r1;
cout << x << endl; // ?
cout << r1 << endl; // ?
cout << r2 << endl; // ?
++r2;
cout << x << endl; // ?
cout << r1 << endl; // ?
cout << r2 << endl; // ?
int x(10);
int& r1{x};
int& r2 = r1;
// Bir referansa atanmış referans ile ilk referansın işaret ettiği değeri (x'i) bağlamış oluruz (bind). r2 de r1 gibi x'i refere edecektir.
++r1;
cout << x << endl; // 11
cout << r1 << endl; // 11
cout << r2 << endl; // 11
++r2;
cout << x << endl; // 12
cout << r1 << endl; // 12
cout << r2 << endl; // 12
Aşağıdaki const
ile neyi sağlarız?
int x = 10;
int* const p = &x;x
p işaretçisi yaratıldığı kapsamı boyunca sadece x'i gösterir başka bir nesneyi gösteremez hale getirirlir. x'in değeri *p
ile değiştirilebilir.
flags
Türünün üyelerinin alabileceği değer aralıkları yorum satırlarında belirtilmiştir. Tanımlı haliyle flags
türünden bir nesnenin kaplayacağı toplam boyutu ve flags
türünü bit-field kullanarak ihtiyaca göre yer kaplayacak şekilde yazdıktan sonra üyeleri ihtiyacımıza uygun tanımladığınızdaki boyutunu yazınız.
struct Flags {
unsigned int bayrak1; // 0..1 > 0 veya 1 değeri alır
unsigned int bayrak2; // 0..3 > 0,1,2,3 değerlerinden birini alır
unsigned int bayrak3; // 0..2 > 0,1,2 değerlerinden birini alır
};
Her bir üyenin unsigned int
olarak (4*3) 12 byte yer kaplar.
Her üyeyi bit-field olarak tanımladığımızda toplam 4 byte yer kaplayacaktır.
struct Flags{
unsigned int bayrak1 : 1; // 1 bit > 0..1 arasında değer alır
unsigned int bayrak2 : 2; // 2 bit > 0,1,2,3 değerlerinden birini alır
unsigned int bayrak3 : 2; // 2 bit > 0,1,2,3 değerlerinden birini alır
};
En fazla 7 değeri alabilen, işaretsiz bir tamsayı bit-field üyesi olan bir struct tipinin tanımını yazınız.
(cppreferans)[https://en.cppreference.com/w/cpp/language/bit_field]
struct S {
// 3 bit uzunluğundaki b, 0...7 arasında değer alabilir
unsigned int b : 3;
};
int main() {
S s = {6};
++s.b; // 6 değeri 1 arttırılarak 7'ye yükselir
std::cout << s.b << '\n'; // 7
++s.b; // Değer 8 olmalı ancak aralık 0..7 olduğu için 0'a atanır
std::cout << s.b << '\n'; // 0
}
Integral promotion nedir?
Bir karakter (char
), short int
veya bir integer bit-field (int a:2;
), tümü işaretli olsun veya olmasın veya numaralandırma türünde bir nesne, bir tamsayının kullanılabileceği her yerde bir ifadede kullanılabilir. Bir int
, orijinal türün tüm değerlerini temsil edebiliyorsa, değer int
'e dönüştürülür; aksi takdirde değer unsigned int
'e dönüştürülür. Bu sürece entegre promosyon (integral promotion) denir.
Dinamik ve statik tür kavramları arasındaki fark nedir?
Dinamik türleri çalışma zamanında, statik türleri derleme zamanında kullanabiliriz. Statik tip kontrolü, derleme zamanında yapılan tip kontrolüdür. Bu, C++'ın yaptığı tek tür denetleme şeklidir. Dinamik tip kontrolü, çalışma zamanında yapılan tip kontrolüdür. Bu genellikle dinamik olarak yorumlanan dillerde görülür, ancak derlenmiş dillerde daha az yaygındır
Dinamik ve statik programlama dilleri arasındaki fark nedir?
Dinamik ve statik yazılan diller için;
- dinamik olarak yazılan diller çalışma zamanında tip kontrolü gerçekleştirirken, statik olarak yazılan diller derleme zamanında tip kontrolü gerçekleştirir. Bu, dinamik olarak yazılan dillerde (Groovy gibi) yazılan komut dosyalarının, komut dosyasının düzgün çalışmasını (eğer varsa) önleyecek hatalar içerse bile derlenebileceği anlamına gelir. Statik olarak yazılmış bir dilde (Java gibi) yazılmış bir komut dosyası hatalar içeriyorsa, hatalar düzeltilene kadar derlenemez.
- statik olarak yazılan diller, değişkenlerinizin veri türlerini kullanmadan önce bildirmenizi gerektirirken, dinamik olarak yazılan diller bunu yapmaz.
Type deduction yani "tür çıkarımı" nedir? Derleme mi çalışma zamanınında mı çalışır?
Tamamen derleme zamanıyla ilgilidir.
auto
, decltype
, decltype(auto)
, template
tür çıkarım anahtarlarını kullanırız.
auto
, bildirilen bir değişkenin türünü başlatma ifadesinden çıkarır.decltype
type belirtici, belirtilen bir ifadenin türünü verir.decltype
tip belirleyicisi,auto
anahtar sözcüğüyle birlikte, öncelikle şablon kitaplıkları yazan geliştiriciler için kullanışlıdır. Dönüş türü, şablon bağımsız değişkenlerinin türlerine bağlı olan bir işlev şablonu bildirmek içinauto
vedecltype
kullanın. Veya, başka bir işleve yapılan çağrıyı sarmalayan ve ardından sarmalanmış işlevin dönüş türünü döndüren bir işlev şablonu bildirmek içinauto
vedecltype
kullanın.
Aşağıdakilerden hangileri auto
tür çıkarım anahtarının özelliklerinden değildir?
- i)
auto
anahtarıyla tanımlanan değişkenler default initialize edilmez - ii)
auto
anahtarı eğer değişken, tanımlanırken değer alıyorsa kullanılır - iii)
auto
anahtarı fonksiyon parametreleri için de kullanılmaz - iv)
auto
değişkenler, yerel değişkenler gibi çalışmaktadır. Geçerli oldukları fonksiyondan veya kapsamdam (scope) çıkılınca hafızadan atılır ve yeniden geçerli oldukları kısma veya fonksiyona girildiğinde yeniden oluşturulurlar.
auto tanımlı parametreler C++20 itibarıyla kullanılabilir. Bu yüzden iii hatalı olacaktır.
Aşağıdaki auto
tanımlı tür çıkarım ifadelerinde auto
'nun türü nedir?
- i)
char c = 'a';
auto x = +c;
- ii)
const int cx = 6;
auto y = cx;
- iii)
int x = 10;
int& r = x;
auto y = r;
- iv)
int x = 10;
const int& r = x;
auto y = r;
- v)
int a[] = {1,2,3,4,5};
auto y = a;
- i)
int
türündedir çünkü char türündekic
değişkeni integral promotion ileint
türüne terfi edecektir+
operatörüyle. - ii)
int
türündedir çünkü cx'in türüconst int
olsa dahi y'nin türündeconst
düşecekint
olacaktır - iii) Referans değişkenin referans olması tür çıkarımında etkili değil bu yüzden y'nin türü
int
olacaktır. - iv)
const
ve referans özellikleri düşer y'nin türüint
olur. - v)
int*
türünde olacaktır y.
Aşağıdaki auto
tanımlı tür çıkarım ifadelerinde auto
'nun türü nedir?
- i)
const int a[] = {1,2,3,4,5};
auto y = &a;
- ii)
const int x = 10;
auto y = &x;
- iii)
auto y = "isim";
- iv)
const int x = 5;
auto y = &x;
- v)
const int x[5]{};
auto y = x;
- i)
const int*
türünde olacaktır yaniconst int (*y)[5]
. - ii)
y=x
olduğunda değeri,y=&x
olduğunda nesneyi geçirdiğimiz içinconst
ifadesi kalacak veconst int
türünde olacaktır y. - iii)
const char*
türünde olacaktır. Sağ taraf const char olacak yaniconst char *y = "isim"
gibi tanımlanmış olacak. - iv)
const int *y
türünde olacaktır y. - v)
const int*
türünde olacaktır y.
- i)
auto x = 0;
ifadesinde x'in türü ne olur? - ii)
auto y = 0u;
ifadesinde y'nin türü ne olur? - iii)
auto z = 0.;
ifadesinde z'nin türü ne olur?
- i)
int
- ii)
unsigned int
- iii)
double
Aşağıdaki tanımlamaların hangileri doğrudur?
- i)
auto x;
- ii)
auto x{};
- iii)
auto x = ifade;
Doğru. auto x = ifade;
ile tanımlanan değişkenin türü = ifade
ile belirlenir. Bu yüzden ilk değer vermek mecburidir.
Yani i ve ii yanlış iii doğrudur.
- i) Aşağıdaki
int a[]{1,2,3,4,5};
ifadesindekia
değişkeninin türü nedir? - ii)
a
değişkeni Sağ taraf referansı mı (R value), Sol taraf referansı (L value) mıdır? - iii)
a
değişkenin işaret eden pointer nasıl tanımlanır? - iv)
a
değişkeninin referans değişkeni nasıl tanımlanır? - v) Aşağıdaki ifadeler doğru mudur?
int& ra = a;
int* p1 = a <denktir?> int* p2 = &a[0] <denktir?> int* p3 = ra <denktir?> auto& ra = a
- i) a'nın türü:
int[5]
'dir. - ii) L value çünkü R value & declaratörü ile ifade edilir.
- iii)
int(*ptr)[5] = &a;
- iv)
int (&ra)[5] = a;
- v) Doğrudur
5 Elemanlı int dizisinin (int a[5]
) tür tanımı için Type alias (tür eş adı) kullanımında aşağıdakilerden hangileri doğrudur?
- a)
typedef int diziTipi[5];
diziTipi& rDizi = a;
- b)
using diziTipi = int[5];
diziTipi& rDizi = a;
Her ikisi de doğru tanımlamadır.
Kullanıcı tanımlı bir yapı tipinde referans kullanımına örnek veriniz.
struct Veri {
int a, b;
}
int main() {
Veri v{1,2};
cout << v.a << endl; //1
cout << v.b << endl; //2
Veri& rv = v;
cout << rv.a << endl; //1
rv.b = 12;
}
int x = 10;
int* p = &x;
- i)
*p
ifadesinin türü nedir? - ii)
p
değişkeninin türü nedir?
- i)
int
- ii)
int*
(int türünde işaretçidir)
int x = 10;
int& r = x;
- i) r ifadesinin türü nedir?
- ii) r değişkeninin türü nedir?
- i) int
- ii) int ref (int türünde referanstır)
Neden sol taraf değerlerini (referanslar) neden kullanırız?
- Bir fonksiyona bir nesneyi call by reference olarak göndermek için
- Bir fonksiyon bir nesneyi kendisini çağıran fonksiyona döndürmek için
"Call by reference" ve "call by value" örnekleri yazınız.
// call by value
void func_byvalue(int v){
v = 10;
}
int main(){
int i = 1;
cout << i << endl; // 1
func_byvalue(i)
cout << i << endl; // 1
}
// call by value
void func_byref(int* p){
*p = 10;
}
int main(){
int i = 1;
cout << i << endl; // 1
func_byvalue(&i)
cout << i << endl; // 10
}
// call by value
void func_byref(int& r){
r = 10;
}
int main(){
int i = 1;
cout << i << endl; // 1
func_byvalue(i)
cout << i << endl; // 10
}
auto İle yapılan tür çıkarımına (type deduction) göre türleri belirtiniz.
- i)
auto x = 5;
- ii)
auto x {5L};
- iii)
auto x (5.5);
- iv)
auto x = {5};
- v)
auto x { 5, 6 };
- vi)
int x = 10;
auto x1 = &x; // x1?
auto* x2 = &x; // x2?
- vii)
int x = 10;
int *p = &x;
auto p1 = &p; // p1 ?
auto* p2 = &p; // p2 ?
auto** p3 = &p; // p3 ?
- i)
int
- ii)
long int
- iii)
double
- iv)
list
- v) Geçersiz! 2011 Standartlarında geçerliyken artık geçersiz. Ancak 1 değer içeren küme parantezinde tipi int olurken birden fazla eleman alacağı zaman
auto x = {,,,}
şeklinde atama yapılması gerekir. - vi) x1 için
int *x1 = &x;
ve x2 içinint *x2=&x;
- vii) p1, p2, p3 eşitliğin sağ taraflarında işaretçinin adresi (
&p
) olduğu için pointer to pointer (int **px
) olmak zorunda. auto'ların değerleri buna göre:
int x = 10;
int *p = &x;
auto p1 = &p; // auto ==> int** Çünkü p1'in türleri int** olacaktır
auto* p2 = &p; // auto ==> int* Çünkü p2'nin türleri int** olacaktır
auto** p3 = &p; // auto ==> int Çünkü p3'ün türleri int** olacaktır
auto
ile belirtilen ifadelerin doğru veya hatalı olduğunu belirtiniz.
- i)
auto x;
- ii)
auto x=5, y;
- iii)
auto x=5, y=2.5;
- iv)
auto x(10), y{x};
- v)
const auto x {10}, y=5;
- vi)
static auto x=10;
- i) Hatalı! Sağ taraf tanımı olmak zorundadır.
- ii) Hatalı! x için değer int olacak ve y için de bu tip kullanılacak ancak atama olmaksızın bir
auto
tanımı kullanamayız. - iii) Hatalı! Çünkü
auto x=5
ifadesiyleauto
içinint
tespit edilmiş ancaky=2.5
iledouble
olması gerekir anca tek satırda tanımlı oldukları için sözdizimi hatası alırız. - iv) Geçerli. x Değişkeni
int
türünde ve 10 değerine sahip olmuş ve ardındany=x
ataması yapılmış. - v) x ve y sabit ve başlangıç değerlerine sahip
int
türünde başlatılır. - vi)
static int
olarak x tanımlanmış olur.
Çıktı ne olur?
int main() {
for(int i=0;i<10;i++) {
static auto x = 5;
std::cout << x++ << " ";
}
}
5 6 7 8 9 10 11 12 13 14
auto Hangi türe denk gelecektir?
auto&& p = 20;
&&
iki tane referans deklaratörü kullanılırsa forwarding referans deklaratörü denir. 20 değeri int türündedir ve int &&p
olacaktır.
Aşağıdaki auto ile çıkarılan fonksiyon işaretçisinin typedef ile tür çıkarımını yaparak çağırınız.
int foo(int);
int main() {
auto f1 = &foo;
}
typedef int(*foo_işaret_eden_tür_adı)(int);
ile foo
işlevinin türünü çıkarır ve f1
değişkenini bu türden yaratarak foo
işlevini değer olarak atarız.
int foo(int);
int main() {
typedef int(*foo_def)(int);
foo_def f1 = foo;
f1(12);
}
void func(int* p);
void func(int& r);
- i) Yukarıdaki iki fonksiyonun aynı sınıfta tanımlanması halinde function overloading sağlanır mı?
- ii) Overloading oluyor ise bu senaryo tercih edilir mi, neden?
- i) Evet ikisinin aynı sınıfta olması function overloading demektir
- ii) Tercih edilmez çünkü ikisi de aynı şekilde "call by reference" fonksiyonu olup kodlama düzeyinde ayrıştıralamaz benzerliktedirler.
int a[3]{};
auto x1 = a;
auto x2 = &a;
Yukarıdaki koda göre x1 ve x2 değişkenlerinin türleri ne olacaktır?
auto
anahtarıyla tanımlanan değişkene bir dizi atandığında da array to pointer decay dönüşümünü görürüz. a
Bir dizidir ve x1
değişkenine atandığında dizinin işaretçiye dönüştürüldüğünü görürüz.
Ancak a
'nın adresini atadığımızda &a
, 3 boyutlu bir diziyi işaret ettiği için bu kez x2
değişkenine 3 boyutlu bir diziyi gösteren pointer olarak ataması yapılır.
int foo(int);
int main() {
auto f1 = foo;
auto f2 = &foo;
auto &f3 = foo;
auto f4 = &f1;
}
f1, f2, f3 ve f4'ü tanımlayan auto ifadelerinin türleri nedir?
foo
Fonksiyonunu f1, f2 ve f3 değişkenlerine atarken auto anahtarının alacağı değerler;
f1
için function-to-pointer dönüşümü ileint (*f1)(int)
. Buradaki atama implicit (örtülü) olacak (f1 = foo
) yanifoo
işlevinin derlenmiş bu ikili dosyadaki yerini f1 işaretçisine atama işini derleyici anlayıpint (*f1)(int)
olacak şekilde tamamlayacak.f2
içinfoo
işlevinin bellek adresini aldığımızda (&foo
) atamasını da bir işaretçiye yapacağız doğal olarak. Burada&foo
ile explicit (aşikar) bildirim yapıyoruz. function-to-pointer dönüşümü ileint (*f1)(int)
f3
için bir decay dönüşümü (burada function to pointer dönüşümü) olmadanint (&f1)(int)
- f1'in pointer to function olduğunu (
int (*f1)(int)
) biliyoruz. f4 ise pointer to pointer to function olacaktır. Yani işaretçinin işaretçisi olur:
int (*f1)(int) = foo;
int (**f4)(int) = &f1;
- pass by value ile pass by reference arasındaki fark nedir? Ne için hangisini tercih etmeliyiz?
- Ne zaman pass by pointer kullanırız?
- Eğer belleği daha verimli kullanmak istiyorsak pass by reference kullanabiliriz
- Eğer çağırdığımız işlevin içinde argümana geçirdiğimiz değişkenin değerinin değişmesini istemiyorsak pass by value kullanmalıyız.
- Eğer çağırıdğımız işlev işaretçi argüman alıyorsa (
void func(int *p1){}
) ya işaretçi bir değişkeni (int x=10; int *y=&x; func(y);
) ya da adresi (int x=10; func(&x);
) parametre olarak geçireceğiz.
int main(){
int x = 10;
// func(x);
cout << x;
}
func(...)
fonksiyonunu görmeden x'in değerinin kaç olacağını söyleyebilir misiniz?
x
'in pass by reference veya pass by value olarak gönderilip gönderilmediğini func
isimli fonksiyonun bildirimini görmeden söyleyemeyiz. Eğer değer olarak geçirilmişse 10 ancak referans olarak geçirilmişse farklı bir değerde olabilir.
#include <iostream>
using namespace std;
// Aşağıdaki tüm func işlevleri geçerlidir
//void func(int c) {
// cout << c;
//}
//void func(const int c) {
// cout << c;
//}
//void func(const int& c) {
// cout << c;
//}
//void func(const double& c) {
// cout << c;
//}
void func(const char& c) {
cout << c;
}
int main() {
int x = 100;
func(x);
}
Aşağıdaki atamalar doğru mudur, yanlışsa neden?
unsigned int uval{ 56u };
int* p = &uval;
int& r = uval;
Her iki atama da yanlıştır çünkü ister pointer ister referans semantiği farklı tipte değeri kabul etmez. Tür uyuşmazlığı doğar.
int a[5][10][20]{0};
Aşağıdaki değerleri atayacağımız sol taraf referans değerini ifadesini yazınız.
- i)
a[1][2][5]
- ii)
a[1][2]
- ii)
a[0]
- i)
int& r = à[1][2][5]
- ii)
int(&r)[5] = a[1][2]
- ii)
int(&r)[2][5] = a[0]
İki int türünde değişkenin değerlerini takas yapacak şekilde hem işaretçi hem referans değişkenler kullanarak fonksiyonları yazınız.
void swap_p(int* p1, int* p2){
int temp = *p1;
*p1 = *p2;
*p2 = temp;
}
void swap_ref(int& r1, int& r2){
int temp = r1;
r1 = r2;
r2 = temp;
}
int main(){
int a = 5;
int b = 10;
swap_p(&a, &b);
swap_ref(a, b);
}
"Function returning pointer" diye adlandırılan, int türünde bir değeri hem işaretçi hem referans değer olarak dönen fonksiyonu yazınız.
int i = 10;
int* func_p(){
return &i;
}
int& func_ref(){
return i;
}
int main(){
int* p = func_p(); // NOT: L value referansa atanırken -> int& ref = *func_p()
*p = 20;
func_ref() = 20; // i'nin değerine 20 atanmış olur.
}
int* func_p();
ile bildirimi yapılan fonksiyonun genel adı nedir?
Function returning pointer
T func()
bildiriminde T
nin hangi türler için func()
fonksiyonu R, hangi türler için L Value ifadesidir.
func
Fonksiyonunun dönüş değerinin türü (yani T
);
- referans türünde ise L value expression,
- değer türünde ise (
double
,int
,date
,struct
vs.) PR value expression.
Statik ömürlü nesne ne demektir? Neler statik ömürlüdür?
Programın sonuna kadar hayatta kalacak nesnelere statik ömürlü nesneler denir.
- Global değişkenler
- static local variables
int& foo(){
static int x = 11;
return x;
}
Otomatik ömürlü nesneler tanımlandığı kapsamın bitmesi halinde hayatları sonlanır. int& foo(void);
bildirimli fonksiyonun döndüreceği değer otomatik ömürlü olması halinde dangling referans veya dangling pointer olacaktır ve tanımsız değerlere neden olacaktır. Buna göre nasıl değişkenler tanımlanabilir?
- Statik ömürlü nesne (programın sonuna kadar hayatta kalacak nesne)
- global değişken
- static local variable
- Dinamik ömürlü bir nesne olmalıdır (bu durumda dinamik ömürlü nesnenin işi bitince bellek bloğunun geri verilmesi sorumluluğu,
foo
fonksiyonunu çağıran fonksiyondadır)
int x = 2;
ifadesindeki x
değişkenini sadece okumak amaçlı olacak (set veya mutate etmeyecek) işaretçiyi nasıl tanımlarsınız (pointer to const int)?
const int* p = &x;
Burada p
işaretçisi "x
'in değerini değiştirmek üzere dereference edilmeyeceğim" diyor. Yani p işaretçisi yeni bir değer ataması için dereference edildiğinde *p = 22
daima hata verecek:
int x = 10;
const int* p = &x;
*p = 22; // error: assignment of read-only location '* p'
int y = 1;
ifadesindeki y
değişkenininin değerini değiştirebilen (set/mutate edebilen) ancak başka bir değişkeni işaret edemeyecek bir işaretçiyi nasıl tanımlarsınız (const pointer to int)?
int* const p = &y;
Burada p
işaretçisi "hayatım boyunca y
'yi göstereceğim" diyor.
Aşağıdaki kod hata verecektir.
int z = 1;
int x = 10;
int* const p = &z;
p = &x; // "error: assignment of read-only variable 'p'"
pointer to const int const int* p = &y;
ifadesindeki p
işaretçisi y
değişkeninin değerine sadece erişebilir (accessor/getter) yani y
değişkenine p
işaretçisi dereference edilerek yeniden değer atanamaz (Örn. *p = 12
).
int y = 10;
const int* p = &y;
*p = 12;
/*
error: assignment of read-only location '* p'
*p = 12;
^~
*/
Buna göre; işaretçi yerine sol taraf referans değişkeni kullanarak, getter/accessor olacak şekilde bir değişken bildirimi yapan ifadeyi yazınız?
const int& r = y
ile bildirim yapılabilir.
int y = 10;
const int* p = &y;
*p = 12;
/*
error: assignment of read-only location '* p'
*p = 12;
^~
*/
// L Value Reference ifadesi
const int& r = y;
r = 22;
/*
error: assignment of read-only reference 'r'
r = 22;
^~
*/
const pointer to int olarak isimlendirilen int* const p = &y;
ifadesindeki p
işaretçisi sadece y
değişkenini işaret eder ve farklı bir değişkeni işaret etmesi için tekrar atama yapılamaz.
int x = 1;
int y = 10;
int* const p = &y;
p = &x;
/*
error: assignment of read-only variable 'p'
p = &x;
^
*/
Buna göre; işaretçi yerine sol taraf referans değişkeni kullanarak, ilk değerinden başka bir değere atama yapılmayacak şekilde ifadeyi yazınız?
L Value referanslar zaten ilk atandıkları değerden başka bir değere atanamazlar. Bu yüzden fazladan bir tanımlamaya ihtiyaç yoktur. Aşağıdaki r = y
atamasıyla sadece x
in değerine y
nin değeri atanır ancak r
yine x
e bağlanmaya devam eder.
int main(){
int x = 1;
int& r = x;
cout << "x: " << x << " | &x: "<< &x << " | &r: "<< &r << endl;
// x: 1 | &x: 0x61fe14 | &r: 0x61fe14
int y = 2;
r = y;
cout << "x: " << x << " | &y: " << &y << " | &r: "<< &r << endl;
// x: 2 | &y: 0x61fe10 | &r: 0x61fe14
}
const int* p1 = &x
int const *p2 = &x
const* int p3 = &x
int* const p4 = &x
Yukarıdaki ifadelerde aynı işi yapanları bulunuz ve ifadelerin ne anlama geldiklerini yazınız?
const int* p1 = &x
==int const *p2 = &x
p1 ve p2 aynıdır ve bu iki işaretçiconst
ile accessor/getter olarak tanımlanmıştır. p1 ve p2 farklı bir değişkeni işaret edebilir ancak derefrence edilerek x'in değeri bu işaretçiler üstünde değiştirilemez (setter/mutator olarak kullanılamaz). Yazılıma başlanmadan önce hangi biçimde yazılacağı karar verilmesi gereken başlıklardandır aksi halde kodu okurken bir karmaşaya mahal verilebilir.
int main(){
int x = 10;
const int* p1 = &x;
cout << "*p1 : " << *p1 << " - &p1 : " << &p1 << endl; // *p1 : 10 - &p1 : 0x61fe10
int const *p2 = &x;
cout << "*p2 : " << *p2 << " - &p2 : " << &p2 << endl; // *p2 : 10 - &p2 : 0x61fe08
// p1 ve p2 dereference edilerek x'in değerini değiştiremez
*p1 = 33; // error: assignment of read-only location '* p1'
*p2 = 44; // error: assignment of read-only location '* p2'
// ancak farklı bir in türünden değişkeni işaret edebilirler
int y = 20;
p1 = &y;
p2 = &y;
cout << "*p1 : " << *p1 << " - &p1 : " << &p1 << endl; // *p1 : 20 - &p1 : 0x61fe10
cout << "*p2 : " << *p2 << " - &p2 : " << &p2 << endl; // *p2 : 20 - &p2 : 0x61fe08
}
const* int p3 = &x
tanımı hatalıdır.const*
ileerror: expected unqualified-id before 'int'
hatası alınır.int* const
, diğer adıyla top level const.int* const p4 = &x
ile p4 işaretçisinin farklı bir değişkene işaretçi olmasının önüne geçiliyor.
int main(){
int x = 10;
int* const p4 = &x;
cout << "*p4 : " << *p4 << " - &p4 : " << &p4 << endl; // *p4 : 10 - &p4 : 0x61fe10
int y = 20;
*p4 = y;
cout << "*p4 : " << *p4 << " - &p4 : " << &p4 << endl; // *p4 : 20 - &p4 : 0x61fe10
p4 = &y;
/*
error: assignment of read-only variable 'p4'
p4 = &y;
^
*/
}
int z = 1;
ifadesindeki z
değişkenininin değerini değiştirebilen (set/mutate edebilen), başka bir değişkeni de işaret edebilecek bir işaretçiyi nasıl tanımlarsınız?
int z = 1;
int x = 10;
int* p = &z;
cout << *p << endl; // 1
p = &x;
cout << *p << endl; // 10
void
Dönen, integer
değer alabilen bir mutator/setter ve işaretsiz tam sayı değer alabilen bir accessor/getter olmak üzere iki parametreli fonksiyon bildirimi yazınız.
void foo(int* mutator, const unsigned int* accessor);
const int* foo();
int main(){
cout << ++*foo() << endl; // ?
}
Ekrana ne yazar?
const int* foo()
veya referans ifadesiyle const int& foo()
fonksiyonunun dönen değeri değiştirilemez yani immutable döneceği için ++ operatörü hata verecektir.
int i = 10;
const int* foo() {
return &i;
}
int main(){
cout << ++*foo();
/*
error: increment of read-only location '* foo()'
cout << ++*foo();
^
*/
}
Aşağıdaki kod geçerli midir, geçerli ise çıktıları yazınız.
int x = 10;
double d = 1.66;
d = x;
cout << d << endl; // ?
d = x * 1.666;
cout << d << endl; // ?
x = d;
cout << x << endl; // ?
int x = 10;
double d = 1.66;
d = x;
cout << d << endl; // 10
d = x * 1.666;
cout << d << endl; // 16.66
x = d;
cout << x << endl; // 16
Aşağıdaki kodun çıktısı nedir?
const int& func();
int main(){
func() = 10;
cout << func();
}
Geçerli midir, değilse neden?
fonksiyon const dönüşlü ve 10 değerini atamaya çalıştığımız için hata alırız.
const int& func();
int main(){
func() = 10;
cout << func();
/*
error: assignment of read-only location 'func()'
func() = 10;
^~
*/
}
Kod geçerli midir? Çıktısı varsa nedir?
void fonk_p(const int* x){
cout << x;
}
void fonk_r1(const int& x){
cout << x;
}
void fonk_r2(int& x){
cout << x;
}
int main(){
double d = 10.16;
fonk_r1(d);
fonk_r2(d);
fonk_p(&d);
}
double
değeriint
değere referans veya pointer bir değişkene atarken tür uyuşmazlığı hatası alırız bu yüzdenfonk_r2
fonksiyonudouble -> int&
dönüşümü hata verecektir. Eğer bu dönüşümdouble -> const int&
şeklinde olsaydı hata alınmaz ancak veri kaybı yaşanabilir.- Referans olarak çalışan
fonk_r1
fonksiyonu hatasız çalışır ancakdouble
değerint
dönüşümünde veri kaybı yaşanır ve çıktı 10 olur. - Ancak işaretçi parametre alan
fonk_p
hata üretir:
error: cannot bind non-const lvalue reference of type 'int&' to an rvalue of type 'int'
fonk_r2(d);
^
note: initializing argument 1 of 'void fonk_r2(int&)'
void fonk_r2(int& x){
^~~~~~~
error: cannot convert 'double*' to 'const int*'
fonk_p(&d);
^~
note: initializing argument 1 of 'void fonk_p(const int*)'
void fonk_p(const int* x){
~~~~~~~~~~~^
Aşağıdakilerden hangisi const int x = 3; fun( x );
kodunun çalışmasını sağlar:
A) void fun (int x);
B) void fun (int& x);
C) void fun (const int& x);
D) A and C
- Eğer değer olarak geçirelecekse fun fonksiyonunun int türünden parametre alması yeterlidir (A).
- Eğer referans olarak geçirilecekse ya fun(&x) veya fun(x) şeklinde geçirilebilir ve bu durumda ya void fun(int* x) ya da void fun(int& x) olmalı. x bildirilirken const int verildiği için B yanlış, C de doğrudur.
- Cevap D.
Hangisi doğrudur?
- A)
const int& x;
- B)
const int x = 3; int *p_int = & x;
- C)
const int x = 12; const int *p_int = & x;
- D)
int x = 3; const int y = x; int& z = y;
- A) Yanlış. Referans değerlerin varsayılan başlatıcıları yoktur, bir değişken atamasının bildirimleriyle birlikte yapılması gerekir.
- B)
const int x
değişkeniconst int*
türünde bir işaretçiye atanmalıdır. - C) Doğru
- D) Yanlış.
const int y
değişkeniconst int& z
referansına atanmalıdır.
int x = 10;
const double& rd = x;
Geçerli midir, değilse neden?
Geçerlidir.
double& rd = 10;
ataması geçersizdir çünkü bir referansı doğrudan değer ile başlatamaz muhakkak bir nesne ile başlatmamız gerekir. Ancak const double& rd = 10
ifadesindeki const
sayesinde makina kodunda önce geçici bir double
değişkeni oluşturulur ve o değişkene 10 değeri atandıktan sonra bu geçici double
değişkeni rd
referansına bağlanır.
void ref(){
double d = 10; // movsd xmm0, QWORD PTR .LC0[rip]
// movsd QWORD PTR [rbp-16], xmm0
double& r (d); // lea rax, [rbp-16]
// mov QWORD PTR [rbp-8], rax
}
void const_ref() {
const double& dref = 10; // movsd xmm0, QWORD PTR .LC0[rip]
// movsd QWORD PTR [rbp-16], xmm0
// lea rax, [rbp-16]
// mov QWORD PTR [rbp-8], rax
}
Aşağıdaki kod geçerli midir, geçerli ise çıktıları yazınız.
int x = 10;
double* pd = x;
d = x;
cout << d << endl; // ?
d = x * 1.666;
cout << d << endl; // ?
x = d;
cout << x << endl; // ?
int x = 10;
double d = 1.66;
d = x;
cout << d << endl; // 10
d = x * 1.666;
cout << d << endl; // 16.66
x = d;
cout << x << endl; // 16
Aşağıdaki kod için şunlar söylenebilir mi?
- fonk_1 fonksiyonuna sadece L Value parametre olarak geçirilebilir
- fonk_2 fonksiyonuna L ve R Value değerler parametre olarak geçirilebilir
void fonk_1(T&)
void fonk_2(const T&)
Doğru
Aşağıdaki ifadenin function pointer ifadesini yazınız.
double bol(int a, int b){return a/b;}
int main(){
????fn???? = bol;
cout << fn(11,2); // 5
}
double bol(int a, int b){return a/b;}
int main(){
double (*fn)(int, int) = bol;
cout << fn(11,2); // 5
}
Aşağıdaki ifadelerden hangileri doğrudur?
- A) Referans değerler varsayılan değerle başlatılabilir ancak işaretçiler bir değere atanmadan tanımlanamazlar.
int* p;
tanımı yapılabilirkenint& r;
tanımlanamaz. - B) Pointer değişkenin kendi adresini alabiliriz ama referans değişkenin adresi bağlandığı değişkenin adresini verir.
- C) Function pointer (fonksiyona işaretçi) gibi function referans (fonksiyona referans) da vardır.
- D) Elemanları pointer ve referans olan dizi tanımlanabilir.
- E) Bir referans tıpkı işaretçiler gibi farklı değişkenlere atanabilir.
- A) Tam tersi doğrudur. Referans değerler varsayılan olarak başlatılamaz ancak işaretçiler değer ataması olmadan tanımlanabilirler.
- B) Doğru
- C) Doğru
double bol(int a, int b);
double (*fn1)(int, int) = bol;
// veya
double (*fn2)(int, int) = &bol;
// aynı şekilde fonksiyona referans olarak da tanımlanabilir
double (&fn2)(int, int) = bol;
- D) Yanlış. Elemanları pointer olan dizi olabilir ancak elemanları referans olan dizi yoktur. Reference wrapper sınıfı ile tekrar bağlanabilir (rebindable) referans oluşturabilir ve elemanları referans olan bir dizi tanımlanabilir.
int x, y, z;
int* pointerArray[] = {&z, &x, &y}; // pointer dizi geçerlidir
int& pointerArray[] = {z, x, y}; // referans dizi tanımlanamaz
/*
error: declaration of 'pointerArray' as array of references
int& pointerArray[] = {z, x, y};
*/
- E) Yanlış. Bir işaretçi değişken eğer
const T* p
olarak tanımlanmamışsa başka bir değişkene gösterecek şekilde atanabilir. Ancak referans değişkenler sadece bir değişkeni işaret eder ve başka bir değişkene bağlanamaz.
Aşağıdaki auto anahtarının kullanımlarından hangileri doğrudur?
- i)
void func(auto x){
//
}
- ii)
auto func()->int {
return 1;
}
- iii)
auto func() {
return 1;
}
- iv)
template <typename FirstType, typename SecondType>
auto add(FirstType a, SecondType b) -> decltype(a + b){
return a + b;
}
- A) i
- B) i ve ii
- C) ii, iii, iv
- D) hepsi
Doğru cevap D (hepsi) olacak.
- ii = trailing return type diye isimlendirilir.
Sondaki dönüş türü (trailing retur type) özelliği, dönüş türünün fonksiyonun argümanlarının türlerine bağlı olması halinde, fonksiyon şablonunun dönüş türünün genelleştirilemeyeceği bir C++ sınırlamasını kaldırır. Örneğin,
a
veb
, çarpım fonksiyonun parametreleri olsun(const A &a, const B &b)
. Buradaa
veb
rastgele türlerdir. Sondaki dönüş türü özelliği olmadan,a*b
için tüm durumları genelleştirmek için çarpma işlevi şablonu için bir dönüş türü bildiremezsiniz. Bu özellik ile fonksiyon argümanlarından sonra dönüş tipini belirtebilirsiniz.
- iii = auto return type diye isimlendirilir.
- iv)
#include <iostream>
template <typename FirstType, typename SecondType>
auto add(FirstType a, SecondType b) -> decltype(a + b){
return a + b;
}
using namespace std;
int main(){
// The first template argument is of the integer type, and
// the second template argument is of the character type.
cout << add(1, 'A');
// Both the template arguments are of the integer type.
cout << add(3, 5);
}
Tür çıkarımlarında kullanılan anahtar sözcükler nelerdir?
- i)
auto
- ii)
pointer
- iii)
decltype
- iv) decltype(auto)
- v)
template
A) i, ii, iii B) i, ii, iv C) hepsi D) i, iii, iv, v
Doğru cevap D şıkkı. auto
, decltype
, decltype(auto)
, template
Aşağıdaki işaretçilerin (pglobal
, plocal
, pstatic
, p
) değerlerini yazınız.
#include <iostream>
int* pglobal;
int main(){
int* plocal;
static int* pstatic;
int* pinited{};
int* pnull = nullptr;
}
Başlatılmamış global ve static işaretçiler nullptr değeriyle tanımlanmış olur.
Varsayılan değeriyle başlatılmış işaretçi değişkenlerin değeri türün varsayılan değeriyle başlar.
- pglobal > nullptr
- plocal > garbage value (otomatik ömürlü işaretçiler çöp değer ile başlatılır)
- pstatic > nullptr (static anahtarıyla başlatılanlar nullptr ile başlatılır)
- pinited > 0 (varsayılan değer ile başlatılanlar türün varsayılan değerini alır. int için 0)
- pnull > nullptr
int* pglobal;
int main(){
int* plocal;
static int* pstatic;
int* p{};
int* pnull = nullptr;
cout << pglobal << endl; // 0
cout << plocal << endl; // 0x737fb0
cout << pstatic << endl; // 0
cout << p << endl; // 0
cout << pnull << endl; // 0
}
bool* pnull = nullptr;
bool* pinited{};
bool* pglobal;
int main(){
bool* plocal;
static bool* pstatic;
cout << "pnull : " << pnull << endl; // 0
cout << "pinited: " << pinited << endl; // 0
cout << "pglobal: " << pglobal << endl; // 0
cout << "plocal : " << plocal << endl; // 0x10
cout << "pstatic: " << pstatic << endl; // 0
}
Sağ ve sol taraf referanslarını nasıl ifade ediyoruz?
Örneğin int türünden referanslar oluşturmak isteyelim:
int& lv
sol taraf referansını, int&& rv
ise sağ taraf referansını verir.
int x = 10;
ifadesinde x
, sol taraf değeri ve 10 ise sağ taraf değeridir. Sol taraf referansına sol taraf değeri atanırken (int x=10; int& lv=x;
), sağ taraf referansına sağ taraf değeri atanır (int&& rv=10;
). Doğrudan değeri atayabileceğimiz sağ taraf referansıyken bir değişkeni atadığımız ise sol taraf referansıdır.
Eğer sağ taraf referansına sol taraf referansı atarsak:
int x = 10;
auto&& r1 = 10; // buraya kadar sağ taraf referansına 10 değeri atıyoruz
// ancak aşağıda ise sağ taraf referansına (&&r), sol taraf referansı atıyoruz
// bu durumda reference collapsing meydana geliyor
auto&& r2 = x;
Bu koda göre ifadelerin auto olmaksızın tanımı:
int x = 10;
auto&& r1 = 10; // int &&r1 = 10
auto&& r2 = x; // int &r2 = x
using mytype = int &&;
int main(){
int x = 5;
mytype&& x1 = 10;
mytype& x2 = 10;
mytype& x3 = x;
}
x Değişkenlerine atamalar geçerli midir, türleri ne olur?
using mytype = int &&;
ile bir tip tanımı yapılıyor. int
türünde sağ taraf referansına (int &&
) mytype
ismi veriliyor. mytype
tipinden bir değişken yaratırken türü int &&
olacaktır.
mytype&& x1 = 10; // mytype Türünde x1 değişkeni sağ taraf referansıdır ve 10 değeri atanır (Geçerli)
mytype& x2 = 10; // int &x2 türünde sol taraf referansıdır ve sağ taraf değeri atanamaz (Hatalı)
mytype& x3 = x; // int &x2 türünde sol taraf referansıdır ve sol taraf değeri olan x atanabilir (Geçerli)
const int&& x = 10;
Sağ taraf referansları const
ile tanımlanabilir mi?
Evet tanımlanabilir ama pratikte anlamlı değildir.
Aşağıdaki fonksiyonların hangilerine L Value/R Value geçirebiliriz?
void f1(T&)
void f2(T&&)
void f3(cont T&)
L Value | R Value | |
---|---|---|
f1 | ? | ? |
f2 | ? | ? |
f3 | ? | ? |
L Value | R Value | |
---|---|---|
f1 | Evet | Hayır |
f2 | Hayır | Evet |
f3 | Evet | Evet |
Neden sol taraf referans semantiğini kullanırız?
Pointer semantiği ile aynı çıktıyı verir ve kodlamamızı ve kodun okunabilirliğini daha kolay kılar. Değere ulaşmak için sürekli dereferencing (*ptr
) yapmamız gerekmez.
using std::cout;
using std::endl;
using std::size;
int main(){
float puanlar[]{10, 22.5, 77.4, 21.5};
for(int i=0; i<size(puanlar)){
cout << "puan: " << puanlar[i] << endl;
}
}
c++ 17 ile birlikte gelen size()
fonksiyonu yerine neden C# veya javadaki gibi dizinin length
türünde bir özellik yoktur.
C++'da diziler bir nesne değildir.
float not1[]{10, 22.5, 77.4, 21.5};
float not2[19]{10, 22.5, 77.4, 21.5};
float not3[2]{10, 22.5, 77.4, 21.5};
Yukarıdaki değişkenler için derleyicinin çıktısı ne olur?
float not1[]{10, 22.5, 77.4, 21.5}; // sorun yok. brace intializer ile verilen eleman sayısı kadar dizinin elemanı olur. 4 Elemanlı dizi oluşturur.
float not2[19]{10, 22.5, 77.4, 21.5}; // sorun yok. tanımsız olan elemanlar (ilk 4 eleman hariç kalanlar) 0 değeriyle başlatılır.
float not3[2]{10, 22.5, 77.4, 21.5}; // hata verir. dizinin eleman sayısından fazla eleman brace initializer içinde tanımlı olamaz.
auto
için yapılan tür çıkarımları nelerdir?
auto x{1}; // auto ??
auto y = {1}; // auto ??
auto z{1,2,3};// auto ??
auto k(1); // auto ??
auto p1 = &x; // auto ??
auto* p2 = &x; // auto ??
auto x{1}; // auto > int
auto y = {1}; // auto > std::initializer_list<int>
auto z{1,2,3};// auto > hatalı (C++ 11 için std::initalizer_list<int> idi ama artık geçersiz )
auto k(1); // auto > int
auto p1 = &x; // auto > int* p1
auto* p2 = &x; // auto > int* p2
p1
, p2
, p3
için yapılan tür çıkarımları nelerdir?
Her satırda auto
için yapılan tür çıkarımları nelerdir?
int x{1};
int* ptr = &x;
auto p1 = &ptr; // p1 ?? , auto ??
auto* p2 = &ptr; // p2 ?? , auto ??
auto** p3 = &ptr; // p3 ?? , auto ??
&ptr
'nin türü int**
olduğuna göre p1
, p2
ve p3
'ün türleri int**
olacaktır
auto
ise ilk satırda int**
, ikinci satırda int*
ve üçüncü satırda int
olacaktır.
Referece collapsing nedir?
C++ reference to reference desteklemez ve bu durum oluştuğunda dilin reference collapsing kuralları devreye girer.
/*
Sağ taraf referansı atandığı için yani doğrudan değeri atadığımızda:
auto > int tür çıkarımı olacak
Bu durumda "auto &&r1 > int &&r" yani SAĞ TARAF REFERANSI olacak.
*/
auto &&r1 = 5; // auto &&r > int &&r
/*
Sol taraf referansı atandığı için yani doğrudan değer yerine
nesneyi bağladığımızda: "auto > int &" tür çıkarımı olacak
int &r ile SOL TARAF REFERANSI tanımlanmış olacak.
*/
int x{1};
auto &&r2 = x; // auto &&r > int &r
// Özetle auto sayesinde SOL veya SAĞ TARAF REFERANSI dinamik olarak tanımlanıyor.
// mytype : SAĞ TARAF REFERANSI
using mytype = int&&;
int main() {
mytype r1 = 10; // sağ taraf referansına 10 değerini atıyoruz
mytype&& r2 = 20; // mytype RValue idi ve mytype&& da RValue
/*
referans deklaratörünü sol taraf referansına çevirsek: mytype&
reference collapsing meydana gelir çünkü sol taraf referansını sağ taraf referansına bağlayamayız.
*/
mytype& r3 = 30; // REFERENCE COLLAPSING
}
sizeof kullanımlarından hangileri doğrudur ve çıktıları nedir?
auto x{1};
auto &&r = x;
cout << r << endl;
cout << sizeof(x) << endl;
cout << sizeof r << endl;
cout << sizeof(int) << endl;
sizeof
eğer bir tür için boyut dönecekse parantez içinde operand olarak verilmelidir. Bunun dışındaki kullanımlarında yani bir değişken için çalışacaksa parantez içinde operand olarak alması gerekmez.
auto x{1};
auto &&r = x;
cout << r << endl; // 1
cout << sizeof(x) << endl; // 4
cout << sizeof r << endl; // 4
cout << sizeof(int) << endl;// 4
Declaration Type anlamıa gelen declytpe kullanımlarından hangileri doğrudur?
i.
Kullanıcıdan küçük harfle bir karakter girmesini isteyen ve büyük harf olarak ekrana yazan bir uygulama yazınız.
#include <iostream>
using namespace std;
int main() {
char lowerCaseLetter, upperCaseLetter;
int offset;
cout << "Please enter a lower case letter:" << endl;
cin >> lowerCaseLetter;
offset = (int)(lowerCaseLetter - 'a');
upperCaseLetter = (char)('A' + offset);
cout << "The upper case of " << lowerCaseLetter << " is " << upperCaseLetter << endl;
return 0;
}
Kullanıcıdan yarı çapını istediğiniz dairenin alanını hesaplayan ve ekrana yazan uygulamayı kodlayınız.
#include <iostream>
#include <cmath>
using namespace std;
int main() {
double radius, area;
cout << "Please enter the radius:" << endl;
cin >> radius;
area = M_PI * (radius*radius);
cout << "The area of a circle with radius of " << radius << " is " << area << endl;
return 0;
}
Kullanıcıya kaç gün yıllık izni olduğunu sorun ve bunu x hafta y gün olacak şekilde yazdırın.
#include <iostream>
using namespace std;
const int DAYS_IN_A_WEEK = 7;
int main() {
int vacationDays;
int fullWeeks, remainingDays;
cout << "Please enter number of days you have for vacation:" << endl;
cin >> vacationDays;
fullWeeks = vacationDays / DAYS_IN_A_WEEK;
remainingDays = vacationDays % DAYS_IN_A_WEEK;
cout << vacationDays << " days you have " << fullWeeks << " week " << remainingDays << " days" << endl;
return 0;
}
Aşağıdaki const ifadelerinin açıklamalarını yazınız?
Aşağıdaki ifadelerin hangisi yanlıştır
auto x=10, y=2.0;
:x
değişkeniint
olarak yaratıldı ancaky
ile aynıauto
tanımlayıcısını kullandıkları ve,
ile ayrıldıkları için her ikisi de aynı türde çıkarımsanacağı için vey
değeriint
olmayacağı için yanlıştır.const auto x=10, y=++x;
: x değişkeniconst
olarak tanımlandığı için ++ ile arttırılamazauto x=10, y=x;
doğrudur.