تبلیغات شما تبلیغات شما

آمار سایت

    آمار مطالب
    کل مطالب : 4090
    آمار کاربران
    افراد آنلاین : 8

    کاربران آنلاین

    آمار بازدید
    بازدید امروز : 3,005
    باردید دیروز : 2,578
    گوگل امروز : 16
    گوگل دیروز : 19
    بازدید هفته : 18,628
    بازدید ماه : 58,690
    بازدید سال : 175,711
    بازدید کلی : 6,622,739

آخرین فروش های موفق

مفاهيم شی گرائی

برنامه نویسی شیءگرائی (object oreinted programming) وسیله ای برای مدل کردن صحیح دنیای واقعی با استفاده از اشیا (objects) در برنامه و استفاده مجدد از کد است. یک شی در برنامه دقیقا همان طور تعريف می شود که در دنيای واقعی است؛ خواص معینی دارد که آن را توصیف می کند و متدهایی که می توانید برای انجام کار معینی روی شیء استفاده کنید.

هدف کلی C++ اضافه کردن شیءگرائی به زبان برنامه نویسی C است. یک شیء برای نگهداری داده استفاده می شود. داده و توابعی که روی داده کار می کنند به هم مربوط هستند بنابراين داده و توابع هردو با هم دریک بسته قرار می گیرند. شیءگرائی بيشتر روی داده تاکيد دارد تا عمليات و توابعی که روی داده کار می کنند.

مثال. ماشین یک شی است دارای خواصی مثل رنگ، تعداد درها و غیره است متدهای معینی دارد مانند سرعت گرفتن، ترمز کردن و غیره. می توان این شی را با استفاده از متدهایش استفاده کرد.

شرحی از داده ها و توابعی که می توانند روی داده کار کنند را کلاس (class) می نامند. کلاس را به عنوان الگوئی برای توليد شیء می توان تصور کرد. کلاس در واقع يک نوع داده user-defined است . اشياء نمونه هائی از کلاس ها هستند که در زمان اجرا ايجاد می شوند.

چهار مفهوم اصلی وجود دارند که اساس برنامه نویسی شیءگرائی را می سازند و توسط کلاس ها ارائه می شوند. این مفاهیم انتزاع (abstraction)، کپسوله کردن (encapsulation)، توارث (inheritance) و چندریختی (polymorphism) هستند.

انتزاع

شیء گرائی ابزاری را برای برنامه نویس فراهم می کند که اجزای فضای مسئله را توسط اشيا نمایش دهد. مسئله به بخش های تشکيل دهنده تجزيه می شود. هر مولفه يک شیء می شود که شامل داده های مرتبط و دستورالعمل های خود است. به اين ترتيب مسئله به همان صورتی که در دنيای واقعی هست توصیف می شود نه به روشی کامپیوتری که مسئله را حل می کند. یعنی می توانید با همه چيز در یک ترتیب کلی سروکار داشته باشید. پيچيدگی عمليات کاهش يافته و جزييات پياده سازی مخفی می ماند.


مثال. درباره خصوصیات کلی وسيله نقليه بدون سروکارداشتن با یک وسيله و مدل خاص می توان بحث کرد. يک نمونه شیء MyVehicle از کلاس Vehicle که خواص کلی و توابع وسايل نقليه را در بر دارد می توان ايجاد کرد. تابع Print مشخصات کلی وسيله نقليه را نمايش می دهد.

Vehicle MyVehicle;
MyVehicle.Print();


کپسوله کردن

قرار دادن داده و توابعی که روی داده کار می کنند را در یک بسته کپسوله کردن می گویند. در برنامه نویسی رویه گرا (مشابه آنچه تا کنون انجام می داديد) معلوم نیست چه تابعی روی چه متغیری کار می کند. در برنامه های پیچیده تر این روابط تیره تر می شوند. در برنامه نویسی شیءگرائی داده و توابع مربوط به آن- که اغلب متد (method) ناميده می شوند- با در يک بسته به نام کلاس قرار می گیرند بنابراین کاملا مشخص است چه تابعی روی چه داده ای کار می کند.

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

