İşaretçi vs Değer
Coddy'nin C Journey'sinin Object Oriented Programming bölümünün bir parçası — ders 9 / 61.
Bir struct'ı bir fonksiyona geçirdiğinizde, C size iki seçenek sunar: değer ile geçirmek (tüm struct'ı kopyalamak) veya işaretçi ile geçirmek (sadece adresi kopyalamak). Bu seçim, performans açısından önemli ölçüde fark yaratır.
Değer ile geçme (passing by value), yığında yapının (struct) tam bir kopyasını oluşturur. Birkaç tamsayı içeren küçük bir yapı için bu sorun değildir. Ancak yüzlerce baytlık bir yapı hayal edin; her fonksiyon çağrısı tüm bu veriyi kopyalar:
typedef struct {
char name[100];
int scores[50];
double average;
} Student;
// Değer ile: her çağrıda ~608 bayt kopyalar
void print_by_value(Student s) {
printf("%s: %.2f\n", s.name, s.average);
}
// İşaretçi ile: sadece 8 bayt kopyalar (adres)
void print_by_pointer(const Student *s) {
printf("%s: %.2f\n", s->name, s->average);
}
Sözdizimi de farklılık gösterir. Bir değer parametresi ile nokta operatörünü (s.name) kullanırsınız. Bir işaretçi ile ok operatörünü (s->name) kullanırsınız.
Pointer versiyonu daha verimlidir çünkü yalnızca bir bellek adresi iletir; bu adres, struct boyutundan bağımsız olarak genellikle 8 bayttır.
C programcılarının struct'ları neredeyse her zaman işaretçi (pointer) ile geçirmelerinin nedeni budur. Fonksiyonun veriyi değiştirmemesi gerektiğinde const, değiştirmesi gerektiğinde ise normal bir işaretçi kullanın. Böylece hem verimlilik hem de net bir niyet elde edersiniz.
Görev
KolayYapıları (structs) değer ile geçirme ve işaretçi (pointer) ile geçirme arasındaki farkı gösteren bir Product modülü oluşturalım. İki adet görüntüleme fonksiyonu oluşturacaksınız; biri yapının tamamını bir kopya olarak alır, diğeri ise sadece ona işaret eden bir işaretçi alır.
Üç dosya oluşturacaksınız:
product.h: Üç üyeye sahip birProductyapısı bildirin:char name[50],double priceveint quantity. Ayrıca iki fonksiyon bildirin:display_by_value— birProductyapısını değer olarak alır ve bilgilerini yazdırırdisplay_by_pointer— birconst Product *alır ve aynı bilgileri yazdırır
PRODUCT_Hsembolü ile include guard (ekleme koruması) kullanın.product.c: Her iki fonksiyonu da uygulayın. Sözdizimi farkına dikkat edin: değer ile geçirme sürümü nokta operatörünü (p.name) kullanırken, işaretçi sürümü ok operatörünü (p->name) kullanır. Her iki fonksiyon da aynı formatta yazdırmalıdır.main.c: Bir Product oluşturun, ardından farklı parametre stilleri kullanmalarına rağmen aynı çıktıyı ürettiklerini göstermek için her iki görüntüleme fonksiyonunu da çağırın.
Üç girdi alacaksınız: ürün adı (bir dize), fiyat (bir double) ve miktar (bir tam sayı).
Ana dosyanızda, bir Product yapısını bu değerlerle başlatın, ardından display_by_value ve sonrasında display_by_pointer fonksiyonlarını çağırın.
Her iki fonksiyon da şu formatta yazdırmalıdır:
Product: {name}, Price: {price}, Qty: {quantity}Fiyatı iki ondalık basamakla görüntülemek için %.2f kullanın.
Örneğin, Laptop, 999.99 ve 5 girdileriyle çıktı şöyle olacaktır:
Product: Laptop, Price: 999.99, Qty: 5
Product: Laptop, Price: 999.99, Qty: 5Kopya kağıdı
Struct'ları fonksiyonlara geçirirken, değer ile geçirme (tüm struct'ı kopyalama) veya pointer ile geçirme (yalnızca adresi kopyalama) arasında seçim yapabilirsiniz.
Değer ile geçirme, struct'ın tam bir kopyasını oluşturur:
void print_by_value(Student s) {
printf("%s: %.2f\n", s.name, s.average); // Nokta operatörünü kullanın
}
Pointer ile geçirme, yalnızca bellek adresini geçirir:
void print_by_pointer(const Student *s) {
printf("%s: %.2f\n", s->name, s->average); // Ok operatörünü kullanın
}
Temel farklar:
- Değer ile geçirme nokta operatörünü kullanır (
s.member) - Pointer ile geçirme ok operatörünü kullanır (
s->member) - Pointer'lar büyük struct'lar için daha verimlidir (tüm struct boyutu yerine yalnızca 8 bayt)
- Fonksiyonun veriyi değiştirmemesi gerektiğinde pointer'larla birlikte
constkullanın
C programcıları, daha iyi performans için genellikle struct'ları pointer ile geçirmeyi tercih ederler.
Kendin dene
#include <stdio.h>
#include <string.h>
#include "product.h"
int main() {
char name[50];
double price;
int quantity;
// Girdileri oku
scanf("%s", name);
scanf("%lf", &price);
scanf("%d", &quantity);
// TODO: Bir Product değişkeni oluşturun ve onu girdi değerleriyle başlatın
// Hint: İsmi struct'ın name alanına kopyalamak için strcpy kullanın
// TODO: Product ile display_by_value fonksiyonunu çağırın
// TODO: Product işaretçisi ile display_by_pointer 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.
Object Oriented Programming bölümündeki tüm dersler
1Modüler Programlama Temelleri
Başlık DosyalarıInclude Guard'larKaynak DosyalarıStatik FonksiyonlarÖzet: Modüler Hesap Makinesi4Kapsülleme
Opaque Pointer KavramıOpaque Struct TanımlamaGetter ve Setter MetotlarıSetter Metotlarında DoğrulamaÖzet: Gizli Kutu2Nesneler ve Metotlar
Nesne Olarak Struct'lar'Self' İşaretçisiConst Doğruluğuİşaretçi vs DeğerYardımcı MetotlarÖzet: Point Manager5Proje: Basit Banka Hesabı
Proje KurulumuHesabın Oluşturulması3Nesne Yaşam Döngüsü
Constructor DeseniDestructor DeseniStack İlklendirmeDerin KopyalamaÖzet: String Wrapper6Kompozisyon Yoluyla Kalıtım
Struct Gömmeİlk Üye KuralıÜst Üyelere ErişimUpcastingÖzet: Şekil Hiyerarşisi