برای روشن کردن ترمینال، کلیک کن یا هر کلیدی را بزن

پرش به محتوای اصلی
>_
درس ۵مقدماتی

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

از ++ و -- تا +=، -=، *=، /=، %=: نوشتن خلاصه‌تر و خواناتر برای شمارش و انباشت

معمولی
مبانی و مقدمات•صفحات ۱۱-۱۲•۲۰ دقیقه•۲٬۱۱۷ کلمهزمان مطالعه: ۰ دقیقه
فهرست این درس
// اهداف۵
  • آشنایی با عملگر‌های افزایش (`++`) و کاهش (`--`) و معادل آن‌ها با `a = a + 1`
  • درک تفاوت دقیق **prefix** (`++a`) و **postfix** (`a++`) با مثال گام‌به‌گام
  • یادگیری پنج عملگر انتساب مرکب (`+=`، `-=`، `*=`، `/=`، `%=`) و معادل کامل آن‌ها
  • تحلیل عبارت‌های ترکیبی مثل `2 * a++` و درک ترتیب ارزیابی
  • شناخت رفتار نامشخص (Undefined Behavior) در عبارت‌های مثل `i = i++ + ++i` و چگونگی پرهیز از آن

چرا `++` اختراع شد؟

افزودن یک واحد به متغیر، یکی از پرکاربردترین عملیات‌ها در برنامه‌نویسی است: شمارش حلقه، شمردن تعداد ورودی‌ها، حرکت اندیس آرایه و...

در ابتدا می‌نوشتیم:

main.cppcpp

این کار درست است اما طولانی. ⁦C++⁩ (و C قبل از آن) یک نوشتار کوتاه‌تر اختراع کرد: عملگر افزایش (++) و عملگر کاهش (--). بنابراین:

  • a = a + 1 ← a++ یا ++a
  • a = a - 1 ← a-- یا --a

نام «⁦C++⁩» خود از همین عملگر گرفته شده! یعنی «C به‌علاوه یک قدم به جلو». این عملگر‌ها فقط برای افزایش یا کاهش یک واحدی کار می‌کنند؛ برای افزایش چند واحدی باید از += استفاده کنید (که در ادامه می‌آید).

نکته: هر دو شکل a++ و ++a مقدار a را یکی زیاد می‌کنند؛ اما در عبارت‌های ترکیبی، ترتیب ارزیابی متفاوت است که در ادامه بررسی می‌کنیم.

مثال ۱: استفاده پایه از ++ و --

وقتی ++ یا -- به تنهایی به‌عنوان یک دستور کامل نوشته شوند، فرقی نمی‌کند قبل یا بعد از متغیر بیایند. در هر دو حالت، مقدار متغیر یکی زیاد یا کم می‌شود.

تفاوت فقط زمانی ظاهر می‌شود که از این عملگر‌ها داخل یک عبارت بزرگ‌تر استفاده کنیم (مثلاً در b = a++).

افزایش و کاهش یک واحدی متغیر acpp
خروجی برنامه
After a++: 6
After ++a: 7
After a--: 6
After --a: 5
در حال باز کردن ویرایشگر…

Prefix در برابر Postfix: ترتیب ارزیابی

این یکی از مهم‌ترین تفاوت‌های ظریف ⁦C++⁩ است که مصاحبه‌های فنی زیادی روی آن تمرکز دارند:

++a (Prefix / پیش‌افزایش)

  • ابتدا مقدار a یکی زیاد می‌شود
  • سپس مقدار جدید در عبارت استفاده می‌شود
  • خلاصه: «اول افزایش، بعد استفاده»

a++ (Postfix / پس‌افزایش)

  • ابتدا مقدار فعلی a در عبارت استفاده می‌شود
  • سپس a یکی زیاد می‌شود
  • خلاصه: «اول استفاده، بعد افزایش»

مثال ملموس با a = 5:

  • b = ++a → ابتدا a می‌شود ۶، سپس b = a = 6. پس a = 6، b = 6.
  • b = a++ → ابتدا b = a = 5، سپس a می‌شود ۶. پس a = 6، b = 5.

قاعده طلایی برای یادآوری:

  • نماد قبل از متغیر (++a) یعنی «قبل از استفاده، افزایش بده»
  • نماد بعد از متغیر (a++) یعنی «استفاده کن، بعد افزایش بده»