وراثت

یکی ديگر از جنبه های مفید برنامه نویسی شیءگرائی قابلیت استفاده مجدد از کد است. یک کلاس می تواند اعضای عمومی را از کلاس دیگر را به ارث ببرد. توارث اجازه می دهد کلاس جديدی شامل کليه داده ها و توابع کلاس (های) پياده سازی شود. کلاس موجود را کلاس پايه (base) و کلاس جديد که اعضای کلاس پايه را به ارث می گيرد را کلاس مشتق شده (derived) می نامند.


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


اگر کلاس ويژگی های تنها يک کلاس را به ارث ببرد وارثت منفرد(single inheritance) و اگر از چند کلاس به ارث گرفته شود وارثت چندگانه (multiple inheritance) ناميده می شود.

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

چندریختی

يک تابع در سلسله مراتب کلاس ها و زير کلاس ها می تواند به طرق مختلف پياده سازی شود و شکل های متعددی بگیرد. چندریختی یک رابط مشترک را برای پیاده سازی های مختلف از يک تابع در اختيار می گذارد که برای اشیا تحت شرایط مختلف متفاوت عمل کند. به عبارت ديگر فراخوانی تابعی که متعلق به کلاس است هميشه به شکل زير خواهد بود.

object.function(parameter-list)


مثال. در مثال قبل تابع نمايش برای قايق ممکن است متفاوت از نمايش يک وسيله نقليه باشد. دو تابع می توانند هم نام باشند ولی با کدهای متفاوت بسته به کلاس شیئی که تابع را فراخوانی می کند.

Vehicle MyVehicle;
Boat YourBoat;
MyVehicle.Print();
YourBoat.Print();


در مثال قبل کامپايلر نوع تابع print را برای دو نوع فراخوانی شده بر اساس نوع شیء می تواند پيدا کند. اما گاهی پيدا کردن آن تا زمان اجرای واقعی برنامه ممکن نيست. مشکل زمانی بروز می کند که به شیء از طريق اشاره گر دسترسی می شود و چون اشاره گرها می توانند بطور پويا به انواع مختلفی از اشيا اشاره کنند کلاس شیء تا زمان اجرا مشخص نمی شود. برای حل اين موضوع توابع عضو مجازی بکار می روند. توابع مجازی عضو (Virtual member functions) اجازه پياده سازی خاص تری از تابعی که فراخوانی می شود را مطابق با نوع شیء زمان اجرا می دهند.

دسترسی تصادفی فايل

هر فايل بازی يک انديکاتور موقعيت دارد که تعيين می کند عمل خواندن/نوشتن در کدام محل فايل انجام می شود. موقعيت هميشه برمبنای تعداد بايت ها از ابتدای فايل داده می شود. اگر فايل موجودی در مد اضافه کردن باز شود انديکاتور در انتهای فايل است در بقيه مدها انديکاتور در ابتدای فايل است و برابر صفر است.

توابع خواندن/نوشتن روی فايل که در محل انديکاتور انجام می شود باعث تغيير موقعيت آن می شود. مثلا اگر فايلی باز شود و 10 بايت از آن خوانده شود انديکاتور روی موقعيت 10 فايل قرار می گيرد. عمل بعدی روی موقعيت 10 انجام می گيرد.

C++ توابعی را در اختيار می گذارد (seekp و seekg) که امکان کنترل انديکاتور و دسترسی تصادفی به فايل را می دهند. يعنی می توانيد به هر نقطه ای درون فايل مراجعه کنيد بدون اينکه مجبور باشيد فايل را از ابتدا بخوانيد يا بنويسيد.


مثال. نمايش اندازه يک فايل.

#include <fstream.h>
#include <iostream.h>
int main () {
   long start,end;
   ifstream myfile (“test.txt”, ios::in|ios::binary);
   start = myfile.tellg();
   myfile.seekg (0, ios::end);
   end = myfile.tellg();
   myfile.close();
   cout << "size of " << “test.txt”;
   cout << " is " << (end-start) << " bytes.n";
   return 0;
}

