SEN2201 · 11. hafta · Programming in C

C'ye giriş: değişkenler, tipler ve operatörler

C programının yapısı, int/char/double, kapsam (scope), tam sayı bölmesi, ++/--, mantık ve bit operatörleri, öncelik. “What is printed?” sorularının temeli.

variabledata typeintchardoublescopelocal variableglobal variableinteger divisionmoduluspre-incrementpost-incrementshort-circuit evaluationbitwise operatorshiftprecedenceprintf

Dönemin son dört haftası C. Neden C? Çünkü C, şimdiye kadar öğrendiğin seviyenin hemen üstünde durur: bir C değişkeni bellekte bir konumdur, bir C ifadesi birkaç LC-3 komutudur, bir fonksiyon çağrısı JSR ve yığın işlemleridir. Kitap C’yi bu yüzden LC-3’ün üzerine kurar. Sınavda C’den gelen soruların çoğu “What is printed?” tipidir: kodu kafanda çalıştırıp çıktıyı yazarsın.

Altın kurallar:

  1. int / int = int, ondalık kesilir.
  2. Doğru = sıfır olmayan, yanlış = 0. Karşılaştırmalar 1 ya da 0 üretir.
  3. x++ eski değeri, ++x yeni değeri verir.
  4. && ve || kısa devre yapar.
  5. Bir blok içinde tanımlanan değişken dışarıdakini gölgeler.

İlk program

#include <stdio.h>

int main(void) {
    int count = 3;
    printf("count = %d\n", count);
    return 0;
}
count = 3
  • #include <stdio.h>: printf/scanf için preprocessor komutu. Derlemeden önce o dosyanın içeriği buraya eklenir.
  • main: program buradan başlar.
  • Her deyim ; ile biter. Bloklar { }.

C programı derlenir (compile): kaynak kod → preprocessor → compiler → assembly/makine kodu → linker → çalıştırılabilir dosya. LC-3 üzerinde bu, 10. haftada yazdığın türden bir assembly üretmek demektir.

Değişkenler ve tipler

Her değişkenin bir tipi, bir adı ve bir değeri vardır. Tip, bellekte kaç bit ayrılacağını ve bitlerin nasıl okunacağını söyler (2. hafta).

TipNe tutar?Örnekprintf
intişaretli tam sayı (2’s complement)int n = -5;%d
chartek karakter (ASCII kodu, küçük tam sayı)char c = 'A';%c ya da %d
doubleondalıklı sayı (IEEE 754)double x = 2.5;%f

LC-3 C’sinde int 16 bittir; senin bilgisayarında genelde 32 bit. Sınavda kullanılacak sayılar her ikisine de sığar.

Sabitler: 17 ondalık, 0x1F hex (31), 017 sekizlik (15). Başa sıfır koymak sayıyı sekizlik yapar: dikkat.

Kapsam (scope)

  • Local değişken: bir fonksiyonun ya da bloğun içinde tanımlanır, sadece orada görülür. LC-3’te yığında (runtime stack) yaşar.
  • Global değişken: tüm fonksiyonların dışında tanımlanır, her yerden görülür. LC-3’te global veri bölgesinde yaşar (R4 bu bölgeyi gösterir).

İç kapsamdaki aynı isimli değişken dıştakini gölgeler:

int g = 10;

void show(void) {
    int g = 3;            /* yeni, yerel g */
    printf("show: %d\n", g);
}

int main(void) {
    show();
    printf("main: %d\n", g);
    return 0;
}
show: 3
main: 10

TUZAK · ilk değer verilmemiş local. int x; yazıp x’i kullanırsan değeri belirsizdir (o bellek konumunda ne kaldıysa). Global değişkenler ise otomatik 0 ile başlar.

Aritmetik operatörler

printf("%d %d %d %d\n", 7 / 2, -7 / 2, 7 % 3, -7 % 3);
3 -3 1 -1
  • Bölme sıfıra doğru kesilir: -3,5 → -3.
  • % sonucunun işareti soldaki sayınınkidir.
  • Biri double ise bölme gerçek bölmedir: 7 / 2.0 = 3.5.

Atama ve bileşik atama

int n = 10;
n -= 3;   /* 7  */
n *= 2;   /* 14 */
n /= 4;   /* 3  */
n %= 3;   /* 0  */
printf("%d\n", n);
0

Artırma ve azaltma