اگر فقط به‌عنوان دستور مستقل (نه داخل عبارت) استفاده شوند، فرقی ندارند.

مثال ۲: مقایسه دقیق b = a++ و b = ++a

این برنامه هر دو حالت را با مقدار اولیه a = 5 امتحان می‌کند تا تفاوت را به وضوح ببینید. در حالت postfix، b مقدار قدیمی a (یعنی ۵) را می‌گیرد؛ در حالت prefix، b مقدار جدید a (یعنی ۶) را می‌گیرد.

این الگو در حلقه‌ها هم مصداق دارد: while (a++) در مقابل while (++a) رفتار متفاوتی نشان می‌دهد.

تفاوت postfix و prefix را با چاپ مقادیر مشاهده کنیدcpp
خروجی برنامه
Postfix:  a = 6, b = 5
Prefix:   a = 6, b = 6
در حال باز کردن ویرایشگر…

تحلیل گام‌به‌گام: `a = d++`

این مثال از صفحه ۱۱ جزوه است و یکی از کلاسیک‌ترین تله‌های postfix را نشان می‌دهد:

main.cppcpp

گام‌های ارزیابی a = d++:

۱. مقدار فعلی d (یعنی ۱۰) برای انتساب به a ارزیابی می‌شود. ۲. سپس d یکی زیاد می‌شود → d = 11. ۳. مقدار ذخیره شده در a همان ۱۰ است.

پس خروجی:

main.cppcpp

اگر به جای آن می‌نوشتیم a = ++d:

  • اول d می‌شد ۱۱
  • سپس a = 11
  • خروجی: 11 و 11

عملگر‌های انتساب مرکب (Compound Assignment)

وقتی می‌خواهیم یک عملیات را روی متغیر اعمال کنیم و نتیجه را در همان متغیر ذخیره کنیم، ⁦C++⁩ یک نوشتار خلاصه فراهم کرده است: عملگر‌های انتساب مرکب.

جدول کامل پنج عملگر انتساب مرکب حسابی:

عملگرمثالمعادل کاملمعنی
+=a += ba = a + bجمع و ذخیره
-=a -= ba = a - bتفریق و ذخیره
*=c *= 10c = c * 10ضرب و ذخیره
/=d /= 10d = d / 10تقسیم و ذخیره
%=a %= 3a = a % 3باقی‌مانده و ذخیره

مزایا:

۱. کوتاه‌تر: یک‌بار نام متغیر نوشته می‌شود. ۲. کم‌خطاتر: اگر نام متغیر طولانی باشد (مثل students_count)، احتمال اشتباه تایپی کاهش می‌یابد. ۳. خواناتر: قصد برنامه‌نویس واضح‌تر است: «این متغیر را تغییر بده، نه متغیر دیگری را».

نکته: اولویت این عملگر‌ها پایین است (مانند =) و از راست به چپ اجرا می‌شوند.

مثال ۳: هر پنج انتساب مرکب در یک برنامه

این برنامه هر پنج عملگر انتساب مرکب را روی متغیر a (با مقدار اولیه ۲۰) اعمال می‌کند و در هر مرحله مقدار جدید را چاپ می‌کند. به هر خط نگاه کنید و معادل کامل آن را در ذهن بازسازی کنید تا الگو در ذهنتان تثبیت شود.

نشان دادن معادل کامل هر عملگر با مقداردهی اولیه a = 20cpp
خروجی برنامه
a += 5  -> a = 25
a -= 5  -> a = 15
a *= 5  -> a = 100
a /= 5  -> a = 4
a %= 3  -> a = 2
a += b (b=7) -> a = 27
در حال باز کردن ویرایشگر…

تحلیل عبارت ترکیبی `2 * a++`

این مثال از صفحه ۱۲ جزوه است. عبارت 2 * a++ با a = 5 را گام‌به‌گام تحلیل می‌کنیم:

گام ۱: مقدار فعلی a (یعنی ۵) در عبارت استفاده می‌شود → 2 * 5 = 10.

گام ۲: سپس a یکی زیاد می‌شود → a = 6.

نتیجه: مقدار عبارت برابر ۱۰ است و a در پایان برابر ۶ می‌شود.

main.cppcpp