فایل های متنی

فايل های متنی مورد استفاده بسياری دارند. يک فايل متنی (text file) جريانی از کاراکترهاست که دارای کاراکتر(های) خاصی برای نشانه گذاری انتهای هر خط است. فايل های متنی را با هر اديتورمتنی می توان توليد کرد يا محتويات آن را مشاهده کرد.


مثال. ايجاد يک فايل متنی با نام test.txt.

#include <fstream.h>
int main() {
   ofstream myfile ("test.txt");
   if (myfile.is_open()){
      myfile << "This outputting a line.n";
      myfile << "Guess what, this is another line.n";
      myfile.close();
      }
   return 0;
}

مثال. خواندن فايل متنی test.txt و نمايش آن روی صفحه.

#include <fstream.h>
#include <iostream.h>
int main (){
   char buffer[256];
   ifstream myfile ("test.txt");
   while (! myfile.eof() ) {
      myfile.getline (buffer,100);
      cout << buffer << endl;
   }
   return 0;
}


در فايل های متنی می توانيم اعداد را هم ذخيره کنيم. اعداد به صورت متن ذخيره می شوند. برای مثال عدد 236 به صورت کاراکتر'2' ، کاراکتر '3' و کاراکتر '6' ذخيره می شود. اين تبديل زمان اضافه می برد اما فايل حاصل قابل خواندن است.


فایل های باینری

فایل های باینری هم نوعی فايل مسطح هستند که در حالت دودوئی ذخیره می شوند. در حالت باینری هر فایل یک فرمت بایت به بایت دارد که باعث می شود فايل در ادیتور اسکی خوانا نباشد و کاراکترهای عجیبی نشان داده شود.

تابع write برای نوشتن داده در فايل باينری استفاده می شود. تابع دارای دو پارامتر است. اولی آدرس جائی که داده بايد نوشته شود و دومی تعداد بايت های داده است که نوشته می شود. تابع read برای خواندن از فايل باينری است.

اشيای ifstream و ofstream

در ++C برای کار کردن با فايل از کلاس های ifstream، ofstream و fstream استفاده می شود که در کتابخانه fstream.h تعريف شده اند. اشيای ifstream و ofstream مشابه cin و cout هستند. این اشیا می تواند در برنامه برای نمایش فایل های مسطح و دستکاری آنها بکار رود.

کلاس ifstream برای فايل های ورودی استفاده می شود. اگر می خواهيد فايلی را به منظور خواندن از آن باز کنيد یک نمونه از این کلاس را مانند زرر ایجاد کنید.

ifstream fin();

برای باز کردن فايلی به منظور نوشتن در آن بايد يک شیء ofstream ايجاد کرد.

ofstream fout();

کلاس ifstream شامل گروهی از توابع مورد استفاده روی فايل های ورودی است و کلاس ofstream توابع خروجی در فایل را دارد. عملکرد هردو در fsream ترکیب می شود. متدهای اصلی در جدول زیر نشان داده شده اند.

عملکرد تابع
به stream جاری فایل موجود می چسباند attach
محتوای بافر را پاک می کند clear
فایل باز متنی يا باينری را می بندد close
آیا در انتهای فایل باز شده می باشد یا خیر eof
یک کاراکتر از فایل می گیرد get
یک خط کامل از فایل می گیرد getline
اگر فایل باز متنی يا باينری شده باشد true بر می گرداند is_open
یک فایل متنی يا باينری را باز می کند open
از فايل باينری می خواند read
در مد باینری می تواند به مکان مشخصی از فایل برود seekg
ممحل اشاره گر فایل متن را تنظیم می کند seekp
موقعیت جاری اشاره گر فایل باينری را می دهد tellg
اشاره گر جاری فایل متن را بازیابی می کند tellp
یک دنباله از بايت ها را در فایل باينری می نویسد write

