✤  نکات مهم در برنامه‌نویسی به زبان ++C

اجتناب از بررسی تساوی در اعداد اعشاری

  [برگرد بالا]

اعداد اعشاری در محاسبات ریاضی - مانند عمل تقسیم یا محاسبه‌ی توابع مثلثاتی و غیره - ممکن است حاوی مقدار بسیار ناچیزی خطا باشند که عموما ناشی از عملیات گرد کردن و قطع کردن نتایج مراحل میانی محاسبات هستند. در چنین حالتی به کار بردن عملگر تساوی لزوما به نتیجه‌ی درست ختم نمی‌شود. به عنوان مثال:

  

float f

/* f عملیات محاسباتی روی متغیر */

if(f == 0.0){

    /*

        عملیات بلاک شرط

    */

}

  

زمانی که تصور می‌کنید پس از انجام محاسبات مقدار f برابر صفر خواهد شد، ممکن است مقدار آن عدد بسیار کوچکی مانند 0.000000019 باشد که با عدد صفر برابر نیست. بنابراین عملکرد قطعه کد فوق با شکست مواجه خواهد شد.

در چنین حالتی بهتر است قرار گرفتن متغیر اعشاری در یک بازه را مورد بررسی قرار دهید:

  

float f

/* f عملیات محاسباتی روی متغیر */

if(f < 0.0001 && f > - 0.0001){

    /*

        عملیات بلاک شرط

    */

}

  

استفاده از اشاره‌گر به جای اندیس در پیمایش آرایه

  [برگرد بالا]

گاهی نیاز به پیمایش یک آرایه از ابتدا تا انتها وجود دارد. این پیمایش ممکن است برای مقداردهی عناصر آرایه، چاپ آنها، یا جستجوی مقدار خاصی انجام گیرد. چنین عملی در روش مختلف دارد.

اولین روش استفاده از اندیس آرایه است:

  

int array[10];

int i;

for(i = 0 ; i < 10 ; i++){

    array[i] = 0;

}

  

