چرا تابع؟ برنامهنویسی ساختیافته
در دههٔ ۱۹۶۰ تولید نرمافزار به بحران خورد: برنامهها بزرگ و پیچیده میشدند، زمانبندی تحویل عقب میافتاد، هزینهٔ نگهداری سرسامآور میشد و استفادهٔ بیقاعده از goto جریان برنامه را غیرقابلردیابی میکرد. پاسخ این بحران، برنامهنویسی ساختیافته بود: شکستن مسئله به قطعات کوچکتر با ورودی و خروجی روشن.
- ۱مسئلهٔ بزرگ را به زیرمسئلههای کوچکتر تقسیم کنید — هر زیرمسئله یک کار مشخص.
- ۲برای هر زیرمسئله یک تابع بنویسید: نام گویا، ورودیهای روشن، خروجی مشخص.
- ۳هر تابع را جداگانه بیازمایید؛ سپس در برنامهٔ اصلی کنار هم بگذارید.
- ۴ساختارهای کنترلی را به سه شکل محدود کنید: ترتیب، انتخاب، تکرار — بدون پرشهای بیقاعده.

انتزاع (Abstraction)
انتزاع یکی از مفاهیم کلیدی برنامهنویسی و در عین حال گیجکنندهترین آنهاست: در برنامهنویسی، انتزاع یعنی نشان دادن ویژگیهای ضروری و پنهانکردن جزئیات پیادهسازی. وقتی تابعی با نام average() میسازید، کاربر آن فقط میداند «میانگین میدهد» — نه اینکه داخلش حلقه و جمع و تقسیم است.
از ساختیافته تا شیءگرا
برنامهنویسی شیءگرا شیوهای است که قطعات نرمافزاری قابلاستفادهٔ مجدد میسازد: داده و عملیات مربوط به آن، در یک واحد به نام «شیء» بستهبندی میشوند.
| پارادایم | واحد اصلی | پرسش محوری | زبانهای نمونه |
|---|---|---|---|
| ساختیافته/رویهای | تابع (function) | چه گامهایی برای حل مسئله لازم است؟ | C، Pascal، بخش رویهای C++ |
| شیءگرا | شیء و کلاس (object / class) | چه اشیائی در مسئله وجود دارد و هر یک چه رفتاری دارد؟ | C++، Java، C#، Python |
| تابعی | تابع محض و دادهٔ تغییرناپذیر | چگونه داده را بدون حالت و عوارض جانبی تبدیل کنیم؟ | Haskell، F#، بخش تابعی C++ |
| همگانی/چندپارادایمی | ترکیبی از همهٔ ابزارها | کدام ابزار برای این مسئله مناسبتر است؟ | C++، Python، Rust |
📦کپسولهسازی encapsulation
داده و عملیات مربوط به آن در یک واحد بستهبندی میشوند و دسترسی بیرونی از دروازههای مشخص عبور میکند.
🧬وراثت inheritance
کلاس تازه میتواند ویژگیهای کلاس پایه را به ارث بگیرد و گسترش دهد؛ ابزار استفادهٔ مجدد از کد.
🎭چندریختی polymorphism
یک نام، رفتارهای متفاوت بر پایهٔ نوع واقعی شیء؛ پایهٔ طراحی انعطافپذیر.
🎯انتزاع abstraction
نمایش آنچه ضروری است و پنهانکردن جزئیات؛ از تابع تا واسط (interface).
struct Student { // کلاس: داده + رفتار std::string name; double grade; bool isPassed() const { return grade >= 10; } // رفتار }; Student s{"Sara", 17.5}; // شیء if (s.isPassed()) { std::cout << s.name << " قبول شد"; } // اگر تعریف Students را عوض کنیم، بقیهٔ برنامه تغییری نمیخواهد.
تعریف، اعلان و انواع توابع
زبان C++ خطبهخط و از بالا به پایین ترجمه میشود؛ پس اگر تابعی در برنامه استفاده میشود، باید پیش از نخستین فراخوانی شناخته شده باشد — یا تعریف شده باشد، یا اعلان شده باشد.
| اصطلاح | معنا | نمونه |
|---|---|---|
| اعلان (declaration) | نوشتن مشخصات تابع بدون بدنه؛ «قرارداد» تابع با کامپایلر | void printFunction(int n); |
| تعریف (definition) | مشخصات + بدنهٔ تابع؛ پیادهسازی واقعی | void printFunction(int n) { … } |
| تابع بازگردانندهٔ مقدار | نوع برگشتی غیر از void و دستور return | float Power(float x, int n); |
| تابع بیبازگشت | کار انجام میدهد و چیزی برنمیگرداند | void maghsom(int n); |
#include <iostream> void maghsom(int n) { for (int i = 1; i < n; i++) if (n % i == 0) { std::cout << i << " "; } std::cout << n; // خود عدد هم مقسوم خودش است } int main() { maghsom(12); // خروجی: 1 2 3 4 6 12 return 0; }
#include <iostream> float check(int x) { // مراقب تقسیم صحیح باشید if (x == 0) { return 2; } else if (x > 0) { return 3 * x + 5 / 2.0f; } else { return 3 * x - 5 / 2.0f; } } int main() { std::cout << check(4) << " " << check(0) << " " << check(-2); return 0; // خروجی: 14.5 2 -8.5 }
#include <iostream> void printFunction(int n); // اعلانها (پیشنمونهها) float Power(float x, int n); int main() { printFunction(4); std::cout << Power(2.0f, 10); // 1024 return 0; } void printFunction(int n) { // تعریفها پایینتر آمدهاند for (int i = 0; i < n; i++) std::cout << i << ' '; } float Power(float x, int n) { float result = 1; for (int i = 0; i < n; i++) result *= x; return result; }
توابع بازگشتی
بازگشتی مفهومی است که در آن تابع خودش را فراخوانی میکند — بهطور مستقیم یا غیرمستقیم. هر تابع بازگشتی دو بخش دارد: حالت پایه (شرط توقف) و گام بازگشتی (کوچککردن مسئله). حذف حالت پایه = بازگشت بیپایان و سرریز پشته.
#include <iostream> long fact(int x) { if (x != 0) { // گام بازگشتی return x * fact(x - 1); } return 1; // حالت پایه: 0! = 1 } int main() { std::cout << fact(5); // 120 return 0; }
#include <iostream> int Fibonacci(int number) { if (number <= 1) { return number; // حالت پایه } return Fibonacci(number - 1) + Fibonacci(number - 2); } int main() { for (int i = 0; i < 10; i++) std::cout << Fibonacci(i) << ' '; return 0; // 0 1 1 2 3 5 8 13 21 34 }
تمرینهای ردگیری از اسلایدهای منبع
| تابع | فراخوانی | ردگیری | پاسخ |
|---|---|---|---|
| rec(n) = اگر n==1 ← ۱، وگرنه rec(n-1)+rec(n-1) | rec(5) | هر سطح دو شاخه میسازد: rec(5)=16 چون 2×rec(4) و rec(1)=1 → 2⁴ = 16 | ۱۶ |
| func(n) = اگر n==0 ← ۰، وگرنه n + func(n-1) | func(100) | جمع اعداد ۱ تا ۱۰۰: (100×101)/2 | ۵۰۵۰ |
| sum(n) = اگر n<=1 ← n، وگرنه sum(n-1)+sum(n-3) | sum(4) | sum(4)=sum(3)+sum(1)؛ sum(3)=sum(2)+sum(0)=0؛ sum(1)=1 ← نتیجه | ۱ |
بارگذاری بیشازحد توابع
در اسلایدهای منبع این مفهوم با نام «چندریختی در توابع» معرفی شده است. تعریف دقیق امروزی: دو یا چند تابع همنام با فهرست پارامترهای متفاوت. کامپایلر بر اساس تعداد و نوع آرگومانها، نسخهٔ درست را انتخاب میکند.
#include <iostream> double Multiply() { return 1; } // بدون آرگومان double Multiply(double x) { return x * x; } // یک آرگومان double Multiply(double x, double y) { return x * y; } // دو آرگومان int main() { std::cout << Multiply() << ' ' << Multiply(4) << ' ' << Multiply(3, 5); return 0; // خروجی: 1 16 15 }
آرایههای ایستا
تعریف تعداد زیادی متغیر مستقل با نامهای مختلف، کاری طاقتفرسا و غیرمنطقی است؛ به همین دلیل طراحان زبان، آرایه را افزودند: مجموعهای از عناصر همنوع با یک نام مشترک و اندیسهای شمارهدار.
- ۱نوع دادهٔ آرایه مشخص میشود: int، float و…
- ۲نام آرایه درج میشود؛ برای همهٔ خانهها یک نام واحد.
- ۳تعداد عناصر داخل کروشه میآید: int grade[20];
- ۴اندیسها از صفر تا n-1 هستند: برای ۲۰ خانه، اندیسهای ۰ تا ۱۹.
چهار روش مقداردهی
// ۱) مقداردهی همزمان با تعریف int a[5] = {2, 4, 6, 8, 10}; // آرایهٔ تازه در C++: int a[5]{}; → همه صفر // ۲) مقداردهی خانهبهخانه int b[5]; b[0] = 7; b[1] = 3; // … // ۳) مقداردهی با حلقهٔ for (روش تعاملی) double points[5]; for (int i = 0; i < 5; i++) std::cin >> points[i]; // ۴) مقداردهی با حلقهٔ for بر پایهٔ الگو for (int i = 0; i < 5; i++) points[i] = i * 10; // 0 10 20 30 40
چاپ خانههای آرایه
| روش | توضیح | نمونه |
|---|---|---|
| چاپ خانهبهخانه | نوشتن جداگانهٔ هر خانه با cout | std::cout << a[0] << a[1]; |
| چاپ با حلقه | پیمایش همهٔ خانهها در یک حلقه | for (int i=0; i<n; i++) cout << a[i]; |
| پیمایش معکوس | از آخرین خانه به اولین خانه | for (int i=n-1; i>=0; i--) |
آرایههای پویا و مدیریت حافظه
اگر تعداد عناصر از پیش معلوم نباشد، آرایهٔ ایستا پاسخ نمیدهد: یا حافظهٔ اضافی هدر میرود، یا برنامه با کمبود حافظه شکست میخورد. آرایهٔ پویا در زمان اجرا از سیستمعامل حافظه میگیرد.
int n; std::cin >> n; double* px = new double[n]; // درخواست حافظه از «کپه» (heap) for (int i = 0; i < n; i++) px[i] = i * i; // مثل آرایهٔ معمولی کار میکند // … delete[] px; // آزادسازی الزامی px = nullptr; // جلوگیری از «اشارهگر معلق»
#include <iostream> #include <vector> int main() { int n; std::cin >> n; std::vector<double> px(n); // آرایهٔ پویا با مدیریت خودکار حافظه for (int i = 0; i < n; i++) px[i] = i * i; std::cout << px.size() << " عنصر آماده است"; return 0; // حافظه خودکار آزاد میشود }
| خطر | توضیح | جلوگیری |
|---|---|---|
| نشت حافظه (memory leak) | حافظهای که new شده و delete نشده است؛ برنامهٔ طولانیمدت کمحافظه میشود | std::vector، std::unique_ptr و اصل RAII |
| اشارهگر معلق | استفاده از اشارهگری که حافظهاش آزاد شده است | پس از delete، اشارهگر را nullptr کنید |
| آزادسازی نادرست | ترکیب new[] با delete (بدون کروشه) | هماهنگی دقیق: new[] با delete[] |
| آزادسازی دوباره | دو بار delete روی یک اشارهگر | مالکیت روشن؛ در کد امروز باید ابزار هوشمند کار را انجام دهد |
آرایه بهعنوان آرگومان تابع
آرایهها همانند متغیرهای معمولی به تابع فرستاده میشوند؛ با این تفاوت مهم که آرایه بهطور کامل کپی نمیشود.
#include <iostream> void fanc1(int x[]); // اعلانها void fanc2(int x[], int len); void findIterate(float a[], int len); // میانگین را مییابد و تکرارش را میشمارد int main() { int x[10]; fanc1(x); fanc2(x, 10); return 0; } void fanc1(int x[]) { /* طول آرایه را نمیدانیم! */ } void fanc2(int x[], int len) { /* طول را همراه آرایه میفرستیم */ }
مرتبسازی: مفاهیم و معیارها
مرتبکردن و جستوجوی اطلاعات از عملیات اساسی و اصلی علم رایانه است. مرتبسازی یعنی تجدید آرایش دادهها با یک ترتیب مشخص؛ جستوجو یعنی یافتن محل یک عنصر خاص در مجموعهای از رکوردها.
| اصطلاح | تعریف | چرا مهم است |
|---|---|---|
| کلید (key) | فیلدی در رکورد که رکوردها را بهطور یکتا مشخص میکند | مبنای مقایسه و ترتیب؛ جستوجو بر اساس کلید انجام میشود |
| مرتبسازی داخلی | مرتبسازی رکوردهای موجود در حافظهٔ اصلی | سرعت دسترسی بالا؛ روشهای این فصل از این نوعاند |
| مرتبسازی خارجی | مرتبسازی رکوردهای موجود در حافظهٔ جانبی (دیسک) | هزینهٔ خواندن/نوشتن غالب میشود؛ الگوریتمهای ادغامی و توزیعی مناسباند |
| مرتبسازی پایدار | رکوردهای با کلید مساوی، ترتیب قبلی خود را حفظ میکنند | مهم در گزارشگیری چندسطحی (مثلاً مرتبسازی بر اساس نام پس از مرتبسازی بر اساس شهر) |
| مرتبسازی درجا | با حافظهٔ کمکی ثابت و مستقل از تعداد عناصر انجام میشود | مناسب محیطهای کمحافظه |
| مرتبسازی با آدرس | بهجای جابهجایی رکوردها، جدول اشارهگرها جابهجا میشود | با رکوردهای بزرگ، صرفهٔ زمانی چشمگیر |
هفت روش مرتبسازی
فهرست روشهایی که در اسلایدهای منبع آمده است، بههمراه ایدهٔ هر یک و هزینهٔ امروزیشان. n تعداد عناصر است.
| روش | ایده در یک جمله | میانگین | بدترین حالت | حافظهٔ کمکی | پایدار |
|---|---|---|---|---|---|
| انتخابی (selection) | در هر گذر، کوچکترین عنصر باقیمانده را پیدا کن و در جایش بگذار | O(n²) | O(n²) | ثابت | خیر |
| حبابی (bubble) | همسایهها را مقایسه و جابهجا کن تا بزرگها به انتها بروند | O(n²) | O(n²) | ثابت | بله |
| درجی (insertion) | هر عنصر را در جای درست خود در بخش مرتبشده وارد کن | O(n²) | O(n²) | ثابت | بله |
| جابجایی/تعویضی (exchange) | هر عنصر را با عناصر بعدی مقایسه و در صورت نیاز عوض کن | O(n²) | O(n²) | ثابت | خیر |
| سریع (quick) | یک عنصر محور انتخاب کن، کوچکترها یک طرف و بزرگترها طرف دیگر، سپس بازگشتی | O(n log n) | O(n²) | O(log n) | خیر |
| ادغامی (merge) | دو نیمهٔ مرتب را در یک فهرست مرتب ادغام کن | O(n log n) | O(n log n) | O(n) | بله |
| مبنایی (radix) | رقمبهرقم از کمارزشترین رقم، عناصر را در سطلها توزیع کن | O(d·n) | O(d·n) | O(n) | بله |
مرتبسازی مبنایی: چهگونه کار میکند؟
مرتبسازی مبنایی روشی است که همه بهطور شهودی از آن استفاده میکنیم: وقتی فهرست بزرگی از نامها را بهترتیب الفبا مرتب میکنیم، مبنا ۲۶ (تعداد حروف انگلیسی) است و نامها نخست بر اساس حرف اول به دستهها تقسیم میشوند.
- ۱هر عدد را به ترتیبی که در آرایه دارد میخوانیم و بر اساس ارزش رقمی که در حال پردازش است، در یکی از ده صف (صفر تا نه) قرار میدهیم.
- ۲سپس صفها را به ترتیب از صف صفر تا صف نه میخوانیم و در آرایه بازنویسی میکنیم.
- ۳این عمل را برای رقم یکان انجام میدهیم، سپس رقم دهگان — یعنی از کمارزشترین رقم به سمت چپ حرکت میکنیم.
- ۴برای اعداد دورقمی، پس از دو گذر آرایه مرتب است؛ برای اعداد پنجرقمی به پنج گذر نیاز داریم.
| گذر | آرایه پیش از گذر | معیار توزیع | آرایه پس از گذر |
|---|---|---|---|
| ۰ (ورودی) | — | — | 57 48 37 12 92 86 33 25 |
| ۱ | 57 48 37 12 92 86 33 25 | رقم یکان | 12 92 33 25 86 57 37 48 |
| ۲ | 12 92 33 25 86 57 37 48 | رقم دهگان | 12 25 33 37 48 57 86 92 |
بهروزرسانی با دانش امروز
این صفحه از نظر حجم مطلب، سنگینترین بخش درس است. جدول زیر وضعیت امروز هر مفهوم را نشان میدهد.
| موضوع | در اسلایدهای منبع | وضعیت امروز (۲۰۲۶) |
|---|---|---|
| حافظهٔ پویا | new[] و delete[] برای آرایه | همان دستورها معتبرند، اما در کد امروزی جای خود را به std::vector، std::unique_ptr و std::make_unique دادهاند؛ مدیریت دستی حافظه فقط در کد پایینسطح و کتابخانهای لازم است. |
| آرایهٔ ایستا | int grade[20]; با اندازهٔ ثابت | همچنان رایج، ولی std::array (اندازه در نوع) و std::vector (اندازهٔ پویا) انتخابهای ایمنتر امروزند. |
| پارامتر آرایه | void fanc(int x[], int len) با فروپاشی آرایه | std::span (C++20) طول را همراه میبرد و سطح مرزها را ایمن نگه میدارد. |
| الگوریتم مرتبسازی | هفت روش دستی و پیادهسازی از صفر | برای استفادهٔ عملی: std::sort، std::stable_sort؛ پیادهسازی دستی برای درک الگوریتم، آموزش و نیازهای خاص (مانند مرتبسازی موازی یا مبنایی). |
| سنجش کارایی | شمارش مقایسهها بهطور شهودی | تحلیل مرتبهٔ زمانی O / Θ / Ω و معادلهٔ بازگشتی، بههمراه سنجش واقعی با ابزار زمانسنجی روی دادهٔ نماینده — معیار پذیرفتهشدهٔ مهندسی. |
| نگهداشت ترتیب | مفهوم پایداری معرفی شده بود | در عمل تعیینکننده است: Timsort در Python، Java و مرورگرها؛ پایداری پیشفرض بسیاری از زبانها. |
| انتخاب روش | مقدمهای بر معیارها در کتاب | قاعدهٔ عملی امروز: دادهٔ کوچک یا تقریباً مرتب ← درجی؛ حالت عمومی ← std::sort؛ نیاز به پایداری ← stable_sort؛ کلید با عرض محدود ← مبنایی/شمارشی؛ دادهٔ عظیم ← موازی یا توزیعشده. |
| آزمون صحت | چند نمونهٔ دستی | آزمون ویژگیمحور، آزمون یکا روی حالتهای مرزی (تهی، یک عنصر، عناصر تکراری، دادهٔ معکوس) و اجرای ابزارهای بررسی خطا. |
نقشهٔ پوشش منبع — کدام بخش این صفحه از کدام اسلاید استخراج شده است.
| بخش این صفحه | اسلایدهای منبع |
|---|---|
| ۷.۱ برنامهنویسی ساختیافته | فصل ۱ — مقدمه، ۱-۱ و ۱-۲ |
| ۷.۲ شیءگرا و انتزاع | فصل ۱ — ۱-۳ |
| ۷.۳ تعریف و اعلان توابع | فصل ۱ — فرمت کلی، اعلان، void و مقدار برگشتی |
| ۷.۴ بازگشتی | فصل ۱ — توابع بازگشتی و تمرینها |
| ۷.۵ بارگذاری بیشازحد | فصل ۱ — چندریختی در توابع |
| ۷.۶ آرایهٔ ایستا | فصل ۲ — تعریف، مقداردهی و چاپ |
| ۷.۷ آرایهٔ پویا | فصل ۲ — new و آزادسازی حافظه |
| ۷.۸ آرایه و تابع | فصل ۲ — ارسال آرایه به توابع |
| ۷.۹–۷.۱۱ مرتبسازی | فصل ۳ — مفاهیم، هفت روش و مرتبسازی مبنایی |
| ۷.۱۲ بهروزرسانیها | افزودهٔ سرویراستار (دانش ۲۰۲۶) |
پازل مفاهیم فصل
همهٔ مفاهیم این فصل، یکجا و بهشکل یک بازی: هر مفهوم را انتخاب کنید و به تعریف درستش وصل کنید — جفت درست همان لحظه سبز میشود و به آسمانِ جدول میپرد، جفت اشتباه با یک جرقه باز میشود. وقتی همهٔ جفتها کامل شد، «بررسی پاسخها» را بزنید تا بالنها بترکند و در آسمانِ جدول به هم گره بخورند. هر وقت خواستید پاسخنامه را ببینید، دکمهٔ «نمایش پاسخها» آن را کامل نشان میدهد.