نام فايل

هر فايل روی ديسک دارای نامی است که هنگام کار کردن با آن مورد استفاده قرار می گيرد. نام فايل به صورت يک رشته کاراکتری است. قواعد نامگذاری فايل بسته به سيستم عامل دارد. در C++ نام فايل می تواند شامل اطلاعات مسير هم باشد. منظور از مسير دراويو و فولدری است که فايل در آنجا قرار دارد. اگر نام فايل بدون مسير مشخص شود محل فايل در موقعيت جاری درنظر گرفته می شود.


مثال. فايل test.txt از مسير جاری را به منظور خواندن باز می کند.

ifstream myfile("test.txt");

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

ifstream myfile ("c:\myfolder\test.txt");


در رشته ها کاراکتر بیان کننده کاراکتر escape است و دارای معنی خاص است به همين دليل برای جداکردن فولدر ها به جای باید از \ استفاده شود. اگر نام فايل از ورودی دريافت می شود يک علامت کافی است.

بازکردن فايل

فرآيند ارتباط بين جريان با فايل را باز کردن فايل می نامند. هنگامی که فايلی باز می شود برای خواندن و نوشتن آماده است. متد open يک فايل متن يا باينری را باز می کند. بايد یک متغیر از نوع ofstream/ifstream بسته به احتیاج تعریف شود.

ifstream infile;
ofstream outfile;
fstream myfile;

سپس فایل را با استفاده از open باز شود. اسم/مسير فایل و مد مورد نظر را تعيين کنید. مد مشخص می کند فايل ورودی، خروجی یا هردو است.فرم کلی متد به صورت زير است:

myfile.open(filename, mode)

filename رشته ای است که نام خارجی فايل، يعنی نامی که توسط ديسک شناخته شده است، را مشخص می کند. mode مقداری است که توسط ios تعريف می شود و مشخص می کند فايل با چه مدی (متن/باينری) و به چه منظوری (خواندن/نوشتن/ايجاد) باز شود. با استفاده از عملگر | می توان چند مقدار را با هم تلفيق کرد. پيش فرض فايل در مد متن باز می شود.


مثال. فايل متن myfile.txt را به منظور خواندن باز می کند.

infile.open("myfile.txt",ios::in);

مثال. فايل باينری myfile.txt را به منظور خواندن باز می کند.

infile.open("myfile.txt",ios::in|ios::binary);

مثال. فايل متن myfile.txt را به منظور نوشتن باز می کند.

outfile.open("myfile.txt",ios::out);

مثال. فايل متن myfile.txt را به منظور خواندن باز می کند.

myfile.open("myfile.txt",ios::in|ios::out);

مثال. فايل متن myfile.txt را به منظور اضافه کردن به انتهای آن خواندن باز می کند.

outfile.open("myfile.txt",ios::app);

مثال. فايل متن myfile.txt را پاک می کند و برای نوشتن باز می کند.

outfile.open("myfile.txt",ios::trunc);


تحت شرايطی ممکن است باز کردن فايل با عدم موفقيت روبرو شود نظير: استفاده از نام فايل غير مجاز، موجود نبودن فايل روی ديسک يا مسير ذکر شده، نداشتن اجازه دسترسی و .... اگر بازکردن فايل موفق نباشد تابع مقدار NULL را برمی گرداند که توسط متدهای is_open يا fail بررسی می شود و برنامه بايد پيغام خطای مناسب را با cerr نمايش دهد.


مثال.

if (!outfile.is_open()) {
   cerr << "Could not create file." << endl;
   exit(1);
   }


خواندن و نوشتن فايل

بعد از بازکردن فايل برنامه می تواند داده را از فايل بخواند يا مقداری را در فايل بنويسد. برای فايل های متن عملگرهای << و >> مشابه cin و cout‌ عمل می کنند و می توانند برای خواندن و نوشتن استفاده شوند.

