آرایههای C چرا اینقدر عجیبن؟
خلاصهٔ کاملتر
در زبان C، آرایهها از نظر تئوری یه نوع مستقل هستن؛ T[n] یعنی دنبالهای از n مقدار از نوع T در حافظه. ولی در عمل هر بار که بخوای به مقدار آرایه دسترسی پیدا کنی، کامپایلر اون رو به پوینتر T* تبدیل میکنه — یه رفتار خودکار که بهش array decay میگن. تنها استثناء مهم اینه که sizeof(arr) هنوز اندازهی واقعی آرایه رو برمیگردونه، نه اندازهی پوینتر.
یه مشکل جدیتر اینجاست: وقتی آرایه رو به عنوان آرگومان به تابع میدی، کامپایلر نوع آرایه رو کاملاً به پوینتر تبدیل میکنه و اطلاعات طول (n) کلاً دور انداخته میشه. یعنی sizeof(buf) داخل تابع اندازهی پوینتر رو برمیگردونه، نه آرایه رو:
size_t foo(char buf[6]) {
return sizeof(buf); // اندازهی پوینتر، نه ۶
}یه راهحل فعلی اینه که بهجای آرایه، پوینتر به آرایه پاس بدی (char (*buf)[6])، که طول رو حفظ میکنه ولی نوشتنش خوانا نیست.
نویسنده معتقده که آرایهها باید مثل struct رفتار کنن: کپی بشن، طولشون حفظ بشه، و برای تبدیل به پوینتر باید صریحاً بنویسی &arr[0]. این کار زبان رو قابل پیشبینیتر میکنه، چون الان این گیجکنندگی وجود داره که تغییر آرایه داخل تابع روی آرایهی بیرون هم اثر میذاره، ولی تغییر یه struct اینطور نیست.
برای ساختن یه آرایه از یه پوینتر، نویسنده از اپراتور @ در GDB (دیباگر معروف) الهام میگیره. این اپراتور به یه «place expression» (یه عبارت که آدرس حافظه داره، مثل *ptr) یه طول میده تا آرایه بسازه. مثلاً *ptr@4 یعنی آرایهای از ۴ عنصر که از آدرس ptr شروع میشه.
با این سینتکس، slice کردن آرایه هم خیلی طبیعی میشه:
int iota[4] = {0, 1, 2, 3};
int one_two[2] = iota[1]@2;در انتها، نویسنده به مفهوم wide pointer هم اشاره میکنه — ایدهای که Rust و C++ هم ازش استفاده میکنن: نگهداشتن پوینتر و طول آرایه کنار هم. در واقع هر بار که در C یه تابع مینویسی که size_t len, char *buf میگیره، داری یه wide pointer دستی پیادهسازی میکنی.
نکات کلیدی:
- آرایههای C بهصورت خودکار به پوینتر تبدیل میشن (array decay) و اطلاعات طول رو از دست میدن
- sizeof تنها جاییه که decay اتفاق نمیافته — مگر داخل تابع
- پاس دادن آرایه به تابع طول رو کاملاً حذف میکنه؛ char (*buf)[6] یه راهحل ناخوانا برای این مشکله
- نویسنده پیشنهاد میکنه آرایهها مثل struct کپی بشن تا رفتارشون قابل پیشبینیتر باشه
- اپراتور @ از GDB ایدهی جالبی برای ساختن آرایه از پوینتر با طول مشخص ارائه میده
- Wide pointer (ذخیرهی پوینتر + طول) راهحلیه که Rust بهصورت توکار داره و در C باید دستی پیادهسازی بشه




