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.
Görev
KolayVerimli 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:
- Aşağıdaki üyelere sahip
BankAccountadında birstructtanı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
- Hesap numarasını saklamak için bir tam sayı
- Şu özellikleri taşıyan
depositMoneyadında bir fonksiyon yazın:- Parametre olarak bir
BankAccountyapı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
- Parametre olarak bir
- Şu özellikleri taşıyan
withdrawMoneyadında bir fonksiyon yazın:- Parametre olarak bir
BankAccountyapı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
- Parametre olarak bir
- Şu özellikleri taşıyan
displayAccountadında bir fonksiyon yazın:- Parametre olarak bir
BankAccountyapı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]
- Parametre olarak bir
- Ana (main) fonksiyonda:
accountadında birBankAccountdeğ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
displayAccountfonksiyonunu çağırın - Bir para yatırma miktarı okuyun ve
depositMoneyfonksiyonunu çağırın - Bir para çekme miktarı okuyun ve
withdrawMoneyfonksiyonunu çağırın - Son hesap durumunu göstermek için
displayAccountfonksiyonunu ç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;
}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
1Pointer Temelleri
Pointer Nedir?Pointer TanımlamaAdres Operatörü (&)Dereference Operatörü (*)NULL Pointer'larÖzet: Pointer Temelleri4Proje: Basit Metin Aracı
Projeye Genel BakışKarakter Sayma2İşaretçiler ve Diziler
İşaretçi Olarak Dizi İsimleriDizi Elemanları - İşaretçilerİşaretçi Aritmetiğiİşaretçilerin KarşılaştırılmasıÖzet: İşaretçi ile Dizi Gezinme5İşaretçiler ve Fonksiyonlar
Değer ile GeçmeFonksiyonlara İşaretçi Göndermeİşaretçiler ile Değişkenleri DeğiştirmeKlasik Bir Örnek: SwapFonksiyonlara Dizi GöndermeÖzet: Fonksiyon İşaretçi Argümanları8Yapılar ve İşaretçiler
Yapılara İşaretçilerOk Operatörü (->)Yapıları Değer ile AktarmaYapı İşaretçilerini AktarmaYapıların Dinamik TahsisiÖzet: Yapıyı Değiştirme - Ptr11Son Tekrar Görevleri
Tekrar: Dinamik String BirleştirmeTekrar: Struct DizisiTekrar: Kelime Frekans Sayacı3Karakter Dizileri ve Stringler
char Dizisi Olarak StringlerNull Sonlandırıcıscanf ile String Girişistrlen() Kullanımıstrcpy() Kullanımıstrcat() Kullanımıstrcmp() KullanımıÖzet: Temel String Fonksiyonları