تابع getline تابع خوبی است که اجازه می دهد يک خط از فايل متن (که به کاراکتر انتهای خط ختم شده است) را بخوانيد و در يک متغير رشته ای ذخيره کنيد. getline از فايل متن کاراکترها را تا رسيدن به کاراکتر انتهای خط می خواند. اما خود کاراکتر انتهای خط را در رشته ذخيره نمی کند.

در فايل های باينری متدهای read و write برای خواندن و نوشتن بکار می روند.


مثال. کپی کردن يک فايل در ديگری.

#include <string.h>
#include <fstream.h>
int main() {
   ifstream in("Scopy.cpp"); // Open for reading
   ofstream out("Scopy2.cpp"); // Open for writing
   string s;
   while(getline(in, s)) // Discards newline char
      out << s << "n"; // ... must add it back
}


تشخيص انتهای فايل

گاهی دقيقا می دانيد طول فايل چند بايت است بنابراين نيازی به تشخيص انتهای فايل نيست. ولی در اکثر مواقع از طول فايل اطلاعاتی نداريد. متد eof() زمانی که به انتهای فايل برسيد مقدار true را بر می گرداند.

بستن فايل

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

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

متد close() فايل را می بندد. اين متد کل جريان های بافر شده را به فايل منتقل می کند.

myfile.close();

اگر برنامه دچار شکست شود داده ممکن است داده موجود در بافر از دست برود. برای جلوگيری از اين کار در صورت نياز با استفاده از متد flush() می توانيد محتويات بافر را بدون بستن فايل به فايل منتقل کنيد.


مثال. يک فايل ممکن است در برنامه به منظور خواندن و نوشتن چندبار باز و بسته شود.

#include <fstream.h>
#include <iostream.h>
int main () {
   char buffer[256];
   fstream myfile; // open it for output then write to it
   myfile.open("test2.txt",ios::out | ios::trunc);
   if (myfile.is_open()) {
      myfile << "This outputting a line.n";
      myfile.close();
      }
   myfile.open("test.txt",ios::in); // open it for input and read in
   myfile.getline(buffer,100);
   cout << "The file contains " << buffer << "n";
   myfile.close();
   myfile.open("test.txt",ios::app); //open for appending and append
   myfile << " Hey this is another line n";
   myfile.close();
   myfile.open("test.txt",ios::in); // open it for input and read in
   myfile.getline(buffer,200);
   cout << "The file contains " << buffer << "n";
   myfile.close();
   return 0;
}


نکته. مديريت بافر با سيستم عامل است.
نکته. قبل از خواندن يا نوشتن فايل آن را باز کنيد.
نکته. هميشه بعد از بازکردن فايل چک کنيد فايل بطور موفق باز شده است يا خير.
نکته. موقعيت خود را درون فايل چک کنيد تا از انتهای فايل عبور نکنيد.
نکته. در انتها حتما فايل را ببنديد.

فایل مسطح

فایل های پایگاه داده دارای ساختار مشخصی هستند. روابط بین داده ها/ رکوردها و فایل های مختلف به روشنی در پایگاه داده تعریف می شود. برخلاف فايل های پايگاه داده، فایل مسطح (flat) ساختاری ندارد. داده در فايل به سادگی بدون ارتباط با داده های ديگر درون فايل يا فايل های ديگر ذخيره می شود. ممکن است تصور بشود که فایل های رابطه ای به دليل داشتن ساختار معين مناسب تر هستند اما حالت هایی وجود دارد که بهتر است داده در فایل های مسطح ذخيره شود تا پایگاه داده های رابطه ای پیچیده (مانند نوشتن log یا event یا exception ).

نکته. فایل هائی که در notepad می سازید فایل مسطح هستند.


جريان ها و فايل

++C کليه عمليات ورودی و خروجی و فايل را به صورت جريانی از بایت ها انجام می دهد. یک جریان (stream) یک دنباله از بایت ها است که هر بایت نشان دهنده یک کاراکتر است. جریان ورودی بایت هایی را از دستگاه ورودی، معمولا صفحه کلید یا یک فایل روی دیسک دریافت می کند. جريان خروجی بايت هائی را به صفحه نمايش، چاپگر يا فايل می فرستد.

