Menu
Coddy logo textTech

Struct'larda Fonksiyon İşaretçileri

Coddy'nin C Journey'sinin Object Oriented Programming bölümünün bir parçası — ders 38 / 61.

Şimdiye kadar, fonksiyon göstericilerini bağımsız değişkenler olarak kullandık veya argüman olarak geçirdik. Polimorfizme doğru bir sonraki adım, bir fonksiyon göstericisini doğrudan bir struct içine yerleştirmektir — bu da struct'a kendi davranışını kazandırır.

Bir struct bir fonksiyon göstericisi (function pointer) içerdiğinde, her bir örnek farklı bir fonksiyon tutabilir. Bu, aynı türdeki iki nesnenin, fonksiyon göstericilerini çağırdığınızda farklı davranabileceği anlamına gelir:

typedef void (*PrintFunc)(const char*);

typedef struct {
    const char* name;
    PrintFunc print;  // Bir üye olarak fonksiyon göstericisi
} Printer;

Printer yapısı artık iki üyeye sahiptir: veri (name) ve davranış (print). Bunu kullanmak için, başlatma sırasında işaretçiye bir fonksiyon atarsınız:

void loud_print(const char* msg) {
    printf("!!! %s !!!\n", msg);
}

int main() {
    Printer p;
    p.name = "Alert";
    p.print = loud_print;
    
    p.print("Hello");  // Çıktı: !!! Hello !!!
    return 0;
}

Fonksiyonu struct üzerinden nasıl çağırdığımıza dikkat edin: p.print("Hello"). Bu, diğer dillerdeki bir nesne üzerinde metot çağırmaya oldukça benzer görünür. Struct, hem verilerini hem de bu veriler üzerinde işlem yapan fonksiyonu taşır.

Bu desen, C'deki polimorfizmin temelidir — aynı struct türünden farklı davranışlar üreterek, farklı örneklere farklı fonksiyonlar atanabilir.

challenge icon

Görev

Kolay

Struct'ların fonksiyon göstericileri (function pointers) aracılığıyla kendi davranışlarını nasıl taşıyabildiğini gösteren bir Notifier sistemi kuralım.

Kodunuzu düzenlemek için iki dosya oluşturacaksınız:

  • notifier.h: Bir const char* parametresi alan ve hiçbir şey döndürmeyen NotifyFunc adında bir fonksiyon göstericisi türü tanımlayın. Ardından, bir name (bir const char*) ve NotifyFunc türünde bir notify fonksiyon göstericisi içeren bir Notifier struct'ı tanımlayın.
  • main.c: Başlık dosyanızı dahil edin ve iki bildirim fonksiyonu uygulayın:
    • alert_notify — mesajı şu formatta yazdırır: [ALERT] message
    • info_notify — mesajı şu formatta yazdırır: [INFO] message
    Ardından bir Notifier örneği oluşturun, girişe göre uygun fonksiyonu bağlayın ve bildirimi struct'ın fonksiyon göstericisi üzerinden çağırın.

Programınız iki giriş alacaktır: bir bildirim türü (alert için 1, info için 2) ve görüntülenecek bir mesaj.

Türe bağlı olarak, ilgili fonksiyonu notifier'ınızın notify üyesine atayın, ardından mesajı görüntülemek için struct üzerinden çağırın.

Tür 1 ve mesaj "System starting" olduğunda örnek çıktı:

[ALERT] System starting

Tür 2 ve mesaj "All systems normal" olduğunda örnek çıktı:

[INFO] All systems normal

Başlık dosyanızda include guard kullanmayı ve fonksiyonu struct üyesi üzerinden çağırmayı unutmayın: n.notify(message)

Kopya kağıdı

Fonksiyon göstericileri doğrudan yapıların (structs) içine gömülebilir, bu da her örneğe kendi davranışını kazandırır. Bu, C'de polimorfizmin (çok biçimlilik) temelidir.

Fonksiyon Göstericisi İçeren Bir Yapı Tanımlama

Öncelikle bir fonksiyon göstericisi türü tanımlayın, ardından bunu bir yapı üyesi olarak ekleyin:

typedef void (*PrintFunc)(const char*);

typedef struct {
    const char* name;
    PrintFunc print;  // Bir üye olarak fonksiyon göstericisi
} Printer;

Yapıyı Kullanma

Başlatma sırasında göstericiye bir fonksiyon atayın, ardından bu fonksiyonu yapı üzerinden çağırın:

void loud_print(const char* msg) {
    printf("!!! %s !!!\n", msg);
}

int main() {
    Printer p;
    p.name = "Alert";
    p.print = loud_print;
    
    p.print("Hello");  // Çıktı: !!! Hello !!!
    return 0;
}

p.print("Hello") sözdizimi, diğer dillerdeki bir nesne üzerinde metot çağırmaya benzer şekilde, fonksiyonu yapı üzerinden çağırır.

Polimorfik Davranış

Aynı yapı türünün farklı örneklerine farklı fonksiyonlar atanabilir, bu da aynı yapı türünden farklı davranışlar üretilmesini sağlar.

Kendin dene

#include <stdio.h>
#include "notifier.h"

// TODO: alert_notify fonksiyonunu uygula
// Şunu yazdırmalı: [ALERT] message


// TODO: info_notify fonksiyonunu uygula
// Şunu yazdırmalı: [INFO] message


int main() {
    int type;
    char message[256];
    
    // Girdiyi oku
    scanf("%d", &type);
    getchar(); // yeni satır karakterini tüket
    fgets(message, sizeof(message), stdin);
    
    // Eğer varsa, mesajın sonundaki yeni satır karakterini kaldır
    int len = 0;
    while (message[len] != '\0') len++;
    if (len > 0 && message[len-1] == '\n') message[len-1] = '\0';
    
    // TODO: Bir Notifier örneği oluştur
    
    
    // TODO: type değerine göre (alert için 1, info için 2),
    // uygun fonksiyonu notifier'ın notify üyesine ata
    
    
    // TODO: struct'ın fonksiyon göstericisi (function pointer) aracılığıyla bildirimi çağır
    // Kullanım: n.notify(message)
    
    
    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.

Object Oriented Programming bölümündeki tüm dersler