Menu
Coddy logo textTech

Yapı İşaretçilerini Aktarma

Coddy'nin C Journey'sinin Logic & Flow bölümünün bir parçası — ders 47 / 63.

Yapıları (structs) değer ile geçirmek veri okumak için iyi çalışsa da, tüm yapı kopyalandığı için büyük yapılarda verimsiz hale gelir. Daha da önemlisi, fonksiyonun içinden orijinal yapıyı değiştiremezsiniz. İşte bu noktada, yapılara işaretçiler (pointers to structs) geçirmek zorunlu hale gelir.

Bir struct'ın kendisi yerine ona bir işaretçi (pointer) geçirdiğinizde, fonksiyon orijinal struct'ın bellek adresini alır. Bu yaklaşım iki temel avantaj sunar: daha verimlidir (kopyalama yapılmaz) ve fonksiyonun orijinal veriyi değiştirmesine olanak tanır.

Bir struct'a (yapı) işaretçi kabul eden bir fonksiyonun sözdizimi şöyledir:

void functionName(struct StructureName *ptr) {
    // ptr->member kullanan fonksiyon gövdesi
}

Fonksiyonun içinde, struct üyelerine erişmek ve onları değiştirmek için ok operatörünü kullanırsınız. İşaretçi (pointer) aracılığıyla yapılan tüm değişiklikler, çağıran fonksiyondaki orijinal struct'ı doğrudan etkileyecektir; bu da bu yaklaşımı, struct verilerini güncellemesi veya dönüştürmesi gereken fonksiyonlar için mükemmel kılar.

Bu teknik, işaretçilerin (pointers) gücünü yapıların (structs) düzeniyle birleştirdiği için karmaşık veri yapılarıyla çalışan verimli C programları oluşturmak için temeldir.

challenge icon

Görev

Kolay

Verimli veri modifikasyonu için yapı (struct) işaretçilerinin fonksiyonlara aktarılmasını gösteren bir C programı oluşturun. Programınız şunları yapmalıdır:

  1. Aşağıdaki üyelere sahip BankAccount adında bir struct tanımlayın:
    • Hesap numarasını saklamak için bir tam sayı accountNumber
    • Hesap sahibinin adını saklamak için 30 boyutunda bir karakter dizisi ownerName
    • Hesap bakiyesini saklamak için bir float balance
    • İşlem sayısını saklamak için bir tam sayı transactionCount
  2. Şu özellikleri taşıyan depositMoney adında bir fonksiyon yazın:
    • Parametre olarak bir BankAccount yapısına işaretçi ve bir float miktar alır
    • Ok operatörünü (arrow operator) kullanarak miktarı hesap bakiyesine ekler
    • İşlem sayısını 1 artırır
    • Deposit successful. New balance: [balance] yazdırır
  3. Şu özellikleri taşıyan withdrawMoney adında bir fonksiyon yazın:
    • Parametre olarak bir BankAccount yapısına işaretçi ve bir float miktar alır
    • Para çekme miktarının mevcut bakiyeden fazla olup olmadığını kontrol eder
    • Yetersiz bakiye durumunda, Insufficient funds. Current balance: [balance] yazdırır
    • Yeterli bakiye durumunda, miktarı bakiyeden çıkarır, işlem sayısını artırır ve Withdrawal successful. New balance: [balance] yazdırır
  4. Şu özellikleri taşıyan displayAccount adında bir fonksiyon yazın:
    • Parametre olarak bir BankAccount yapısına işaretçi alır
    • Hesap bilgilerini tam olarak şu formatta yazdırır:
      • Account Information:
      • Account Number: [accountNumber]
      • Owner: [ownerName]
      • Balance: [balance]
      • Transactions: [transactionCount]
  5. Ana (main) fonksiyonda:
    • account adında bir BankAccount değişkeni oluşturun
    • Girdiden hesap numarasını, sahip adını ve başlangıç bakiyesini okuyun
    • İşlem sayısını 0 olarak ayarlayın
    • Başlangıç hesap durumunu göstermek için displayAccount fonksiyonunu çağırın
    • Bir para yatırma miktarı okuyun ve depositMoney fonksiyonunu çağırın
    • Bir para çekme miktarı okuyun ve withdrawMoney fonksiyonunu çağırın
    • Son hesap durumunu göstermek için displayAccount fonksiyonunu çağırın

Bu meydan okuma, yapı işaretçilerini fonksiyonlara aktarmanın gücünü göstermektedir. Değerle aktarımın (pass-by-value) aksine, fonksiyonlar orijinal yapının bellek adresini alır ve bu da onların orijinal veriyi doğrudan değiştirmesine olanak tanır. Bu yaklaşım daha verimlidir (kopyalama yapılmaz) ve fonksiyonların çağıran fonksiyondaki yapı değerlerini kalıcı olarak değiştirmesini sağlar.

Kopya kağıdı

Struct'lar değer ile aktarıldığında, tüm yapı kopyalanır; bu durum büyük struct'lar için verimsizdir ve orijinal verinin değiştirilmesini engeller. Struct işaretçileri (pointers to structs) geçirmek, bunun yerine bellek adresini geçirerek her iki sorunu da çözer.

Bir struct işaretçisini kabul eden fonksiyon sözdizimi:

void functionName(struct StructureName *ptr) {
    // ptr->member kullanan fonksiyon gövdesi
}

Fonksiyon içinde, işaretçi aracılığıyla struct üyelerine erişmek ve bunları değiştirmek için ok operatörünü (->) kullanın. Yapılan tüm değişiklikler, çağıran fonksiyondaki orijinal struct'ı doğrudan etkileyecektir.

Bu yaklaşım iki temel avantaj sunar:

  • Daha verimli (tüm struct kopyalanmaz)
  • Fonksiyonların orijinal struct verilerini değiştirmesine olanak tanır

Kendin dene

#include <stdio.h>
#include <string.h>

// YAPILACAK: BankAccount yapısını (struct) burada tanımlayın

// YAPILACAK: depositMoney fonksiyonunu burada yazın

// YAPILACAK: withdrawMoney fonksiyonunu burada yazın

// YAPILACAK: displayAccount fonksiyonunu burada yazın

int main() {
    // Girdiyi oku
    int accountNum;
    char ownerName[30];
    float initialBalance;
    float depositAmount;
    float withdrawAmount;
    
    scanf("%d", &accountNum);
    scanf("%s", ownerName);
    scanf("%f", &initialBalance);
    scanf("%f", &depositAmount);
    scanf("%f", &withdrawAmount);
    
    // YAPILACAK: BankAccount değişkenini oluşturun ve başlatın
    
    // YAPILACAK: Başlangıç durumunu göstermek için displayAccount fonksiyonunu çağırın
    
    // YAPILACAK: Yatırılacak tutar ile depositMoney fonksiyonunu çağırın
    
    // YAPILACAK: Çekilecek tutar ile withdrawMoney fonksiyonunu çağırın
    
    // YAPILACAK: Son durumu göstermek için displayAccount fonksiyonunu çağırın
    
    return 0;
}
quiz iconKendini test et

Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.

Logic & Flow bölümündeki tüm dersler