برنامه بايد ارتباطی بين جريان و يک فايل معين روی ديسک برقرار کند. به عبارت ديگر يک جريان مربوط به فايل بايد قبل از استفاده باز شود. بعد از باز کردن فايل می توان اطلاعات را از فايل خواند يا درون فايل نوشت. هر فايل باز شده يک اشاره گر فايل دارد که بر اساس تعداد بايت هائی که از ابتدای فايل خوانده يا نوشته شده است موقعيت درون فايل را مشخص می کند. دسترسی به فايل باعث می شود اين اشاره گر بهنگام شود.

دو نوع دسترسی به فايل وجود دارد: ترتيبی و تصادفی. در دسترسی ترتيبی (sequential access) داده ها از فايل به ترتيب از ابتدا تا انتها خوانده می شوند. فايل با دسترسی مستقيم يا تصادفی (random access) اجازه می دهد اشاره گر فايل به هر نقطه مورد نظر در فايل پرش کند.

يک جريان فايل می تواند در دو مد متن (text) يا باينری (binary) باز شود. يک فايل متن شامل مجموعه ای از خطوط است. هر خط شامل مجموعه ای از کاراکترهاست که به کاراکتر انتهای خط (newline) ختم می شود (کاراکترهای با کد اسکی 10 و 13). ماکزيمم طول هر خط 255 کاراکتر است.

نکته. بخاطر داشته باشيد هر خط يک رشته منتهی به کاراکتر NULL نيست بلکه به کاراکتر انتهای خط ختم می شود.

فایل های مسطح متنی نوعی فایل ترتیبی هستند. ++C با این فایل ها به صورت دنباله ای از بایت ها برخورد می کند، فایل های ترتیبی ساختار اضافی ندارند هرساختار اضافی باید توسط برنامه تحمیل شود. راهی برای گردش در فایل های ترتيبی وجود ندارد، فايل هميشه بايد از ابتدا شروع شود.

فايل باينری داده ها را به همان فرمتی که در حافظه اصلی نمايش داده می شوند روی ديسک ذخيره می کند. بنابراين مانند فايل های متن اعداد به کاراکتر تبديل نمی شوند. اگر فايل باينری در يک اديتور متن باز شود اعداد به صورت کاراکترهای نامفهوم نمايش داده می شوند. فايل های باينری از هيچ نشانه ای برای جدا کردن خطوط داده ای استفاده نمی کنند.

آرگومان های خط فرمان

هنگامی که يک برنامه از خط فرمان سيستم عامل فراخوانی می شود آرگومان هائی را می توان به تابع main ارسال کرد. پارامترهای تابع main به شکل زير هستند.

int main(int argc, char* argv[])
{
...
}

argv هميشه آرايه ای رشته ای است که شامل دستوری است که در خط فرمان وارد می شود. فضای خالی، اجزای فرمان را از هم جدا و تبديل به آرگومان های جداگانه در آرايه می کند. argc تعداد عناصر درون آرايه پارامتر دوم است. argv[0] شامل مسير و نام خود برنامه است.


مثال. برنامه زير کليه آرگومان های خط فرمان را نمايش می دهد.

//CommandLineArgs.cpp
#include <iostream.h>
int main(int argc, char* argv[]) {
cout << "argc = " << argc << endl;
for(int i = 0; i < argc; i++)
cout << "argv[" << i << "] = "
<< argv[i] << endl;
}


اسامی argv و argc برای آرگومان های خط فرمامن الزامی نيست و می توان از شناسه های ديگر استفاده کرد ولی اين دو اسم متعارف هستند و استفاده از اسامی ديگر باعث گيج شدن افراد ديگر می شود.

اشاره گر به ساختمان

