نکات برنامه‌‌نویسی با زبان C : خطر اندیس متغیر در آرایه‌‌

 از موارد بسیار کاربردی در برنامه‌نویسی با زبان سی، آرایه‌ها هستند. در ادامه این قسمت می‌خواهیم به خطر احتمالی اندیس متغیر در آرایه ، که می‌تواند موجب باگ‌های خطرناک شود بپردازیم و همچنین ببینیم که چه راهکاری برای مقابله با این خطر احتمالی می‌توان به کار بست.

پیش نوشت: یکی از دلایلی که موجب شد تا زبان‌‌های برنامه‌نویسی شی‌گرا ایجاد شوند، خطرپذیر بودن برنامه‌نویسی با زبان‌هایی چون C بود. در زبان C دست شما برای انجام بسیاری از کارها باز است. این باز بودن، اغلب بی هیچ قید و شرطی است. گرچه این ویژگی می‌تواند به شما قدرت زیادی ببخشد، اما در عین حال می‌تواند باعث شود برنامه‌ای بنویسید که مملو از باگ است. آن هم باگ‌هایی که پیدا کردنشان بسیار سخت و گاهی غیرممکن است. به همین دلیل شرکت‌ها و برنامه نویسان حرفه‌ای برای آنکه در دام این مشکلات نیفتند، قواعدی برای خود وضع می‌کنند که تا حد زیادی مانع از به وجود آمدن چنین مشکلاتی می‌شود.

 در برنامه‌ای، لازم بود تا اطلاعات رسیده به پورت سریال 1 میکروکنترلر، در بافری ذخیره شود. به عبارتی دیگر در برنامه آرایه‌ای با اندازه 200، در نقش یک بافر، دیتا رسیده را به صورت موقت نگه می‌داشت.


 
uint8_t tempBuffer[200];
uint8_t freeIndex=0;

خب قاعدتاً لازم است برای ذخیره در خانه‌های آرایه، از متغیری استفاده شود که با هر بار رسیدن دیتا مقدارش یک واحد اضافه گردد. به این طریق شماره‌ی خانه‌ای از آرایه، که می‌توان درونش داده جدید را ذخیره کرد نگه دارد. از طرفی باید با هر بار خواندن و پردازش یکی از خانه‌های بافر، این متغیر را یک واحد کم کرد. در غیر این صورت تا زمانی که ارسال داده برقرار است مقدار  زیاد می‌شود و اگر از عدد 199 بیشتر شود و ما بخواهیم داده در  tempBuffer[freeIndex] بریزیم، مشکل به وجود خواهد آمد. چراکه برنامه در محلی از حافظه داده می‌ریزد که مربوط به جاهای دیگر برنامه است. همانطور که گفتم متاسفانه در اینجا کامپایلر به شما حتی اخطار هم نمی‌دهد و چه بسا برنامه شما در نگاه اول بسیار هم عالی کار کند و شما از نتیجه کارتان بسیار راضی باشید. اما امان از روزی که این مشکل خود را به شکلی نشان دهد، که اگر شانس بیاورید با سروکله زدن بسیار با کدها شاید بتوانید محل مشکل را پیدا کنید. اتفاقی که در ادامه برای من در این برنامه رخ داد.

در ابتدا برنامه بسیار عالی کار می‌کرد. اما با گسترش برنامه، حالتی به وجود آمد که در آن کم کردن freeIndex غیرفعال می‌شد و باگ برنامه خود را در کشیدن نموداری که هیچ ارتباطی با tempBuffer و freeIndex نداشت، نشان می‌داد. به این صورت که در لحظاتی از زمان، پرش‌هایی در نمودار شاهد بودیم که غیرعادی بود. احتمالا تا الان برای شما روشن شده که چرا حل این سری باگ‌ها اغلب اینقدر سخت است؟

در اینجا برنامه در حال تغییرِ مقدارِ محلی از حافظه است که ممکن است مربوط به متغیری در تابع و جای دیگری از برنامه باشد. حال تصور کنید که هنگام استفاده از این تابع و متغیر آن، بی آنکه دلیلش واضح باشد، خودبخود مقدار متغیر، تغییر کند. در آن صورت حتی با دیباگ کردن خط به خط هم به راحتی متوجه عامل تغییر نخواهید شد.

با توضیحات بالا ممکن است به راحتی بگویید خب پس باید همیشه حواسمان باشد که علاوه بر افزایش متغیر اندیس آرایه، حتماً جایی از برنامه آن را قبل از رسیدن به مقدار اندازه آرایه، کم کنیم. که البته من هم موافقم با شما، اما به نظر من این کافی نیست. توصیه‎ای که من در این خصوص دارم این است که در برنامه، جایی که قرار است مقدار freeIndex را افزایش دهید. قبل از این افزایش مقدار، حتماً با گذاشتن یک if چک کنید که آیا کوچکتر از حد مجاز هست یا خیر. مثلاً در این مثال که گفته شد مقدار freeIndex نباید از 199 بالا بزند و کد ما بهتر است به شکل زیر در بیاید تا جلوی یکی از مشکلات احتمالی گرفته شود.


 if(freeIndex<199)
  {
    freeIndex++;
  }