İfadeDeğeriSonra x
x++eski xx + 1
++xx + 1x + 1
x--eski xx - 1
--xx - 1x - 1
int i = 3;
int k = i++ * 2;     /* 3 * 2, sonra i = 4 */
printf("%d %d\n", i, k);
4 6

++i * 2 yazsaydın önce i = 4 olur, k = 8.

TUZAK · aynı değişkeni bir ifadede iki kez değiştirmek. x = x++ + ++x; gibi ifadeler C’de tanımsızdır (undefined behavior). Derleyiciye göre farklı sonuç verir. Sınav sorularında bunlarla karşılaşırsan cevap “undefined” olabilir.

İlişkisel ve mantıksal operatörler

< <= > >= == != sonuç olarak 1 (doğru) ya da 0 (yanlış) verir. && (ve), || (veya), ! (değil) her sıfır olmayan değeri doğru sayar.

int a = 3, b = 0;
printf("%d %d %d %d\n", a && b, a || b, !b, a == 3);
0 1 1 1

Kısa devre (short-circuit): A && B’de A yanlışsa B hesaplanmaz. A || B’de A doğruysa B hesaplanmaz. Bu, (i != 0) && (10 / i > 1) gibi korumalı ifadeleri mümkün kılar.

Koşul operatörü: koşul ? a : b. Koşul doğruysa a, değilse b.

Bit operatörleri

OperatörAnlamıÖrnek (12 = 1100, 10 = 1010)
&AND12 & 10 = 8
|OR12 | 10 = 14
^XOR12 ^ 10 = 6
~NOT (her bit)~5 = -6
<<sola kaydır5 << 2 = 20
>>sağa kaydır40 >> 3 = 5

~x = -x - 1 (2’s complement). & ile &&’yi karıştırma: 12 & 10 = 8, 12 && 10 = 1.

char aritmetiği

char bir tam sayı olduğu için onunla hesap yapılır:

char c = 'b';
c = c - 'a' + 'A';      /* küçük → büyük */
printf("%c\n", c);
printf("%d\n", '7' - '0');
B
7

Öncelik ve birleşme

SeviyeOperatörlerYön
1() [] -> . x++ x--soldan sağa
2++x --x ! ~ -x *p &x (tip)sağdan sola
3* / %soldan sağa
4+ -soldan sağa
5<< >>soldan sağa
6< <= > >=soldan sağa
7== !=soldan sağa
8&soldan sağa
9^soldan sağa
10|soldan sağa
11&&soldan sağa
12||soldan sağa
13?:sağdan sola
14= += -= …sağdan sola

Emin değilsen parantez kullan; sınavda ise tabloya göre adım adım çöz:

2 + 3 * 4 % 5
2 + 12 % 5        * ve % aynı seviye, soldaki önce
2 + 2
4

C’den LC-3’e

a = b + c; (üçü de local) derleyici tarafından kabaca şöyle çevrilir (R5 frame pointer, 12. hafta):

        LDR  R0, R5, #-1    ; R0 = b
        LDR  R1, R5, #-2    ; R1 = c
        ADD  R0, R0, R1
        STR  R0, R5, #0     ; a = R0

Yani her C değişkeni bir bellek konumu, her işlem bir ya da birkaç komut.

Sık yapılan hatalar

Yanlış düşünceDoğrusu
7 / 2 = 3.53; ondalık için 7 / 2.0
double d = 7 / 2; → 3.53.0
y = x++ → y yeni değery eski değer
10 > 5 > 1 doğru(10>5)=1, 1>1 = 0
& ile && aynı& bitsel, && mantıksal
!5 = -50; -5 için -5, -6 için ~5
017 = 17Sekizlik: 15
Local değişken 0 ile başlarBelirsiz; global 0 ile başlar

Kendini test et

Sınavdaki gibi İngilizce sorular. Önce kâğıt kalemle çöz, sonra cevabı aç.

Soru 1kolay

What is printed?

printf("%d %d\n", 17 / 5, 17 % 5);
Cevabı göster
3 2

İki int bölünürse sonuç int, ondalık kesilir: 17 / 5 = 3. Kalan: 17 = 3·5 + 2 → 2.

Soru 2kolay

What is printed?

int x = 5;
int y = x++;
printf("%d %d\n", x, y);
Cevabı göster
6 5

x++ (post-increment) önce eski değeri verir, sonra artırır. y = 5, x = 6.

Soru 3kolay

What is printed?

int x = 5;
int y = ++x;
printf("%d %d\n", x, y);
Cevabı göster
6 6

++x (pre-increment) önce artırır, sonra yeni değeri verir. x = 6, y = 6.