مشابه هر نوع داده ديگری می توان اشاره گری به ساختمان در برنامه اعلان کرد. اشاره گر به ساختمان معمولا برای ارسال ساختمان به تابع استفاده می شود. علاوه براين برای پياده سازی ساختمان داده مهم هم بکار می رود.

برای دسترسی به عناصر ساختمان از طريق اشاره گر باید از عملگر -> (indirect membership operator) استفاده شود.


مثال. استفاده از اشاره گر برای دسترسی به ساختمان

#include <iostream.h>
typedef struct account {
   float balance;
}
account *ptraccout;
int main() {
   ptraccount = new account;
   ptraccount->balance=2000;
   cout << ptraccount->balance;
   delete ptraccount;
   return 0;
}


راه ديگر برای دسترسی به اجزای ساختمان توسط اشاره گر استفاده از عملگر مرجع است. اشاره گر به همراه علامت * بايد درون پرانتز قرار گيرند زيرا عملگر (.) الويت بيشتری نسبت به (*) دارد.

(*ptraccount).balance = 2000;


اشاره گر به اشاره گر

C++ اجازه می دهد که اشاره گری به اشاره گر دیگر داشته باشید. چون یک اشاره گر یک روش غیر مستقیم دسترسی به یک متغیر است به همين دليل اشاره گر به اشاره گر غیر مستقیم چندگانه (multiple indirection) ناميده می شود. برای تولید اشاره گر به اشاره گر یک ستاره برای هر لایه از ارجاع اضافه می شود. بندرت اتفاق می افتد که اشاره گر به اشاره گر را در برنامه ای استفاده شود.


مثال.

char x;
char *y;
char **z;
x='z';
y=&x;
z=&y;

اشاره گر به تابع

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

اعلان و استفاده اشاره گر به تابع درنظر اول کمی متفاوت است ولی از همان قاعده تبعيت می کند. برای اعلان اشاره گر به تابع نام تابع درون پرانتز قرار می گيرد و قبل از آن علامت * قرار می گيرد. مشابه زير:

datatype (*pointerToFunction) (pElement) = NULL ;

*pointerToFunxtion اشاره گر به تابع است که درون پرانتز بايد باشد. سمت چپ آن نوع برگشتی و سمت راست آن پارامترهای تابع قرار می گيرند. سپس با NULL مقداردهی می شود.


مثال. funcPtr اشاره گر به تابعی است که هيچ آرگومان و مقدار برگشتی ندارد.

void (*funcPtr)() = NULL ;


مشابه آرايه ها، برای بدست آوردن آدرس تابع نيازی به عملگر آدرس & نيست. فراخوانی تابع توسط اشاره گر مشابه فراخوانی عادی تابع است.


مثال. متغير p اشاره گری به تابع square است. تابع به دو طريق فراخوانی شده است که خروجی هر دو فراخوانی يکسان است.

#include <iostream.h>
double square(double x); // The function prototype.
double (*p)(double x) = NULL; // The pointer declaration.
main() {
   p = square; // Initialize p to point to square().
   Cout << square(6) << p(6));
   return(0);
}
double square(double x) {
return x * x;
}


اشاره گر وپارامتر مرجع

همانطور که قبلا در بخش تابع گفته شد آرگومان به دو صورت مقداری و مرجع می تواند به تابع ارسال شود. در حالت مرجع آدرس آرگومان به تابع داده مي شود اين کار بسادگي با اضافه کردن علامت & (عملگر ادرس) قبل از پارامتر در خط اعلان تابع انجام مي شود.


اشاره گر و آرايه

ارتباط خاصی بين اشاره گرها و آرايه ها در ++C وجود دارد. از اشاره گرمی توان برای پيمايش آرايه ها استفاده کرد. در حقيقت اسم يک آرايه بدون هيچ انديسی اشاره گری به اولين خانه آن است. اگر آرايه ای به نام []array تعريف کرده باشيد array به اولين خانه آرايه اشاره می کند. بنابراين می توان به صورت غير مستقيم توسط عملگر * به عناصر آن دسترسی پيدا کرد. يعنی *array اولين خانه آرايه است و *(array+1) خانه دوم و به همين ترتيب الی آخر.