در هر تکرار این حالت، کامپایلر برای یافتن محل [array[i یک عمل ضرب عدد i در اندازه‌ی هر عنصر آرایه (در اینجا int) و جمع آن با آدرس شروع آرایه انجام می‌دهد.

در روش دوم که روش سریعتری نسبت به روش اول است، از اشاره‌گر استفاده می‌شود:

  

int array[10];

int *pInt, *pEnd = &array[9];

for(pInt = array ; pInt <=  pEnd; pInt++){

    *pInt = 0;

}

  

در این حالت اشاره‌گر pInt جایگزین شمارنده‌ی i شده است. اما دیگر نیازی به عملیات ضرب و جمع برای محاسبه‌ی محل عناصر وجود ندارد. بنابراین سرعت پردازش بالا می‌رود.

توجه: برای آشنایی با مفهوم اشاره‌گر و عملیات ریاضی روی آنها به مطلب با عنوان اشاره‌گرها در زبان ++C مراجعه نمایید.

  

دقت در استفاده از اشاره‌گر به عنوان مقدار خروجی تابع

  [برگرد بالا]

یکی از اشتباهات رایج در میان برنامه‌نویسان ++C، برگشت یک اشاره‌گر تعریف شده درون تابع است:

  

char* HexToAscii(unsigned nHex){

    char AsciiValue[10];

    /*

        عملیات تولید خروجی تابع

    */

    return AsciiValue;

}

  

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

روش سنتی برای رفع این مشکل، تعریف آرایه به صورت static است:

  

char* HexToAscii(unsigned nHex){

    static char AsciiValue[10];

    /*

        عملیات تولید خروجی تابع

    */

    return AsciiValue;

}

  

در این حالت آرایه فضای AsciiValue هرگز آزاد نشده و از بیرون تابع نیز در دسترس خواهد بود. اما این روش همیشه جوابگو نبوده و ممکن است مشکلاتی به همراه داشته باشد.

راه حل بهتر آن است که آدرس یک بافر به تابع ارسال شود و تابع خروجی خود را درون آن تولید کرده و آدرس همان بافر را بازگرداند:

  

char* HexToAscii(unsigned nHex, char *pBuffer, int nBufferSize){

    /*

        عملیات پر کردن بافر با مقدار مناسب

    */

    return pBuffer;

}

  

در این حالت pBuffer آدرس شروع بافر و nBufferSize اندازه‌ی بافر را مشخص می‌کند. تابع به جای استفاده از یک آرایه‌ی داخلی، خروجی را در بافر ریخته و آدرس آن را باز می‌گرداند.

توجه: با توجه به ثابت بودن آدرس بافر، می‌توان از مقدار بازگشتی تابع نظر کرد. انتقال آدرس ثابت از ورودی به خروجی کاربردهای خاص خود را دارد.

  

کاربرد کلمه‌ی کلیدی volatile

  [برگرد بالا]

متغیرهایی از نوع volatile متغیرهایی هستند که ممکن است مقدار آنها توسط یک پردازش خارجی تغییر یابد. این پردازش می‌تواند وقوع یک وقفه، یا تغییر از طریق یک پردازش موازی باشد.

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

  

volatile int Item;

int WaitForChange(){

    Item = 0;

    while(!Item); // حلقه با بدنه‌ی تهی

    return Item;

}

  

این تابع تا زمانی که Item صفر باشد درون حلقه باقی خواهد ماند. متغیر Item به صورت volatile معرفی شده است تا با هر بررسی شرط، مقدار Item از حافظه واکشی شود. این مقدار ممکن است توسط یک پردازش موازی دیگر، یا یک وقفه تغییر کند.

  

دقت در تعریف متغیرها به صورت یک عبارت

  [برگرد بالا]

همانطور که می‌دانید در زبان ++C می‌توان چند متغیر هم‌نوع را با یک عبارت تعریف کرد:

  

int a, b, c;

  

اینطور به نظر می‌رسد که عبارتی مانند

  

int* p, q, r;

  

سه اشاره‌گر به عدد صحیح را مشخص کند. اما اینگونه نیست! در واقع اشاره‌گر p و اعداد صحیح q و r معرفی شده‌اند. عملگرهایی مانند * (برای اشاره‌گر) و & (برای متغیر مرجع) تنها روی اولین عبارت بعد از خود عمل می‌کنند.

شکل صحیح عبارت فوق به این ترتیب است:

  

int *p, *q, *r;

  

به بیان دیگر، هیچ تفاوتی نمی‌کند عملگری مانند * چسبیده به int باشد، یا نام متغیر. تمام عبارت‌های زیر متغیر p را به عنوان اشاره‌گر به متغیر صحیح و q را عنوان متغیر صحیح معرفی می‌کنند:

  

int* p, q;

int * p, q;

int *p, q;

int*p,q;

  

منبع کمکی: کتاب The Best C/C++ Tips Ever، نوشته‌ی Anthony Porter، انتشارات Osborne McGraw-Hill

مسعود اقدسی‌فام

مسعود اقدسی‌فام هستم.

یک معلم علاقه‌مند به تحقیق، تدریس و نوشتن در حوزه‌های برنامه‌نویسی، الگوریتم و حل مسئله :)

algs.ir/sp8pi6z     اشتراک‌گذاری در LinkedIn     اشتراک‌گذاری در Twitter     ارسال با Telegram
نوشته‌ها از این دست
آخرین نوشته‌ها
       ✦   الگوریتم آنلاین
       ✦   ابزار CodinGame
بازدید نوشته
          ۲۴ ساعت گذشته:  ۴ بازدید
          ۳۰ روز گذشته:  ۵۰ بازدید
          کل: ۲۴۹۲ بازدید
  • 1
  • 2
  • 3
  • 4
  • 5

نام: *  

پست الکترونیک:

متن پیام: *  

01 02 06 07 08 09 10 11 12 13 14

• الناز
پنجشنبه، ۲۷ مهر ماه ۱۳۹۱، ساعت ۱۴:۲۷

خوب بود.خسته نباشین01

• محمد غلامی
سه‌شنبه، ۱۹ دی ماه ۱۳۹۱، ساعت ۰۲:۱۱

سلام

به نظر من :

    1. توضیحات مختصر ومفید بود

    2.سایت به صورت کاملا ساده وشفافه

    3.منبع خوبی برای نو اموزانه

    4.مثال ها کاملا قابل فهمه

    5.لینک هایی که گذاشتین کاملا مفید و مرتبت با سایت هست

در اخر از شما به خاطر وقتی که برای راه اندازی این سایت گذاشتین تشکر می کنم.

موفق باشید.03

• قایق بادی
یکشنبه، ۱۰ فروردین ماه ۱۳۹۳، ساعت ۰۰:۳۳

با تشکر خیلی عالی بود

• استخر بادی
شنبه، ۶ آذر ماه ۱۳۹۵، ساعت ۰۱:۳۵

خییلی عالی و کارامد بود

• جکوزی
شنبه، ۶ آذر ماه ۱۳۹۵، ساعت ۰۱:۴۷

متشکرم

• علی
یکشنبه، ۳۰ اردیبهشت ماه ۱۳۹۷، ساعت ۱۴:۵۶

عالی و مفید

• تور استانبول
پنجشنبه، ۵ مهر ماه ۱۳۹۷، ساعت ۱۲:۲۴

خیلی خوب بود برای سایتم استفاده کردم خسته نباشید 06