ProgramlamaC geliştirici

C dilinde işlevlere işaretçi ve dizilerin geçirilmesi sırasında ne olur? Hangi farklılıklar, tuzaklar vardır ve yaygın hatalardan nasıl kaçınılır?

Hintsage yapay zeka asistanı ile mülakatları geçin

Cevap.

C dilinde bir işaretçi veya dizi işlevine geçirildiğinde aslında işaretçinin değerinin (yani bellek adresinin) bir kopyası geçirilir, dizi veya bellek içeriği değil. Tarihsel olarak diziler C dilinde değer ile geçilmez - bunun yerine işleve dizinin ilk elemanına işaret eden bir işaretçi gider. Bu mekanizma bellek tasarrufu sağlar, ancak yanlış kullanımda istenmeyen yan etkilere neden olabilir.

Sorun - işaretçiler ve diziler arasındaki kafa karışıklığı: geliştiriciler sık sık işlev içinde diziyi değiştiremeyeceklerini veya işlevin otomatik olarak geçirilen dizinin boyutunu bildiğini düşünürler. Pratikte işlev dizinin orijinal boyutunu kaybeder ve kolayca sınırlarının dışına çıkabilir.

Çözüm - her zaman dizinin boyutunu ayrı bir argüman olarak açıkça geçirmek, işaretçi kopyası ve nesne kopyası arasındaki farkı net bir şekilde anlamak, işaretçi üzerinden yapılan herhangi bir değişikliğin orijinal verilere yansıyacağını unutmamak.

Dizinin doğru bir şekilde geçirilmesine örnek:

void print_array(const int* arr, size_t size) { for (size_t i = 0; i < size; ++i) printf("%d ", arr[i]); } int main() { int nums[] = {1,2,3,4,5}; print_array(nums, sizeof(nums)/sizeof(nums[0])); return 0; }

Anahtar özellikler:

  • İşleve dizinin adresi geçirilir, elemanların kopyası değil.
  • Dizinin boyutu açıkça geçirilmelidir.
  • İşlev içinde elemanlardaki değişiklikler dışarıdaki diziyi değiştirir.

Kandırıcı sorular.

Bir işlev, int arr[10] olarak bildirildiğinde geçirilen dizinin uzunluğunu öğrenebilir mi?

Cevap: Hayır, işlev içinde sizeof(arr) ifadesi işaretçinin boyutunu döndürecektir, tüm dizinin boyutunu değil. Boyutu ayrı olarak geçirmek gerekir.

Diziyi int arr[] ve int arr olarak işlevlerde geçirmek aynı şey midir?*

Cevap: Evet, işlevin imzasında eşdeğerdir - her iki durumda da int için bir işaretçi geçirilir. Sadece sözdiziminde farklılıklar vardır.

İşlev içinde dizinin elemanlarını değiştirerek, orijinal dizi değişir mi?

Cevap: Evet, çünkü işaretçi geçirilmiş, işlev işaretçinin işaret ettiği belleği değiştirir.

Tipik hatalar ve anti-paternlere

  • Dizinin boyutunu argüman olarak geçirmemek (sınır dışı çıkış).
  • İşlev içinde dizinin boyutunu belirlemek için sizeof(arr) kullanmak (yanlış sonuç).
  • Farklı bağlamlarda int arr[10] ile int* arr'ı karıştırmak.

Gerçek dünyadan örnekler

Olumsuz durum

Proje dizileri başlatmak için bir işlev tanımlayarak boyutu işlev içinde sizeof(arr) / sizeof(arr[0]) ile belirledi. Test aşamasında işlev çalışıyordu, ancak diğer diziler işlenirken - başka bir bellek alanını yazıyor veya hatalı çalışıyordu.

Artılar:

  • İşlev imzası basitleşiyordu.

Eksiler:

  • Program diğer verilerle çöküyordu ya da hatalı çalışıyordu.

Olumlu durum

İşlev her zaman dizinin boyutunu ayrı bir parametre olarak alıyordu, uzunluk çağıran taraf tarafından hesaplanıyordu. İşlev içinde yalnızca geçirilen parametrelerle çalışılıyordu.

Artılar:

  • Sınır dışı çıkmama garantisi.
  • Daha güvenilir, emniyetli ve taşınabilir kod.

Eksiler:

  • Boyutun açıkça geçirilme gerekliliği, çağrının biraz daha uzun olması.