*(array) == array[0]
*(array + 1) == array[1]
*(array + 2) == array[2]
...
*(array + n) == array[n]

به عملگر & برای بدست آوردن آدرس آرايه نياز نيست البته می توان توسط &array[0] هم آدرس اولين عنصر آرايه را بدست آورد يعنی array == &array[0].


مثال. برنامه زير عناصر آرايه A را توسط اشاره گر نمايش می دهد.

#define MAX 10
int A[MAX] = {100, 90, 80, 70, 60, 50, 40, 30, 20, 10};
for (int i=0 ; i<10 ; i++)
   cout << *(A+i) << endl;

شکل زير ارتباط آرايه و آدرس های را نشان می دهد.


نکته. استفاده از اشاره گر برای آرايه روش سريع تری نبست نوشتن به انديس آرايه است.
نکته. هنگام کار کردن با آرايه توسط اشاره گر کامپايلر شروع و پايان آرايه را چک نمی کند بنابراين خودتان بايد مواظب باشيد از محدوده عناصر آرايه عبور نکنيد.
نکته. بخاطر داشته باشيد اسم آرايه يک ثابت اشاره گری است و نمی تواند تغيير کند و در طی اجرای برنامه ثابت می ماند.


اشاره گر و رشته

رشته يک آرايه کاراکتری است که به کاراکتر null ختم می شود. مانند آرايه نام رشته اشاره گری به اولين کاراکتر آن است بنابراين برای کار با رشته ها يک اشاره گر به کاراکتر بکار می آيد.


مثال. متغير Msg1 اشاره گری به کاراکتر است که با يک ثابت رشته ای مقداردهی اوليه شده است. 1Msg به اولين کاراکتر اين رشته اشاره می کند.

char *Msg1 = "This is a message";


راه ديگر برای استفاده اشاره گر برای رشته ها اختصاص فضای پويا به متغير اشاره گر است.


مثال. Msg2 متغير اشاره گری است که در حافظه پويا ايجاد شده است.

Msg2 = new char[16];
if (Msg2 == NULL) {
   cerr << "Could not allocate sufficient space" << endl;
   exit(1);
   }
strcpy(Msg2, "A new message");
cout << Msg2 << endl;
delete [] Msg2;

محاسبات روی اشاره گر

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

عملگر افزایش (++) مقدار متغیر را یکی اضافه می کند در حالیکه متغير اشاره گر را به تعداد بایت های نوع داده آن حرکت می دهد. اگر یک اشاره گر به عدد float دارید چون نوع float چهار بایت دارد با افزایش اشاره گر 4 واحد به آن اضافه می شود. بنابراین به 4 بایت بعدی حافظه اشاره می کند و دیگر به همان 4 بایت قبلی اشاره نمی کند.


مثال. اگر int را چهاربايت درنظر بگيريم، اشاره گر p هشت بايت به جلو حرکت می کند.

int a;
int p;
p=&a;
p=p+2;


عمل ديگری که روی اشاره گر ها انجام می شو تفاضل است. می توان مقدار دو اشاره گر را از هم کم کرد و فاصله بين آنها را بدست آورد.


مثال. اگر ptr1 و ptr2‌ هر دو اشاره گر باشند عبارت زير اختلاف فاصله آنها را می دهد.

ptr1 - ptr2


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

مقايسه دو متغير اشاره گر با هم تنها زمانی معتبر است که هردو به يک نوع داده اشاره کنند.


مثال. عبارت زير زمانی درست است که اشاره گر ptr1 به آدرسی قبل از ptr2 اشاره کند.

ptr1 < ptr2


توجه کنيد که عمل‍يات ضرب و تقسیم روی یک اشاره گر انجام نمی گيرد و باعث بروز خطای کامپايلر می شود.

تبلیغات شما تبلیغات شما

کدهای اختصاصی