اگر به جای آن می‌نوشتیم 2 * ++a:

  • اول a می‌شد ۶
  • سپس 2 * 6 = 12
  • خروجی: 12 6

این نشان می‌دهد که postfix یا prefix بودن، در عبارت‌های ترکیبی تأثیر جدی بر نتیجه می‌گذارد.

مثال ۴: چاپ ردیف ستاره با ++ (پیش‌نمایش حلقه for)

این الگو را در درس‌های بعدی (حلقه for) به طور کامل یاد می‌گیریم، اما همین‌جا آن را به‌عنوان کاربرد ++ می‌بینیم. هدف: چاپ دو ردیف ستاره و کلمه hello بین آن‌ها. این الگو در صفحه ۱۱ جزوه آمده بود.

ایده: یک حلقه با شمارنده i از ۱ تا ۸، در هر گام یک ستاره چاپ می‌کند. گام حلقه i++ است که شمارنده را یکی زیاد می‌کند.

استفاده از ++ در شمارنده حلقه — الگوی پرکاربردcpp
خروجی برنامه
* * * * * * * * 
hello
* * * * * * * * 
در حال باز کردن ویرایشگر…

رفتار نامشخص (Undefined Behavior): یک تله خطرناک

یکی از خطرناک‌ترین تله‌های ⁦C++⁩ نوشتن عبارت‌هایی است که در آن‌ها یک متغیر در یک عبارت دو بار تغییر می‌کند. مثلاً:

main.cppcpp

این عبارت در استاندارد ⁦C++⁩ رفتار نامشخص (Undefined Behavior) دارد؛ یعنی استاندارد نمی‌گوید کدام ++ اول ارزیابی شود. هر کامپایلر ممکن است نتیجه متفاوتی بدهد:

  • GCC ممکن است بدهد: 4
  • Clang ممکن است بدهد: 5
  • MSVC ممکن است بدهد: 6

و حتی بدتر: با تغییر سطح بهینه‌سازی (-O0، -O2) در همان کامپایلر، خروجی می‌تواند تغییر کند!

چرا؟ چون دو عملگر ++ روی همان i در یک عبارت، درگیر نظم ارزیابی (Sequence Points) می‌شوند که استاندارد آن را نامشخص گذاشته است.

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

main.cppcpp

اگر در مصاحبه یا کنکور چنین عبارتی دیدید، جواب صحیح «Undefined Behavior» است، نه یک عدد مشخص!

اصلاح اشتباهات جزوه: علامت‌های نامعتبر در انتساب

در صفحه ۱۲ جزوه، جدولی از قوانین انتساب مرکب نوشته شده بود که در آن چند اشتباه تایپی دست‌نویس وجود داشت:

۱. سطر اول a۰=b; → a=a۰b; نوشته شده بود که در آن ۰ یک صفر فارسی است به جای عملگر واقعی. به نظر می‌رسد منظور a %= b (باقی‌مانده) بوده، یا یک placeholder کلی برای الگو بوده است.

۲. سطر ششم 1=; به جای %=; (یا حداقل =1) نوشته شده بود؛ این کاملاً نامعتبر است.

۳. در پاورقی نوشته شده بود «اولویت ++ بیشتر از -- است» که اشتباه است. در استاندارد ⁦C++⁩، ++ و -- هم‌تراز هستند و هر دو اولویت یکسانی دارند. تفاوت فقط در prefix یا postfix بودن است، نه در نوع عملگر.

همیشه قوانین را از منابع معتبر (مثل cppreference.com) بررسی کنید، نه از جزوه‌های دست‌نویس.

نسخه اشتباه جزوه
کد دارای باگcpp
نسخه اصلاح‌شده و استاندارد
کد صحیحcpp

چه زمانی `++` و چه زمان `+= 1`؟

هرچند a++ و a += 1 از نظر نتیجه یکسان هستند، اما عرف‌های فرهنگی وجود دارد:

  • ++ را برای شمارش‌های یک واحدی به کار ببرید: شمارنده حلقه (i++)، شمارنده تعداد (count++)، حرکت اندیس آرایه (p++).

  • += را برای افزایش با مقدار دلخواه به کار ببرید: sum += value، total += price * quantity.

  • += را حتی برای += 1 ترجیح دهید اگر در یک عبارت بزرگ‌تر قرار دارد و خوانایی مهم است؛ مثلاً if ((count += 1) >= 10) { ... }.