Soru 4orta

What is printed?

double d = 7 / 2;
printf("%.1f\n", d);
Cevabı göster
3.0

Sağ taraf önce hesaplanır: 7 / 2 iki int → 3. double'a atanınca 3.0 olur. 3.5 için 7 / 2.0 ya da (double) 7 / 2 yazılmalı.

Soru 5orta

What is printed?

printf("%d\n", 10 > 5 > 1);
Cevabı göster
0

C'de karşılaştırma 1 (doğru) ya da 0 (yanlış) üretir ve soldan sağa yapılır: (10 > 5) = 1, sonra 1 > 1 = 0. Matematikteki gibi zincirleme okunmaz.

Soru 6orta

What is printed? Does the program crash?

int i = 0;
int r = (i != 0) && (10 / i > 1);
printf("%d\n", r);
Cevabı göster
0, no crash

&& kısa devre (short-circuit) yapar: sol taraf 0 ise sağ taraf hiç hesaplanmaz. Bu yüzden 10 / 0 çalışmaz. Sonuç 0.

Soru 7kolay

What is printed?

printf("%d %d %d\n", 12 & 10, 12 | 10, 12 ^ 10);
Cevabı göster
8 14 6

12 = 1100, 10 = 1010. AND: 1000 = 8. OR: 1110 = 14. XOR: 0110 = 6. 2. haftadaki maske işlemlerinin aynısı.

Soru 8orta

What is printed?

printf("%d %d\n", 5 << 2, 40 >> 3);
Cevabı göster
20 5

Sola k bit kaydırma 2k2^k ile çarpar: 5 · 4 = 20. Sağa kaydırma (pozitif sayıda) 2k2^k'ya böler: 40 / 8 = 5.

Soru 9kolay

What is printed?

char c = 'A' + 2;
printf("%c %d\n", c, c);
Cevabı göster
C 67

char bir tam sayıdır: 'A' = 65, 65 + 2 = 67. %c karakter olarak ('C'), %d sayı olarak (67) basar.

Soru 10orta

What is printed?

printf("%d\n", 2 + 3 * 4 % 5);
Cevabı göster
4

* ve % aynı seviyede, soldan sağa: 3 * 4 = 12, 12 % 5 = 2. Sonra 2 + 2 = 4.

Soru 11orta

What is printed?

int x = 4;
printf("%d %d %d\n", !x, !!x, x > 3 ? 10 : 20);
Cevabı göster
0 1 10

Sıfır olmayan her değer doğrudur. !4 = 0, !!4 = !0 = 1. Koşul operatörü: x > 3 doğru → 10.

Soru 12zor

What is printed?

int g = 10;

void show(void) {
    int g = 3;
    printf("show: %d\n", g);
}

int main(void) {
    show();
    printf("main: %d\n", g);
    return 0;
}
Cevabı göster
show: 3 / main: 10

show içindeki int g yeni bir yerel (local) değişkendir ve global g'yi gölgeler (shadowing). Global g'ye dokunulmaz. main global g'yi görür: 10.

Doğrulama: Her kod parçası C99 olarak Zig cc (clang) ile derlenip çalıştırıldı, çıktılar birebir kopyalandı (verify/SEN2201/c/w11a.c; ilk program ve char örneği w11b.c başında; node verify/SEN2201/c/run.mjs w11).

Deftere not kartı

int / int -> int, KESİLİR: 7/2=3, -7/2=-3 | % işareti soldan: -7%3=-1 double d = 7/2; -> 3.0 (bölme önce int yapıldı) x++ eski değeri verir, ++x yeni değeri | y = x++ -> y eski x Doğru = sıfır olmayan, yanlış = 0 | karşılaştırma 1/0 üretir | 10>5>1 = 0 && ve || kısa devre: sol taraf sonucu belirliyorsa sağ çalışmaz ! mantıksal (!4=0) | ~ bitsel (~5=-6) | & | ^ bitsel | << *2^k | >> /2^k char = küçük tam sayı: 'A'=65, '7'-'0'=7, 'b'-'a'+'A'='B' Öncelik: () > ++ -- ! ~ (unary) > * / % > + - > << >> > < <= > >= > == != > & > ^ > | > && > || > ?: > = += ... Local değişken global'i gölgeler | blok {} yeni kapsam printf: %d int, %c char, %f double (%.2f), %x hex, %s string LC-3 C'sinde int 16 bit (2's complement), PC'de genelde 32 bit