در حلقه for، هر سه حالت زیر معادل‌اند، اما i++ رایج‌ترین است:

main.cppcpp

فلوچارت: تحلیل b = a++

گام‌به‌گام ارزیابی عبارت b = a++ با a = 5. این فلوچارت نشان می‌دهد چرا postfix ابتدا مقدار قدیمی را می‌دهد و سپس a را افزایش می‌دهد.

flow.svg

مرور سریع مطالب

۱۳ بخش در این درس

تمرین‌ها

01
تمرین•حل کامل دارد

برنامه‌ای بنویسید که یک متغیر `count` را از ۰ شروع کند و در یک حلقه ۱۰ بار آن را با `count++` افزایش دهد. در نهایت مقدار نهایی را چاپ کند.

نمایش راهنما
از for (int i = 0; i < 10; i++) { count++; } استفاده کنید.
02
تمرین•حل کامل دارد

برنامه‌ای بنویسید که عدد `a = 100` را با عملگر‌های انتساب مرکب به‌ترتیب `-=` ۲۰، `/=` ۲ و `+=` ۵ کند و مقدار نهایی را چاپ کند.

نمایش راهنما
به‌ترتیب بنویسید: a -= 20; a /= 2; a += 5;. مقدار نهایی باید 45 باشد.
03
تمرین•حل کامل دارد

خروجی قطعه کد زیر را بدون اجرا پیش‌بینی کنید: ```cpp int a = 5, b; b = ++a; // prefix cout << a << " " << b << endl; a = 5; b = a++; // postfix cout << a << " " << b << endl; ```

نمایش راهنما
در prefix (++a) اول a یک واحد افزایش می‌یابد و سپس در عبارت استفاده می‌شود: a=6 و b=6. در postfix (a++) اول مقدار فعلی در b ذخیره می‌شود و سپس a افزایش می‌یابد: b=5 و سپس a=6. توجه: عبارت‌های مثل b = ++a + a++ رفتار نامشخص (UB) دارند چون a در یک expression دو بار تغییر می‌کند؛ هرگز چنین کدی ننویسید.
04
تمرین•حل کامل دارد

برنامه‌ای بنویسید که n عدد صحیح را بگیرد و با استفاده از `sum += x` مجموع آن‌ها را حساب کند و سپس میانگین را به‌صورت اعشاری چاپ کند.

نمایش راهنما
در بدنه حلقه بنویسید: cin >> x; sum += x;. در پایان از (float)sum / n برای خروجی اعشاری استفاده کنید.
// نکات-کلیدی۶
  • 01عملگر‌های `++` و `--` برای افزایش و کاهش یک واحدی متغیر استفاده می‌شوند و معادل `a = a + 1` و `a = a - 1` هستند.
  • 02تفاوت `++a` (prefix) و `a++` (postfix): در prefix اول افزایش و بعد استفاده، در postfix اول استفاده و بعد افزایش.
  • 03پنج عملگر انتساب مرکب: `+=`، `-=`، `*=`، `/=`، `%=`. هر کدام معادل `a = a OP b` هستند.
  • 04اولویت `++` و `--` در شکل prefix با عملگر‌های یگانی هم‌تراز است؛ اما شکل postfix (مثل `a++`) اولویت بالاتری از prefix دارد.
  • 05عبارت‌هایی مثل `i = i++ + ++i` رفتار نامشخص (UB) دارند و نباید نوشته شوند؛ هرگز یک متغیر را دو بار در یک عبارت تغییر ندهید.
  • 06در حلقه `for`، `i++` و `++i` از نظر نتیجه یکسان‌اند اما `++i` گاهی در ⁦C++⁩ کمی سریع‌تر است (برای انواع پیچیده‌تر).
گام بعدی پیشنهادی

کاراکتر‌ها و کدهای ASCII

از نوع char تا کدهای اسکی، تبدیل حروف بزرگ/کوچک و خواندن کلید بدون Enter با getch

۲۵ دقیقهمقدماتی۱۶ بخش

شروع درس

جستجوی سریع در درس‌ها

نام درس، موضوع یا کلمه کلیدی را بنویسید و با Enter به آن بروید