توضیح برخی از دستورات در++c

دستور break :

کلمه کلیدی break به معنی شکستن می باشد، که در زبان سی همان معنی شکستن حلقه یا خارج شدن از حلقه می باشد. وقتی برنامه به این دستور برسد از ساختار حلقه خارج می شود و دستورات بعدی را اجرا می کند. منظور دستورات داخل  {} می باشد از این دستور بیشتر در حلقه switch استفاده می شود که در ادامه توضیح کامل می دهیم. ابتدا یک مثال از break :

char i,b;
while (1) {
 i++;
 if (i==23) break;
}
b=i+6;

در این مثال دو متغییر i , b تعریف شده و بعد یک حلقه بی نهایت نوشتیم که در هر بار اجرای حلقه یک واحد به متغییر i اضافه می شود و بعد از آن یک دستور شرطی نوشتیم و گفتیم که اگر متغییر i برابر با 23 شد دستور break را اجرا کن که بعد از اجرا شدن آن برنامه از حلقه بیرون می آید و اولین دستور بعد از { را اجرا می کند که در اینجا متغییر i را با عدد 6 جمع می کند در متغییر b ذخیره می کند. که حاصل اون هم بابر با 29 می باشد.

دستور switch :

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

switch (متغییر) {
 case مقدار1 :
  { مجموعه دستورات1 };
 case مقدار2 :
  { مجموعه دستورات2 };
 case مقدار3 :
  { مجموعه دستورات3 };

default:
  { مجموعه دستورات };
}

برای روشن تر شدون موضوع به مثال زیر توجه کنید:

switch (i) {
 case 3:
  b=5; break;
 case 6:
  b=7; break;
 case 2:
  b=7; break;
default:
 b=55;
}

در این مثال ابتدا متغییر i انتخاب می شود و بعد 3 حالت یا کیس مختلف براش در نظر گرفتیم. نوشتیم که اگر توی متغییر i مقدار 3 هست بیا و عدد 6 را توی متغییر b قرار بده و از حلقه خارج شو یعنی حالت های بعدی رو دیگه امتحان نکن. خوب اگر در این مرحله i برابر با 3 نبود دستور break اجرا نخواهد شد و حالت بعدی امتحان می شود. و این کار همین طور ادامه دارد تا مقدار یکی از حالت ها با مقدار متغییر i برابر باشد، که در این صورت دستور break هم اجرار خواهد شد و دیگه حالت های بعدی امتحان نمی شوند و برنامه از حلقه خارج می شود. حال ممکن که هیج یک از حالت ها با مقدار متغییر برابر نباشد!! در این صورت دستور default اجرا می شود (به معنی مقدار پیش فرض) و متغییر b مقدار پیش فرض 55 را می گیرد. البته نوشتن دستور default اختیاری می باشد و شما می توانید ننویسید.

 نکته:

  1. در جلوی دستور case فقط می توانیم مقدار ثابت قرار دهیم یعنی نمی توانیم یک متغییر قرار دهیم.
  2. اگر در یکی از حالت ها یا همون case دستور break را قرار ندهیم با مقدار حالت بعدی OR می شود.

دستور goto :

از این دستور برای رفتن به یا به عبارتی پرش به یک لیبل یا برچسب می باشد. فرم کلی آن به صورت زیر می باشد:

goto  نام برچسب ;
نام برچسب:

مثال:

while (1) {
 i++;
  if (i==56) goto picpars;
}
picpars:
دستورات;

 ابتدا تشکیل یک حلقه بی نهایت و یعد هم افزایش یک واحدی به متغییر i و بعد تست یک شرط که اگر متغییر i برابر با 56 باشد از حلقه خارج می شود و به لیبل picpars پرش می کند و دستورات بعد از آن اجرا می شود.

 دستور continue :

این دستور بر خلاف دستور break از حلقه خارج نمی شود بلکه به ابتدای حلقه می رود. یعنی به ابتدای } می رود و مجددا دستورات داخل حلقه رو اجرا میکنه. به مثال زیر برای روشن تر شدن موضوع توجه کنید:

while (1) {
 i++;
  if (i==9) continue;
 i=i+2;
}

در این مثال ما یک حلقه بی نهایت تشکیل دادیم که در آن ابتدا افزایش یک واحدی به متغییر i اجرا می شود و بعد شرطی تست می شود که اگر محتوای متغییر i برابر با 9 بود دستور بعدی یعنی اضافه کردن عدد 2 به متغییر i اجرا نمی شود. دستور i=i+2 در حلقه همیشه اجرا می شود به جزء یک بار اون هم اگر i برابر با 9 بود این اتفاق می افتد.

تعریف توابع


تعریف اشاره گر ها


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

count به طور مستقيم به مقدار 7 مراجعه می کند .

countPtr به طور غير مستقيم به متغيری که حاوی 7 می باشد مراجعه می کند .

اشاره گرها نيز مانند هر متغير ديگری ، قبل از استفاده بايد تعريف شوند . به عنوان مثال دستور زير متغير count را از نوع int و متغير countPtr را اشاره گری به متغيری از نوع int تعريف می کند .

int count , *countPtr ;

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

به دستور زير توجه کنيد :

double *xPtr , *yPtr ;

در دستور فوق ، xPtr و yPtr اشاره گرهايی به متغيرهايی از نوع double تعريف می شوند .

نکته: استفاده از Ptr در انتهای نام متغيرهای اشاره گر الزامی نمی باشد ولی برای اينکه برنامه قابل فهم تر باشد توصيه می شود از Ptr در انتهای نام اشاره گر استفاده کنيد .

     

عملگرهای اشاره گر ها


   عملگر آدرس (&) عملگری است که آدرس خانه حافظه عملوند خود را بر می گرداند .

int y=5;
int *yPtr;
yPtr = &y;

   دستورات فوق متغير y را از نوع int با عدد 5 مقدار دهی کرده و سپس yPtr ، اشاره گری به متغيری از نوع int تعريف می شود و سرانجام آدرس خانه حافظه y در yPtr قرار می گيرد .

   همانطور که در شکل فوق می بينيد ، yPtr حاوی آدرس خانه حافظه y می باشد .

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

#include 
 
void main ()
{
  int x = 5, y = 15;
  int *xPtr, *yPtr;
 
  xPtr = &x;
  yPtr = &y;
 
  cout << "The value of x is " << x
       << "\nThe address of x is " << &x 
       << "\nThe value of xPtr is " << xPtr;
 
  cout << "\n\nThe value of y is " << y
       << "\nThe address of y is " << &y 
       << "\nThe value of yPtr is " << yPtr;
 
  *xPtr = 10;
  cout << "\n\nx=" << x << " and y=" << y;
 
  *yPtr = *xPtr;
  cout << "\nx=" << x << " and y=" << y;
 
  xPtr = yPtr;
  cout << "\nx=" << x << " and y=" << y;
 
  *xPtr = 20;
  cout << "\nx=" << x << " and y=" << y;
}

   خروجی برنامه فوق به صورت زير می باشد :

The value of x is 5
The address of x is 0x8fb4fff4
The value of xPtr is 0x8fb4fff4
 
The value of y is 15
The address of y is 0x8fb4fff2
The value of yPtr is 0x8fb4fff2
 
x=10 and y=15
x=10 and y=10
x=10 and y=10
x=10 and y=20

   در برنامه فوق دو متغير x وy از نوع عدد صحيح تعريف شده و x حاوی 5 و y حاوی 15 می گردد سپس xPtr و yPtr اشاره گری به عدد صحيح تعريف می شوند .

xPtr = &x;
yPtr = &y;

   دو دستور فوق همانطور که در خروجی برنامه نيز می بيند ، آدرس خانه حافظه x را در xPtr و آدرس خانه حافظه y را در yPtr قرار می دهد .

   دستور *xPtr = 10; در خانه ای از حافظه که xPtr اشاره می کند ( يعنی متغير x ) عدد 10 را قرار می دهد سپس*yPtr = *xPtr; مقدار خانه حافظه ای که xPtr به آن اشاره می کند را در خانه ای از حافظه که yPtr به آن اشاره می کند قرار می دهد يعنی مقدار متغير x در متغير y قرار می گيرد .

   دستور xPtr = yPtr; مقدار yPtr را که همان آدرس خانه حافظه y می باشد در xPtr قرار می دهد پس با اجرای اين دستور xPtr ديگر به x اشاره نمی کند بلکه به y اشاره خواهد کرد ، لذا با اجرای دستور *xPtr = 20; همانطور که مشاهده می کنيد x حاوی 20 نمی شود بلکه اين مقدار yاست که به 20 تغيير می يابد .

ارسال آرگومان به تابع توسط اشاره گر


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

#include 
 
void callByPointer( int * );
 
int main()
{
  int number = 5;
 
  cout << "The original value of number is " << number;
 
  // pass address of number to callByPointer
  callByPointer( &number );
 
  cout << "\nThe new value of number is " 
       << number << endl;
 
  return 0;
}
 
void callByPointer( int *nPtr )
{
  *nPtr = *nPtr * *nPtr * *nPtr; // cube *nPtr
}
 

خروجی برنامه فوق به صورت زير می باشد :

The original value of number is 5
The new value of number is 125

   همانطور که در برنامه فوق مشاهده می کنيد ، برای ارسال آرگومان به تابع توسط اشاره گر ، در پيش تعريف تابع پس از مشخص کردن نوع آرگومان از علامت * استفاده می کنيم و در تعريف تابع نيز علامت * را قبل از نام آرگومان اشاره گر قرار می دهيم . ضمناً از آنجا که اشاره گرها آدرس متغيرها را در خود قرار می دهند برای ارسال آرگومان توسط اشاره گر به يک تابع ، هنگام فراخوانی تابع بايد نام متغير ارسالی را همراه علامت & به کار ببريم چون تنها در اين صورت آدرس متغير ارسال می گردد .

اعمال محاسباتی با اشاره گرها


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

   يک اشاره گر می تواند افزايش (++) يا کاهش (--) يابد . يک عدد صحيح می تواند به آن اضافه (=+ يا +) و يا از آن کم (=- يا -) شود .

   فرض کنيد که آرايهint v[5] تعريف شده است و اولين خانه آن در آدرس 3000 از حافظه قرار دارد و فرض کنيد که vptr به خانهv[0] از آرايه اشاره می کند . توجه داشته باشيد که برای اينکه vptr به آرايه v اشاره کند کافی است از يکی از دستورات زير استفاده کنيم :

vptr = v;
vptr = &v[0];

   در رياضيات معمول 2+3000 برابر 3002 می شود اما در محاسبات اشاره گرها معمولاً بدين صورت نم باشد . هنگامی که عدد صحيحی به يک اشاره گر اضافه و يا از آن کم می شود ، مقدار اشاره گر معمولاً به اندازه آن عدد زياد يا کم نمی شود ، بلکه به اندازه طول نوع داده ای که اشاره گر به آن اشاره می کند ، زياد يا کم می شود . به عنوان مثال دستور vptr += 2; حاصلش برابر (3000 + 2*4) 3008 خواهد شد البته با فرض اينکه متغيری از نوع  int در چهار بايت از حافظه قرار می گيرد . در آرايه v ، اشاره گر vptr حالا به خانهv[2] اشاره می کند .

   اگر متغيری از نوع int در دو بايت از حافظه قرار بگيرد حاصل دستور vptr += 2; خانه (3000 + 2*2)3004 می بود .

   اگر vptr به خانه v[4] که در آدرس 3016 است اشاره کند اجرای دستور زير :

vptr -= 4;

باعث می شود که vptr به خانه(3016 - 4*4)3000 يعنیv[0] اشاره کند .

   هر يک از دستورات زير باعث می شود که اشاره گر به خانه بعدی آرايه v ، اشاره کند .

++vptr;
vptr++;

و هر يک از دستورات زير باعث می شود که اشاره گر به خانه قبلی آرايه v ، اشاره کند .

--vptr;
vptr--;

   اشاره گرهايی که به خانه های يک آرايه اشاره می کنند می توانند از يکديگر کم شوند . به عنوان مثال اگر vptr حاوی 3000 (يعنی به خانهv[0] اشاره کند ) و v2ptr حاوی 3008 ( يعنی به خانهv[2] اشاره کند ) دستور زير :

x=v2ptr - vptr;

   تعداد خانه های بين vptr تا v2ptr را در x قرار می دهد که در اينجا x حاوی 2 می گردد . محاسبات اشاره گرها تنها هنگامی که اشاره گرها به خانه های يک آرايه اشاره می کنند ، معنا دار هستند . همچنين مقايسه اشاره گرها نيز هنگامی مفهوم دارد که به خانه های يک آرايه اشاره کنند به عنوان مثال مقايسه دو اشاره گر می تواند نشان دهد که يکی از اشاره گرها به خانه ای با انديس بزرگتر نسبت به اشاره گر ديگر ، اشاره می کند .

ارتباط اشاره گرها و آرايه ها


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

int b[5];
int bptr;

   از آنجا که نام آرايه (بدون انديس) اشاره گری به عنصر اول آرايه می باشد ، می توانيم اشاره گرbptr را توسط دستور زير، به اولين عنصر آرايه b اشاره دهيم :

bptr = b;

   و يا می توانيم از دستور زير برای اشاره دادن bptr به عنصر اول آرايه b استفاده کنيم :

bptr = &b[0]

   برای دستيابی به عنصر b[3] توسط اشاره گر bptr که توسط يکی از دستورهای فوق به آرايه bمرتبط شد، می توان از دستور زير استفاده کرد :

*(bptr + 3)

   در مبحث قبل با مفهوم bptr+3 و عباراتی از اين قبيل آشنا شده ايد. از آنجايی که bptr به عنصر اول آرايه اشاره می کند پس حاوی آدرس عنصر اول آرايه يعنی b[0] می باشد، لذا bptr+3 آدرس خانه b[3] خواهد بود پس *(bptr + 3) به خانه b[3] اشاره خواهد کرد . توجه داشته باشيد که استفاده از پرانتز در اينجا اجباری می باشد ، چون عملگر * اولويت بالاتری نسبت به عملگر + دارد . اگر دستور فوق را بدون پرانتز به کار ببريم يعنی از bptr+3* استفاده کنيم عدد 3 به خانه b[0] اضافه می گردد .

   توجه داشته باشيد که *(b + 3) ( در اينجا b نام آرايه ای می باشد که در دستورات فوق تعريف گرديد ) نيز به خانه b[3] از آرايه اشاره می کند ، چون همانطور که در ابتدای اين بحث گفته شد نام آرايه همانند يک اشاره گر ثابت می باشد .

   اشاره گرها را نيز می توان مانند آرايه ها انديس دار کرد ، به عنوان مثال bptr[1] به عنصر b[1]رجوع خواهد کرد چون bptr اشاره گری به آرايهb می باشد .

   نکته : همانطور که می دانيد نام آرايه ، اشاره گر ثابتی می باشد لذا دستوری مانند b+=3; برای آرايه ای با نام b قابل استفاده نمی باشد ، چون اشاره گر ثابت همواره به يک خانه از حافظه اشاره می کند .

   برای درک نحوه ارتباط و شباهت آرايه ها و اشاره گرها ، به برنامه زير که در آن عناصر آرايه ای توسط چهار روش متفاوت در خروجی چاپ می شوند ، توجه کنيد :

#include 
 
void main()
{
  int b[] = { 10, 20, 30, 40 };
  int *bPtr = b;
  int i;
 
  cout << "b[i]:\n";
  for ( i = 0; i < 4; i++ )
    cout << "b[" << i << "] = " << b[ i ] << '\n';
 
  cout << "\n*(b + i):\n";
  for ( i = 0; i < 4; i++ )
    cout << "*(b + " << i << ") = "
         << *( b + i ) << '\n';
 
 
  cout << "\nbPtr[i]:\n";
  for ( i = 0; i < 4; i++ )
    cout << "bPtr[" << i << "] = " << bPtr[ i ] <<'\n';
 
  cout << "\n*(bPtr + i):\n";
  for ( i = 0; i < 4; i++ )
    cout << "*(bPtr + " << i << ") = "
         << *( bPtr + i ) << '\n';
 
}

خروجی برنامه فوق به صورت زير می باشد :

b[i]:
b[0] = 10
b[1] = 20
b[2] = 30
b[3] = 40
 
*(b + i):
*(b + 0) = 10
*(b + 1) = 20
*(b + 2) = 30
*(b + 3) = 40
 
bPtr[i]:
bPtr[0] = 10
bPtr[1] = 20
bPtr[2] = 30
bPtr[3] = 40
 
*(bPtr + i):
*(bPtr + 0) = 10
*(bPtr + 1) = 20
*(bPtr + 2) = 30
*(bPtr + 3) = 40

آرايه ای از اشاره گرها


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

const char *s[4] =
 { "string1","string2","string3","string4" }

   دستور فوق آرايه ای چهار عنصری شامل رشته هايی از حروف ايجاد می کند. *char در دستور فوق مشخص می کند که هر عنصر آرايه s ، اشاره گری به داده ای از نوع char می باشد . چهار مقداری که در آرايه قرار می گيرند "string1" و "string2" و "string3" و "string4" می باشند . انتهای هر کدام از اين رشته ها که در حافظه قرار می گيرند با کاراکتر پوچ مشخص می شود ، لذا طول اين رشته ها يک واحد بيشتر از تعداد حروفی می باشد که بين " " قرار دارد . در اين دستور طول هر يک از رشته ها هشت حرف می باشد . اگر چه به نظر می رسد که اين رشته از حروف درآرايه قرار می گيرند ولی در واقع اشاره گرهايی به اولين حرف هر يک از اين رشته ها در آرايه قرار دارد . به شکل زير توجه کنيد :

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

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

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


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

   برای آشنايی با نحوه کاربرد اشاره گرهای توابع، برنامه مرتب کردن حبابی عناصر آرايه را بازنويسی می کنيم. اين برنامه دارای توابع ascending ، swap ،bubble و descending می باشد . تابعbubble يک اشاره گر تابع را به عنوان آرگومان ، همراه با آرايه و عدد ثابتی به عنوان طول آرايه ، دريافت می کند .

   اين اشاره گر به تابع ، اشاره گری به يکی از توابع ascending يا descending می باشد که اين دو تابع نحوه مرتب شدن آرايه را از نظر صعودی يا نزولی بودن تشخيص می دهند. برنامه در ابتدا از کاربر نحوه مرتب کردن عناصر را که به صورت صعودی مرتب شوند يا نزولی ، می پرسد . اگر کاربر عدد1 را وارد کند ، يک اشاره گر به تابع ascending به عنوان آرگومان، به تابع bubble ارسال می شود که باعث می شود عناصر آرايه به صورت صعودی مرتب شوند. و اگر کاربر عدد 2 را وارد کند ، يک اشاره گر به تابع descending به عنوان آرگومان، به تابع bubble ارسال می گردد که باعث می شود عناصر آرايه به صورت نزولی مرتب شوند. به کدهای اين برنامه توجه کنيد :

#include 
 
void bubble( int [], const int, int (*)( int, int ) );
void swap( int * const, int * const );
int ascending( int, int );
int descending( int, int );
 
void main()
{
  const int arraySize = 10;
  int order;
  int counter;
  int a[ arraySize ] = { 2, 6, 4, 8, 10,
                         12, 89, 68, 45, 37 };
 
  cout << "Enter 1 to sort in ascending order,\n"
       << "Enter 2 to sort in descending order: ";
  cin >> order;
  cout << "\nData items in original order\n";
 
  for ( counter = 0; counter < arraySize; counter++ )
    cout << " " << a[ counter ];
 
  if ( order == 1 ) {
    bubble( a, arraySize, ascending );
    cout << "\nData items in ascending order\n";
  }
  else {
    bubble( a, arraySize, descending );
    cout << "\nData items in descending order\n";
  }
 
  for ( counter = 0; counter < arraySize; counter++ )
    cout << " " << a[ counter ];
 
  cout << endl;
}
 
void bubble( int work[], const int size,
             int (*compare)( int, int ) )
{
  for ( int pass = 1; pass < size; pass++ )
    for ( int count = 0; count < size-1; count++)
      if ( (*compare)( work[count], work[count + 1]))
        swap( &work[ count ], &work[count + 1]);
}
 
void swap( int * const element1Ptr, 
           int * const element2Ptr )
{
  int hold = *element1Ptr;
  *element1Ptr = *element2Ptr;
  *element2Ptr = hold;
}
 
int ascending( int a, int b )
{
  return b < a;
}
 
int descending( int a, int b )
{
  return b > a;
}

 خروجی برنامه فوق به صورت زير می باشد :

Enter 1 to sort in ascending order,
Enter 2 to sort in descending order: 1
 
Data items in original order
  2  6  4  8  10  12  89  68  45  37
Data items in ascending order
  2  4  6  8  10  12  37  45  68  89
Enter 1 to sort in ascending order,
Enter 2 to sort in descending order: 2
 
Data items in original order
  2  6  4  8  10  12  89  68  45  37
Data items in descending order
  89  68  45  37  12  10  8  6  4  2

   همانطور که در برنامه ديديد آرگومان زير در تابع bubble مورد استفاده قرار گرفت :

int (*compare) (int , int)

   اين دستور به تابع bubble می گويد که آرگومانی که دريافت می کند، يک اشاره گر به تابعی می باشد که دو آرگومان از نوع عدد صحيح دريافت می کند و خروجی آن از نوع int می باشد.

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

int *compare (int,int)

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

   اين آرگومان در پيش تعريف تابع bubble به صورت زير می باشد :

int (*)(int,int)

   توجه داشته باشيد که تنها نوع داده ها مشخص شده است و نيازی به ذکر نام داده ها و آرگومانها نمی باشد .

   تابع ارسال شده به bubble توسط دستور زير فراخوانی می شود :

(*compare) (work[count],work[count+1])

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

#include 
 
void function1( int );
void function2( int );
void function3( int );
 
int main()
{
  void(*f[ 3 ])(int)={function1, function2, function3};
 
  int choice;
 
  cout << "Enter a number between 0 and 2, 3 to end:";
  cin >> choice;
 
  while ( choice >= 0 && choice < 3 ) {
 
   (*f[ choice ])( choice ); 
 
    cout <<"Enter a number between 0 and 2, 3 to end:";
    cin >> choice;
  }
 
  cout << "Program execution completed." << endl;
 
  return 0;
}
 
void function1( int a )
{
  cout << "You entered " << a 
       << " so function1 was called\n\n";
}
 
void function2( int b )
{
  cout << "You entered " << b 
       << " so function2 was called\n\n";
}
 
void function3( int c )
{
  cout << "You entered " << c 
       << " so function3 was called\n\n";
}

خروجی برنامه فوق به صورت زير می باشد :

Enter a number between 0 and 2, 3 to end: 2
You entered 2 so function3 was called
 
Enter a number between 0 and 2, 3 to end: 0
You entered 0 so function1 was called
 
Enter a number between 0 and 2, 3 to end: 1
You entered 1 so function2 was called
 
Enter a number between 0 and 2, 3 to end: 3
Program execution completed.

   در برنامه فوق سه تابع با نامهای function1 و function2 و function3 که هر يک عدد صحيحی را به عنوان ورودی دريافت می کنند و خروجی ندارند ، تعريف شده است. دستور زير اشاره گرهای به اين سه تابع را در آرايه ای با نام f قرار می دهد .

void (*f[3]) (int) = {function1,function2,function3};

   همانطور که می بينيد نوع آرايه کاملاً مثل نوع توابع، تعريف شده است ، چون اين آرايه حاوی اشاره گرهايی به توابع می باشد . هنگامی که کاربر عددی را بين 0 تا 2 وارد می کند ، عدد وارد شده به عنوان انديس آرايه f استفاده می شود . لذا دستور زير :

(*f[choice]) (choice);

 باعث اجرای يکی از توابع آرایه f میشود و Choice به عنوان آرگومان به تابع ارسال 

پردازش رشته ها


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

char *strcpy (char *s1, const char *s2);

   تابع فوق رشته s2 را در رشته s1 کپی می کند و مقدار s1 به عنوان خروجی تابع برگردانده می شود .

char *strncpy (char *s1, const char *s2, size_t n);

   تابع فوق تعداد n حرف را از رشته s2 در رشته s1 کپی می کند و s1 را به عنوان خروجی برمی گرداند . به برنامه زير توجه کنيد :

#include 
#include 
 
void main()
{
  char x[] = "Happy Birthday to You";
  char y[ 25 ];
  char z[ 15 ];
 
  strcpy( y, x ); // copy contents of x into y
 
  cout << "The string in array x is: " << x
       << "\nThe string in array y is: " << y << '\n';
 
  // copy first 14 characters of x into z
  strncpy( z, x, 14 ); // does not copy null character
  z[ 14 ] = '\0'; // append '\0' to z's contents
 
  cout << "The string in array z is: " << z << endl;
}

   خروجی برنامه فوق به صورت زير می باشد :

The string in array x is: Happy Birthday to You
The string in array y is: Happy Birthday to You
The string in array z is: Happy Birthday

char *strcat (char *s1, const char *s2);

   تابع فوق رشته s2 را به انتهای رشته s1 اضافه می کند و s1 را به عنوان خروجی بر می گرداند .

char *strncat (char *s1, const char *s2, size_t n);

   تابع فوق n حرف از رشته s2 را به رشته s1 اضافه می کند و s1 را به عنوان خروجی تابع بر می گرداند. به برنامه زير توجه کنيد :

#include 
#include 
 
void main()
{
  char s1[ 20 ] = "Happy ";
  char s2[] = "New Year ";
  char s3[ 40 ] = "";
 
  cout << "s1 = " << s1 << "\ns2 = " << s2;
 
  strcat( s1, s2 ); // concatenate s2 to s1
 
  cout << "\n\nAfter strcat(s1, s2):\ns1 = " << s1 
       << "\ns2 = " << s2;
 
  // concatenate first 6 characters of s1 to s3
  // and places '\0' after last character
  strncat( s3, s1, 6 ); 
  
 
  cout << "\n\nAfter strncat(s3, s1, 6):\ns1 = " << s1 
       << "\ns3 = " << s3;
 
  strcat( s3, s1 ); // concatenate s1 to s3 
  cout << "\n\nAfter strcat(s3, s1):\ns1 = " << s1 
       << "\ns3 = " << s3 << endl;
}

   خروجی برنامه به صورت زير می باشد :

s1 = Happy
s2 = New Year
 
After strcat(s1, s2):
s1 = Happy New Year
s2 = New Year
 
After strncat(s3, s1, 6):
s1 = Happy New Year
s3 = Happy
 
After strcat(s3, s1):
s1 = Happy New Year
s3 = Happy Happy New Year
 

int strcmp (const char *s1, const char *s2);

   تابع فوق رشته s1 را با رشته s2 مقايسه می کند . اگر دو رشته برابر بودند مقدار صفر برگردانده می شود ، اگر رشته s1 کوچکتر از s2 باشد عددی منفی و اگر رشته s1 بزرگتر از s2 باشد عددی مثبت خروجی تابع خواهند بود .

int strncmp (const char *s1, const char *s2, size_t n);

   تابع فوق n حرف اول رشته s1 را با رشته s2 مقايسه می کند و خروجی تابع همانند خروجیstrcmp خواهد بود . به برنامه زير توجه کنيد :

#include 
#include 
 
void main()
{
  char *s1 = "Happy New Year";
  char *s2 = "Happy New Year";
  char *s3 = "Happy Holidays";
 
  cout << "s1 = " << s1 << "\ns2 = " << s2
       << "\ns3 = " << s3 << "\n\nstrcmp(s1, s2) = " 
       << " " << strcmp( s1, s2 )
       << "\nstrcmp(s1, s3) = " << " "
       << strcmp( s1, s3 ) << "\nstrcmp(s3, s1) = "
       << " " << strcmp( s3, s1 );
 
  cout << "\n\nstrncmp(s1, s3, 6) = " << " "
       << strncmp(s1,s3,6) << "\nstrncmp(s1,s3,7) = "
       << " " << strncmp( s1, s3, 7 )
       << "\nstrncmp(s3, s1, 7) = "
       << " " << strncmp( s3, s1, 7 ) << endl;
}

خروجی برنامه فوق به صورت زير می باشد :

s1 = Happy New Year
s2 = Happy New Year
s3 = Happy Holidays
 
strcmp(s1, s2) = 0
strcmp(s1, s3) = 6
strcmp(s3, s1) = -6
 
strncmp(s1, s3, 6) = 0
strncmp(s1, s3, 7) = 6
strncmp(s3, s1, 7) = -6
 

char *strtok (char *s1, const char *s2);

   تابع فوق رشته s1 را توسط s2 جدا جدا می کند . به برنامه زير توجه کنيد :

#include 
#include 
 
void main()
{
  char sentence[] ="This is a sentence with 7 tokens";
  char *tokenPtr;
 
  cout << "The string to be tokenized is:\n"<
       << "\n\nThe tokens are:\n\n";
 
  tokenPtr = strtok( sentence, " " );
 
  while ( tokenPtr != NULL ) {
    cout << tokenPtr << '\n';
    tokenPtr = strtok( NULL, " " ); // get next token 
  }
  cout <<"\nAfter strtok, sentence ="<
 
}

خروجی برنامه فوق به صورت زير می باشد :

The string to be tokenized is:
This is a sentence with 7 tokens
 
The tokens are:
 
This
is
a
sentence
with
7
tokens
 
After strtok, sentence = This

size_t strlen (const char *s);

تابع فوق طول رشته s را به عنوان خروجی بر می گرداند . به برنامه زير توجه کنيد :

#include 
#include 
 
void main()
{
char *string1 = "abcdefghijklmnopqrstuvwxyz";
char *string2 = "four";
char *string3 = "Boston";
 
cout << "The length of \"" << string1
     << "\" is " << strlen( string1 )
     << "\nThe length of \"" << string2
     << "\" is " << strlen( string2 )
     << "\nThe length of \"" << string3
     << "\" is " << strlen( string3 ) << endl;
}

خروجی برنامه فوق به صورت زير می باشد :

The length of "abcdefghijklmnopqrstuvwxyz" is 26
The length of "four" is 4
The length of "Boston" is 6

اعلان آرایه ها


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

 طول آرايه] نام آرايه   نوع داده آرايه];

   به عنوان مثال دستور زير آرايه ای به طول 6 ، با نام num را از نوع int ايجاد می کند .

int num [6];

توجه داشته باشيد که تمام عناصر دارای نام يکسانی می باشند و تنها با انديس از هم تفکيک می شوند . به عنوان مثال عنصر با انديس 2 دارای مقدار 23560- می باشد ، ضمناً انديس عناصر از 0 شروع می شود .

   استفاده از يک عبارت محاسباتی به جای انديس عناصر امکان پذير می باشد ، به عنوان مثال با فرض اينکه متغير a حاوی 2 و متغير b حاوی 3 باشد ، دستور زير:

num [a+b] + = 3;

   سه واحد به عنصر num [5] اضافه خواهد کرد و اين عنصر حاوی عدد 3 می گردد . برای چاپ مجموع سه عنصر اول آرايه می توانيد از دستور زير استفاده کنيد :

cout << num[0] + num[1] + num[2] << endl;

   برای تقسيم عنصر چهارم آرايه بر 2 و قرار دادن حاصل در متغير x از دستور زير می توانيد استفاده کنيد :

x = num[3]/2;

   نکته : توجه داشته باشيد که عنصر چهارم آرايه با عنصر شماره چهار ( با انديس چهار ) متفاوت می باشد . همانطور که در دستور فوق ديديد عنصر شماره چهار دارای انديس سه می باشد ، دليل اين امر اينست که انديس گذاری از صفر شروع می شود . در آرايه فوق عنصر چهارم آرايهnum[3]=-50 می باشد ولی عنصر شماره چهار ( با انديس چهار ) num[4]=32500 می باشد .

همانند متغيرها چند آرايه را نيز می توان توسط يک دستور تعريف کرد :

int b[100] , x[27] ;

   دستور فوق 100 خانه از نوع عدد صحيح را برای آرايه با نام b و 27 خانه از نوع عدد صحيح را برای آرايه با نام x در نظر می گيرد .

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

int n[5] = {32 , 27 , 64 , 18 , 95 }

 

   اگر طول آرايه هنگام تعريف آرايه تعيين نشده باشد و ليست مقدار عناصر نوشته شود ، همانند دستور زير :

int n[] = { 1 , 2 , 3 , 4 , 5 }

در اين صورت کامپايلر به تعداد عناصر ليست ، خانه حافظه برای آرايه در نظر می گيرد ، مثلاً در دستور فوق 5 خانه حافظه برای آرايه n در نظر گرفته می شود .

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

int num[10] = {0}

   دستور فوق 10 خانه حافظه برای آرايه num در نظر می گيرد و مقادير همه آنها را صفر می کند . توجه داشته باشيد که اگر از دستور زير استفاده کنيم :

int num[10] = {1}

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

   در تعريف آرايه ديديد که طول آرايه را با عدد صحيح ثابتی تعيين می کنيم . هر جا که از عدد ثابتی استفاده می شود ، متغير ثابت نيز می توان به کار برد . متغيرهای ثابت به صورت زير تعريف می شوند :

const   مقدار متغير = نام متغير ثابت     نوع داده متغير ;

   به عنوان مثال :

const  int  arraySize = 10;

   دستور فوق عدد 10 را به متغير arraySize ثابت انتساب می دهد . توجه داشته باشيد که مقدار يک متغير ثابت را در طول برنامه نمی توان تغيير داد و نيز متغير ثابت در هنگام تعريف شدن ، مقدار اوليه اش نيز بايد تعيين گردد . به متغيرهای ثابت ، متغيرهای فقط خواندنی نيز گفته می شود . کلمه "متغير ثابت" يک کلمه مرکب ضد و نقيض می باشد چون کلمه متغير متضاد ثابت می باشد و اين اصطلاحی است که برای اينگونه متغيرهای در اکثر زبانهای برنامه نويسی به کار می رود . برنامه زير نحوه تعريف يک متغير ثابت را نشان می دهد :

#include 
 
void main()
{
   const int x = 7; 
 
   cout << "The value of constant variable x is: "
        << x << endl;
 
}

   برنامه فوق عدد 7 را در متغير ثابت x قرار می دهد و توسط دستور cout آنرا چاپ می کند . همانطور که گفتيم مقدار متغير ثابت در هنگام تعريف بايد تعيين گردد و نيز ثابت قابل تغيير نمی باشد ، به برنامه زير توجه کنيد .

#include 
 
void main()
{
   const int x;  
 
   x=7;
}

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

 Compiling C:\TCP\BIN\CONST1.CPP:
Error : Constant variable 'x' must be initialized
Error : Cannot modify a const object

   مثال : در برنامه زير طول آرايه توسط متغير ثابتی تعيين می گردد و عناصر آرايه توسط حلقه forمقدار دهی شده و سپس توسط حلقه for ديگری ، مقدار عناصر آرايه چاپ می گردد .

#include 
 
void main()
{
   const int arraySize = 10;
 
   int s[ arraySize ];
 
   for ( int i = 0; i < arraySize; i++ )
   s[ i ] = 2 + 2 * i;
 
   cout << "Element Value" << endl;
 
   for ( int j = 0; j < arraySize; j++ )
       cout << j << "\t " << s[ j ] << endl;
 
}

   خروجی برنامه فوق به صورت زير می باشد :

Element  Value
0        2
1        4
2        6
3        8
4        10
5        12
6        14
7        16
8        18
9        20


 

چند مثال از آرایه ها


    مثال : برنامه ای بنويسيد که 10 عدد صحيح را ورودی دريافت کرده و در آرايه ای قرار داده سپس مجموع عناصر آرايه را محاسبه کرده و درخروجی چاپ نمايد .

#include 
 
void main()
{
  const int arraySize = 10;
  int total = 0,i;
  int a[ arraySize ];
 
  for (i = 0; i < arraySize; i++)
    {
     cout << "Enter number " << i << " : ";
     cin >> a[ i ];
    }
 
  for (i = 0; i < arraySize; i++ )
     total += a[ i ];
 
  cout << "Total of array element values is "
       << total << endl;
 
}

   خروجی برنامه به صورت زير می باشد :

Enter number 0 : 12
Enter number 1 : 3
Enter number 2 : 4
Enter number 3 : 654
Enter number 4 : 34
Enter number 5 : 2
Enter number 6 : 123
Enter number 7 : 794
Enter number 8 : 365
Enter number 9 : 23
Total of array element values is 2014

  مثال : برنامه ای بنويسيد که توسط آرايه ، نمودار ميله ای افقی برای اعداد {1 و17 و5 و13 و9 و11 و7 و15 و3 و19 } رسم کند .

#include 
 
int main()
{
  const int arraySize = 10;
  int n[ arraySize ] = { 19, 3, 15, 7, 11, 
                         9, 13, 5, 17, 1 };
 
  cout << "Element" << " Value" << endl;
 
  for ( int i = 0; i < arraySize; i++ ) {
     cout << i << "\t " << n[ i ] << "\t";
 
     for ( int j = 0; j < n[ i ]; j++ )
        cout << '*';
     cout << endl; 
  } 
 
return 0; 
 
} 

   خروجی برنامه به صورت زير می باشد :

 
Element  Value
0        19     *******************
1        3      ***
2        15     ***************
3        7      *******
4        11     ***********
5        9      *********
6        13     *************
7        5      *****
8        17     *****************
9        1      *

   مثال : برنامه ای بنويسيد که يک تاس را 6000 بار پرتاب کرده و توسط آرايه ای تعداد دفعات آمدن هر وجه را حساب کند .( تعداد دفعات آمدن هر وجه را يک عنصر آرايه ای در نظر بگيريد )

#include 
#include 
#include 
 
void main()
{
  const int arraySize = 7;
  int frequency[ arraySize ] = { 0 };
 
  srand( time( 0 ) ); 
 
  for ( int roll = 1; roll <= 6000; roll++ ) 
     ++frequency[ 1 + rand() % 6 ];
 
  cout << "Face Frequency" << endl;
 
  for ( int face = 1; face < arraySize; face++ ) 
     cout << face << "\t" << frequency[face] << endl;
 
}

   خروجی برنامه به صورت زير می باشد :

 
Face  Frequency
1       1023
2       990
3       1008
4       971
5       1025
6       983

   دستور ++frequency [rand()%6 + 1]; ، مقدار عنصر مربوط به هر وجه را يک واحد اضافه می کند ، زيرا rand()%6 + 1 عددی بين 1 تا 6 توليد می کند ، پس هر بار به طور تصادفی تنها مقدار عنصر مربوط به يکی از وجوه افزايش می يابد .

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

    يک عبارت رشته ای مانند: "hello" در واقع آرايه ای از حروف می باشد.

char string1[]="hello";

   دستور فوق آرايه ای به نام string1 را با کلمه hello مقدار دهی می کند. طول آرايه فوق برابر است با طول کلمه hello يعنی 5 بعلاوه يک واحد که مربوط است به کاراکتر پوچ که انتهای رشته را مشخص می کند. لذا آرايه string1 دارای طول 6 می باشد. کاراکتر پوچ در زبان ++C توسط '\0'مشخص می گردد. انتهای کليه عبارات رشته ای با اين کاراکتر مشخص می شود.

char string1[]={'h','e','l','l','o','\0'}

   دستور فوق عناصر آرايه string1 را جداگانه مقدار دهی می کند. توجه داشته باشيد که عناصر آرايه در دستور فوق داخل (') قرار گرفتند و نيز انتهای رشته با '\0' تعيين شد. نتيجه همانند دستور char string1[]="hello"; می باشد.

   چون عبارت رشته ای، آرايه ای از حروف می باشند، لذا به هر يک از حروف رشته، توسط انديس عنصری که شامل آن حرف می باشد، می توان دسترسی پيدا کرد. به عنوان مثال string1[0]شامل 'h' و string1[3] شامل 'l' و string1[5] شامل '\0' می باشد.

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

char string2[20];

   دستور فوق يک آرايه رشته ای که قابليت دريافت کلمه ای با طول 19 به همراه کاراکتر پوچ را دارا می باشد.

cin >> string2;

   دستور فوق رشته ای از حروف را از صفحه کليد خوانده و در string2 قرار می دهدو کاراکتر پوچ را به انتهای رشته وارد شده توسط کاربر اضافه می کند. به طور پيش فرض دستور cin کاراکتر ها را از صفحه کليد تا رسيدن به اولين فضای خالی در يافت می کند. به عنوان مثال اگر هنگام اجرای دستورcin >> string2; کاربر عبارت "hello there" را وارد کند، تنها کلمه hello در string2 قرار می گيرد. چون عبارت وارد شده شامل کاراکتر فاصله است. برنامه زير نحوه به کار گيری آرايه های رشته ای را نشان می دهد.

#include 
 
void main()
{
  char name[ 20 ];
 
  cout << "Please Enter your name : ";
  cin >> name;
 
  cout << "Welcome, " << name
       << " to this program. \n" ;
 
  cout << "Your separated name is\n";
 
  for ( int i = 0; name[ i ] != '\0'; i++ )
       cout << name[ i ] << ' ';
 
}

   خروجی برنامه به صورت زير می باشد :

 
Please Enter your name : Mohammad
Welcome, Mohammad to this program.
Your separated name is
M o h a m m a d

   در برنامه فوق حلقه for ، حروف نام وارد شده توسط کاربر را جدا جدا در خروجی چاپ می کند. ضمنا شرط حلقه name[ i ] != '\0' می باشد و تا وقتی اين شرط برقرار است که حلقه به انتهای رشته نرسيده باشد.

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

#include 
 
void staticArrayInit( void );
void automaticArrayInit( void );
 
int main()
{
  cout << "First call to each function:\n";
  staticArrayInit();
  automaticArrayInit();
 
  cout << "\n\nSecond call to each function:\n";
 
  staticArrayInit();
  automaticArrayInit();
  cout << endl;
 
return 0; 
 
}
 
// function to demonstrate a static local array
void staticArrayInit( void )
{
  // initializes elements to 0
  // first time function is called
  static int array1[ 3 ]={0};
 
  cout << "\nValues on entering staticArrayInit:\n";
 
  // output contents of array1
  for ( int i = 0; i < 3; i++ )
     cout << "array1[" << i << "] = " 
          << array1[ i ] << " ";
 
  cout << "\nValues on exiting staticArrayInit:\n";
 
  // modify and output contents of array1
  for ( int j = 0; j < 3; j++ )
     cout << "array1[" << j << "] = " 
          << ( array1[ j ] += 5 ) << " ";
 
} // end function staticArrayInit
 
// function to demonstrate an automatic local array
void automaticArrayInit( void )
{
  // initializes elements each time function is called
  int array2[ 3 ] = { 1, 2, 3 };
 
  cout << endl << endl;
  cout << "Values on entering automaticArrayInit:\n";
 
  // output contents of array2
  for ( int i = 0; i < 3; i++ )
     cout << "array2[" << i << "] = " 
          << array2[ i ] << " ";
 
  cout << "\nValues on exiting automaticArrayInit:\n";
 
  // modify and output contents of array2
  for ( int j = 0; j < 3; j++ )
    cout << "array2[" << j << "] = " 
         << ( array2[ j ] += 5 ) << " ";
 
}

خروجی برنامه به صورت زير می باشد :

 
First call to each function:
 
Values on entering staticArrayInit:
array1[0] = 0  array1[1] = 0  array1[2] = 0
Values on exiting staticArrayInit:
array1[0] = 5  array1[1] = 5  array1[2] = 5
 
Values on entering automaticArrayInit:
array2[0] = 1  array2[1] = 2  array2[2] = 3
Values on exiting automaticArrayInit:
array2[0] = 6  array2[1] = 7  array2[2] = 8
 
Second call to each function:
 
Values on entering staticArrayInit:
array1[0] = 5  array1[1] = 5  array1[2] = 5
Values on exiting staticArrayInit:
array1[0] = 10  array1[1] = 10  array1[2] = 10
 
Values on entering automaticArrayInit:
array2[0] = 1  array2[1] = 2  array2[2] = 3
Values on exiting automaticArrayInit:
array2[0] = 6  array2[1] = 7  array2[2] = 8

   در برنامه فوق عناصر آرايه array1 در اولين بار فراخوانی تابع staticArrayInit مقدار صفر را می گيرند ولی در دفعات بعدی فراخوانی اين تابع، آخرين مقدار قبلی خود را حفظ می کنند . اما آرايهarray2 در هر بار فراخوانی تابع automaticArrayInit مقدار دهی اوليه می شود و با خروج از تابع مقدار خود را از دست می دهد.


 

ارسال آرایه ها به توابع


    برای ارسال يک آرايه به عنوان آرگومان به يک تابع ، کافيست نام آرايه را بدون علامت براکت ([]) به کار ببريد . به عنوان مثال اگر آرايه ای با نام x به صورت زير تعريف شده باشد :

int x[24];

   برای ارسال آن به تابع modifyArray کافيست تابع را به صورت زير:

modifyArray(x,24);

   فراخوانی کنيد . دستور فوق آرايه و طول آن را به تابع modifyArray  ارسال می کند . معمولاً هنگامی که آرايه ای را به تابعی ارسال می کنند ، طول آرايه را نيز همراه آرايه به عنوان يک آرگومان جداگانه به تابع می فرستند.

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

   نکته : توجه داشته باشيد که عناصر آرايه را به صورت جداگانه همانند ارسال متغيرها و يا مقادير عددی به تابع ارسال کرد . در اين صورت تغيير بر روی آرگومان ارسالی ، تأثيری بر روی عنصر آرايه نخواهد داشت . در حقيقت اين شيوه ، همان ارسال با مقدار می باشد .

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

void modifyArray (int b[] ,int array size)

   دستور فوق مشخص می کند که تابع modifyArray قادر به دريافت آدرس آرايه ای از اعداد صحيح توسط آرگومان b و تعداد عناصر آرايه توسط آرگومان arraySize می باشد . ضمناً تعداد عناصر آرايه را لازم نيست بين براکت ها ([]) بنويسيد ، اگر اين کار نيز صورت پذيرد ، کامپايلر آن را ناديده می گيرد . توجه داشته باشيد که پيش تعريف تابع فوق را به صورت زير بنويسيد :

void modifyArray (int [] , int);

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

#include 
 
void modifyArray( int [], int );
void modifyElement( int );
 
void main()
{
  const int arraySize = 5; 
  int a[ arraySize ] = { 0, 1, 2, 3, 4 };
 
  cout<<"Effects of passing entire array by reference:"
      <<"\n\nThe values of the original array are:\n";
 
  // output original array
  for ( int i = 0; i < arraySize; i++ )
    cout << "\t"<< a[ i ];
 
  cout << endl;
 
  // pass array a to modifyArray by reference
  modifyArray( a, arraySize ); 
 
  cout << "The values of the modified array are:\n";
 
  // output modified array
  for ( int j = 0; j < arraySize; j++ )
    cout << "\t" << a[ j ];
 
  // output value of a[ 3 ]
  cout<<"\n\n\n"
      <<"Effects of passing array element by value:"
      <<"\n\nThe value of a[3] is " << a[ 3 ] << '\n';
 
  // pass array element a[ 3 ] by value
  modifyElement( a[ 3 ] );
 
  // output value of a[ 3 ]
  cout << "The value of a[3] is " << a[ 3 ] << endl;
 
}
 
// in function modifyArray, "b" points to 
// the original array "a" in memory
void modifyArray( int b[], int sizeOfArray )
{
  // multiply each array element by 2
  for ( int k = 0; k < sizeOfArray; k++ )
  b[ k ] *= 2;
}
 
// in function modifyElement, "e" is a local copy of
// array element a[ 3 ] passed from main
void modifyElement( int e )
{
  // multiply parameter by 2
  cout << "Value in modifyElement is " 
       << ( e *= 2 ) << endl;
}

   خروجی برنامه فوق به صورت زير می باشد :

Effects of passing entire array by reference:
 
The values of the original array are:
        0       1       2       3       4
The values of the modified array are:
        0       2       4       6       8
 
 
Effects of passing array element by value:
 
The value of a[3] is 6
Value in modifyElement is 12
The value of a[3] is 6

   در برنامه فوق ، تابع modifyArray مقدار عناصر آرايه a را که به آن فرستاده شده است دو برابر می کند . تابع modifyElement مقدار آرگومان دريافتی را دو برابر کرده و در خروجی چاپ می کند ولی تأثيری در نسخه اصلی عنصر آرايه نداشته و تغييری در مقدار آن ايجاد نمی کند .

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

#include 
 
void tryToModifyArray( const int [] );
 
void main()
{
  int a[] = { 10, 20, 30 };
 
  tryToModifyArray( a );
 
  cout << a[0] <<' '<< a[1] <<' '<< a[2] <<'\n';
 
}
 
// In function tryToModifyArray, "b" cannot be used
// to modify the original array "a" in main.
void tryToModifyArray( const int b[] )
{
  b[ 0 ] /= 2; // error
  b[ 1 ] /= 2; // error
  b[ 2 ] /= 2; // error
}
 
 

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

Error in line 19: Cannot modify a const object
Error in line 20: Cannot modify a const object
Error in line 21: Cannot modify a const object

 


مرتب کردن آرایه ها


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

2 , 5 , 4 , 3 , 6 , 1

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

int a[] = { 2 , 5 , 4 , 3 , 6 , 1};

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

   برنامه زير ليست اعداد ذکر شده را به شيوه مرتب کردن حبابی ، از کوچک به بزرگ مرتب می کند .

#include 
 
void showArray(const int [] , int);
 
void main()
{
  const int arraySize = 6;
  int a[ arraySize ] = { 2, 5, 4, 3, 6 ,1};
  int hold;
 
  cout << "Data items in original order\n";
 
  showArray(a,arraySize);
 
  for ( int i = 0; i < arraySize - 1 ; i++ )
     for ( int j = 0; j < arraySize - 1; j++ )
        if ( a[ j ] > a[ j + 1 ] ) {
           hold = a[ j ];
           a[ j ] = a[ j + 1 ];
           a[ j + 1 ] = hold;
         }
 
  cout << "\nData items in ascending order\n";
 
  showArray(a,arraySize);
 
}
 
void showArray( const int array[] ,int arraySize)
{
  for (int c=0; c
     cout << array[c] << " ";
     cout << endl;
}

   خروجی برنامه فوق به صورت زير می باشد :

Data items in original order
2 5 4 3 6 1
 
Data items in ascending order
1 2 3 4 5 6

   در برنامه فوق تابع showArray وظيفه نمايش عناصر آرايه را به عهده دارد . در اولين اجرای دستورات حلقه ها ، i = 0 می باشد . در اولين دور اجرای حلقه داخلی ، با شمارنده j عناصر آرايه به صورت زير با هم مقايسه می شوند .

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


 

جستجو در آرایه ها


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

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

#include 
 
int linearSearch(const int [], int, int );
 
void main()
{
   const int arraySize = 7;
   int a[ arraySize ]={2,6,4,3,12,10,5};
   int searchKey;
 
   cout << "Enter integer search key: ";
   cin >> searchKey;
 
   int element=linearSearch(a, searchKey, arraySize);
 
   if ( element != -1 )
      cout << "Found value in element " 
           << element << endl;
   else
      cout << "Value not found" << endl;
 
}
 
int linearSearch( const int array[],
                  int key, int sizeOfArray )
{
   for ( int j = 0; j < sizeOfArray; j++ )
 
   if ( array[ j ] == key )
      return j;
 
   return -1;
}

خروجی برنامه فوق به صورت زير می باشد :

Enter integer search key: 12
Found value in element 4

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

#include 
 
int binarySearch( const int [], int, int);
 
void main()
{
  const int arraySize = 15;
  int a[ arraySize ]={0,2,4,6,8,10,12,14,
                      16,18,20,22,24,26,28};
  int key;
 
  cout << "Enter a number between 0 and 28: ";
  cin >> key;
 
  int result =
      binarySearch( a, arraySize, key);
 
  if ( result != -1 )
    cout << '\n' << key << " found in array element "
         << result << endl;
  else
    cout << '\n' << key << " not found" << endl;
}
 
int binarySearch( const int b[],
                  int arraySize ,
                  int searchKey )
{
  int middle,low=0,high=arraySize - 1;
 
  while ( low <= high )
  {
    middle = ( low + high ) / 2;
    if ( searchKey < b[ middle ] )
      high = middle - 1;
    else
      if ( searchKey > b[ middle ] )
        low = middle + 1;
      else return middle;
  }
 
  return -1;
}

   خروجی برنامه فوق به صورت زير می باشد :

Enter a number between 0 and 28: 8
 
8 found in array element 4

 


آرایه های چند بعدی


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

int a[3][4];

   دستور فوق يک آرايه دو بعدی 3 در 4 را به صورت زير ايجاد می کند :

   هر عنصر آرايه به صورت a[i][j]، که در آن i شماره سطر و j شماره ستون می باشد ، قابل دسترسی است .

   برای مقدار دهی اوليه به عناصر آرايه می توانيد مانند دستور زير عمل کنيد :

int b[2][2] = {{1,2},{3,4}};

   دستور فوق آرايه b را به صورت زير مقدار دهی می کند :

1

2

3

4

   در برنامه زير چند نمونه از مقدار دهی اوليه به آرايه دو بعدی 2 در 3 آورده شده است :

#include 
 
void printArray( int [][ 3 ] );
 
void main()
{
  int array1[ 2 ][ 3 ] = { { 1, 2, 3 }, { 4, 5, 6 } };
  int array2[ 2 ][ 3 ] = { 1, 2, 3, 4, 5 };
  int array3[ 2 ][ 3 ] = { { 1, 2 }, { 4 } };
 
  cout << "Values in array1 by row are:" << endl;
  printArray( array1 );
 
  cout << "Values in array2 by row are:" << endl;
  printArray( array2 );
 
  cout << "Values in array3 by row are:" << endl;
  printArray( array3 );
 
}
 
void printArray( int a[][ 3 ] )
{
  for ( int i = 0; i < 2; i++ ) 
  {
    for ( int j = 0; j < 3; j++ )
      cout << a[ i ][ j ] << ' ';
    cout << endl;
  }
 
}

   خروجی برنامه به صورت زير می باشد :

Values in array1 by row are:
1 2 3
4 5 6
Values in array2 by row are:
1 2 3
4 5 0
Values in array3 by row are:
1 2 0
4 0 0
 

   دربرنامه فوق تابع PrintArray وظيفه چاپ عناصر آرايه را بر روی صفحه نمايش دارا می باشد . توجه داشته باشيد که ارسال آرايه به تابع به صورتint a[][3] انجام گرفت . اگر بياد داشته باشيد در آرايه های يک بعدی نيازی به ذکر طول آرايه نبود اما آرايه های بيش از يک بعد تعداد عناصر بعدهای ديگر بايد ذکر شود ، اما نيازی به ذکر طول بعد اول نمی باشد .

   مثال : در برنامه زير آرايه 2 بعدی 10 در 10 را با مقادير جدول ضرب ، مقدار دهی می کنيم و سپس آن را بر روی صفحه نمايش چاپ می کنيم .

#include 
void main( )
{
 
  int a[10][10],i,j;
 
  for (i=0;i<10;i++)
    for (j=0;j<10;j++)
      a[i][j]=(i+1)*(j+1);
 
 
  for (i=0;i<10;i++){
    for (j=0;j<10;j++)
      cout <
    cout<
  }
}
 

   خروجی برنامه فوق به صورت زير می باشد :

1   2   3   4   5   6   7   8   9   10
 
2   4   6   8   10  12  14  16  18  20
 
3   6   9   12  15  18  21  24  27  30
 
4   8   12  16  20  24  28  32  36  40
 
5   10  15  20  25  30  35  40  45  50
 
6   12  18  24  30  36  42  48  54  60
 
7   14  21  28  35  42  49  56  63  70
 
8   16  24  32  40  48  56  64  72  80
 
9   18  27  36  45  54  63  72  81  90
 
10  20  30  40  50  60  70  80  90  100


 

توابع ریاضی

   مفهوم تابع يکی از مهمترين مفاهيم در رياضيات و علوم کامپيوتر و نيز ساير علوم می باشد. تابع را می توان به عنوان دستگاهی در نظر گرفت که وروديهای مجازش را با تغييراتی که وظيفه آن دستگاه می باشد به خروجی متناظر با ورودی تبديل می کند. معادله خط y = 2x + 1  را در نظر بگيريد، اگر به جای f(x)، y را قرار دهيم معادله خط فوق به صورت f(x) = 2x + 1 در خواهد آمد. در اينجا دستگاه ما تابع f خواهد بود که هر ورودی (هر عدد حقيقی) را در 2 ضرب می کند و سپس يک واحد به آن اضافه می کند.

    به عنوان مثال :

f(0) = 2 * (0) + 1 = 1
f(1) = 2 * (0) + 1 = 3
f(-1) = 2 * (-1) + 1 = -1

   همانطور که در مثالهای فوق ديديد تابع f به هر ورودی تنها يک خروجی را نظير می کند.

   مثال : تابعی بنويسيد که شعاع يک دايره به عنوان ورودی باشد و خروجی ، مساحت دايره باشد.

می دانيم که فرمول مساحت دايره s = 3.14*r2 می باشد پس تابع را به صورت زير تعريف می کنيم:

s(r) = 3.14*r2

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

   به عنوان نمونه :

abs(1) = 1
abs(-1) = 1
abs(0) = 0

 

   زبان ++C برای انجام محاسبات رياضياتی ، توابع کاربردی فراوانی را در اختيار ما قرار داده است ، به عنوان مثال فرض کنيد که می خواهيد جذر يک عدد را بدست آوريد، تابعی که زبان ++C برای اينکار در اختيار ما قرار داده است، تابع sqrt می باشد. به عنوان مثال دستور زير :

cout << sqrt (900);

   عدد 30 را چاپ خواهد کرد. در اينجا عدد 900 آرگومان تابع sqrt می باشد. برای استفاده از توابع رياضی در برنامه ملزم به استفاده از دستور:

#include 

   در ابتدای برنامه می باشيم، چون توابع رياضی در فايل کتابخانه ای math.h قرار دارند. آرگومانهای توابع می توانند شامل اعداد ثابت، متغيرها و يا ترکيبی از آنها باشند؛ به عنوان مثال به برنامه زير توجه کنيد :

#include 
#include 
int main ( )
{
    int x = 30;
    double y = 5;
    cout << sqrt (x+2*y+9)<
    return 0;
}

   خروجی برنامه فوق عدد 7 خواهد بود چون تابع sqrt جذر عبارت 30+2*5+9=49 را محاسبه خواهد کرد.

   مثال : برنامه ای بنويسيد که sin و cos وtan زاويه های زوج 1 تا 90 درجه را در خروجی به صورت جدول بندی شده تا سه رقم اعشار چاپ نمايد.

#include 
#include 
 
int main( )
{
  float r;
  for (int d=2;d<=90;d+=2)
  {
    r = 3.1415 * d / 180;
    cout<<"sin("<
        <
    cout<<"\tcos("<
        <
    cout<<"\ttan("<
        <
    cout<
  }
  return 0;
}

   خروجی برنامه به صورت زير می باشد:

sin(2)=0.035    cos(2)=0.999    tan(2)=0.035
sin(4)=0.07     cos(4)=0.998    tan(4)=0.07
sin(6)=0.105    cos(6)=0.995    tan(6)=0.105
sin(8)=0.139    cos(8)=0.99     tan(8)=0.141
sin(10)=0.174   cos(10)=0.985   tan(10)=0.176
sin(12)=0.208   cos(12)=0.978   tan(12)=0.213
sin(14)=0.242   cos(14)=0.97    tan(14)=0.249
 
       .               .               .
       .               .               .
       .               .               .
 
sin(86)=0.998   cos(86)=0.07    tan(86)=14.292
sin(88)=0.999   cos(88)=0.035   tan(88)=28.599
sin(90)=1       cos(90)=0       tan(90)=21584.891

   در برنامه فوق توسط فرمول r = 3.1415 * d / 180 زاويه بر حسب درجه را به راديان تبديل کرديم و توسط فرمول floor(sin(r)*1000 + 0.5)/1000 خروجی را تا سه رقم اعشار محاسبه کرديم. همانطور که می بينيد ورودی تابع، علاوه بر متغير  و عدد  ثابت  خروجی  تابع  ديگری می باشد.  به  عنوان  مثال sqrt(pow(2,2)) برابر با 2 خواهد بود و ترکيب توابع به اين شکل کاملاً مجاز می باشد و بر حسب نياز می توانيد از اين شيوه استفاده کنيد. 
 

گرانبار کردن توابع (استفاده از يک نام برای چند تابع)


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

#include 
 
int square( int );
double square( double );
 
void main()
{
  // calls int version
  int intResult = square( 7 ); 
  // calls double version
  double doubleResult = square( 7.5 ); 
 
  cout << "\nThe square of integer 7 is " 
       << intResult
       << "\nThe square of double 7.5 is "
       << doubleResult 
       << endl; 
 
} // end main
 
// function square for int values
int square( int x ) 
{ 
  cout <<"Called square with int argument: "
       << x << endl;
  return x * x; 
} // end int version of function square
 
// function square for double values
double square( double y ) 
{ 
  cout <<"Called square with double argument: "
       << y << endl;
  return y * y; 
} // end double version of function square
 
 

خروجی برنامه به صورت زير می باشد .

Called square with int argument: 7
Called square with double argument: 7.5
 
The square of integer 7 is 49
The square of double 7.5 is 56.25

   برنامه فوق برای محاسبه مربع يک عدد صحيح (int) و يک عدد اعشاری (double) از تابع گرانبارشده square استفاده می کند .هنگامی که دستور:

int intResult = square (7) ;

اجرا می گردد تابع square با پيش تعريف :

int square (int) ;

فراخوانی می شود و هنگامی که دستور :

double doubleResult = square (7.5) ;

اجرا می گردد تابع square با پيش تعريف :

double square (double );

فراخوانی می شود .

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


ارسال آرگومانها با توابع و ارجاع


    تا به حال ، در تمام توابعی که نوشتيم آرگومان ها با مقدار به توابع فرستاده می شدند . اين بدان معناست که هنگامی که توابع با آرگومانها فرا خوانی می شدند ، چيزی که ما به عنوان ورودی تابع ارسال می کرديم مقدار يا عدد بود و هرگز خود متغير به تابع فرستاده نشد ، به عنوان مثال تابعmaximum در مبحث تعريف توابع را به صورت زير فراخوانی می کنيم :

int a=5, b=6, c=7, max;
max = maximum(a,b,c);

   کاری که در اينجا صورت می گيرد فراخوانی تابع و فرستادن مقادير موجود در a وb وc يعنی 5 و 6 و 7 به تابع می باشد . و خود متغيرها فرستاده نمی شوند .

   بدين صورت هنگامی که تابع maximum فراخوانی می شود ، مقدار متغيرهای x وy وz به ترتيب برابر 5 و 6 و 7خواهند شد و هرگونه تغييری روی متغيرهای x وy وz  در تابع ، تأثيری روی متغيرهای aوb وc نخواهد داشت . زيرا خود متغيرهای a وb وc به تابع فرستاده نشده اند بلکه  مقادير موجود در آنها به تابع  ارسال گشته اند .

   در برنامه نويسی مواردی پيش می آيد که بخواهيد از داخل تابع ، مقادير متغيرهای خارجی را تغيير دهيم ، به عنوان مثال در تابع maximum مقدار متغير a را از داخل تابع تغيير دهيم . برای نيل به اين هدف بايد از روش ارسال آرگومان ها با ارجاع استفاده کنيم . برای آنکه آرگومان تابعی با ارجاع فرستاده شود ، کافی است در پيش تعريف تابع بعد از تعيين نوع آرگومان يک علامت (&) بگذاريم و نيز در تعريف تابع قبل از نام آرگومان يک علامت (&) قرار دهيم . برای آشنايی با نحوه ارسال آرگومان ها با ارجاع به برنامه زير توجه کنيد .

#include 
 
void duplicate (int & , int & );
 
void main ( )
{
    int a=1 , b=2 ;
    cout << "a = " << a << " and b = " << b << endl;
    duplicate (a,b);
    cout << "a = " << a << " and b = " << b << endl;
}
 
void duplicate (int &x , int &y)
{
    x*=2;
    y*=2; 
}

خروجی برنامه به صورت زير می باشد .

a = 1 and b = 2
a = 2 and b = 4

در برنامه فوق متغيرهای a وb به تابع ارسال می گردند و سپس در دو ضرب می شوند. در اين برنامه مقدار متغيرهای a وb فرستاده نمی شود بلکه خود متغير فرستاده می شود و لذا هنگامی که دستورهای

x*=2;
y*=2;

اجرا می گردند مقادير دو متغيرa وb دو برابر می شود . در حقيقت x وy مانند نام مستعاری برای  aوb می باشند .

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

   مثال : تابعی بنويسيد که دو متغير را به عنوان ورودی دريافت کرده و مقادير آنها را جابه جا کند . از اين تابع در برنامه ای استفاده کنيد .

#include 
void change (int & , int &);
int main ( )
 {
      int a=1 , b=2 ;
      cout << "a is " << a << " and b is " << b << endl;
      change (a,b);
      cout << "a is " << a << " and b is " << b << endl;
      return 0;
  }
void change (int &x , int &y)
 {
      int temp;
      temp = y;
      y = x;
      x = temp;
 }
 

خروجی برنامه به صورت زير است :

a is 1 and b is 2
a is 2 and b is 1

برنامه فوق مقادير دو متغير a وb را توسط change با شيوه ارسال آرگومان با ارجاع جابه جا می کند .

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

#include 
 
void prevnext (int ,int & , int &);
 
void main ( )
{
    int x = 100 , y , z ;
    cout << "The input of prevnext function is "
         << x << endl;
    prevnext (x,y,z) ;
    cout << "previous =" << y <<",Next =" << z;
}
 
void prevnext (int input , int & prev , int & next)
{
    prev = input - 1 ;
    next = input + 1 ;
}

خروجی برنامه فوق به صورت زير می باشد .

The input of prevnext function is 100
previous =99,Next =101

   همانطور که مشاهده می کنيد آرگومان input مقدار داده موجود در متغير x را دريافت می کند ولی آرگومان های prev وnext خود متغيرهای y وz را دريافت می کنند . لذا تغييرات روی متغيرprevوnext  بر روی y وz انجام می گيرد و توسط تابع مقدار دهی می شوند .


عملگر یگانی تفکیک حوزه


      همانطور که در مبحث قوانين حوزه ديديد تعريف متغيرهای محلی و عمومی با يک نام در برنامه امکان پذير می باشد . زبان ++C عملگر يگانی تفکيک دامنه (::) را برای امکان دستيابی به متغير عمومی همنام با متغير محلی ، در اختيار ما قرار داده است . توجه داشته باشيد که اين عملگر تنها قادر به دستيابی به متغير عمومی در حوزه فايل می باشد . ضمناً متغير عمومی بدون نياز به اين عملگر نيز قابل دستيابی می باشد ؛ به شرط آنکه متغيرمحلی همنام با متغير عمومی ، در برنامه به کار برده نشود . استفاده از عملگر (::) همراه نام متغير عمومی ، در صورتی که نام متغير عمومی برای متغير ديگری به کار برده نشده باشد ، اختياری است . اما توصيه می شود که برای اينکه بدانيد از متغير عمومی استفاده می کنيد از اين عملگر همواره در کنار نام متغير عمومی استفاده کنيد . برنامه زير نحوه کاربرد عملگر (::) را نشان می دهد .

#include 
 
float pi=3.14159;
 
void main( )
{
     int pi=::pi;
     cout << "Local pi is : " << pi << endl;
     cout << "Global pi is : " << ::pi << endl;
}

   خروجی برنامه به صورت زير می باشد :

Local pi is : 3
Global pi is : 3.14159

   در برنامه فوق متغير عمومی pi از نوع float تعريف شده است و در تابع متغير محلی pi از نوع intبا مقدار اوليه pi عمومی مقدار دهی می شود . توجه داشته باشيد که برای دستيابی به مقدار piعمومی از عملگر يگانی تفکيک حوزه (::) استفاده شد . پس از مقدار دهی به pi محلی ، توسط دستور cout ، متغير pi محلی که حاوی عدد 3 است چاپ می گردد و در خط بعدی متغير pi عمومی که حاوی 3.14159 می باشد چاپ خواهد شد .


 

آرگومانهای پيش فرض توابع


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

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

   مقادير پيش فرض می توانند اعداد ، مقادير ثابت ، متغيرهای عمومی و يا خروجی تابع ديگر باشند .

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

#include 
 
// function prototype that specifies default arguments
int boxVolume(int length=1, int width=1, int height=1);
 
int main()
{
  //no arguments--use default values for all dimensions
  cout <<"The default box volume is: "<
 
  //specify length; default width and height
  cout <<"\n\nThe volume of a box with length 10,\n"
       <<"width 1 and height 1 is: "<
 
  //specify length and width; default height
  cout <<"\n\nThe volume of a box with length 10,\n" 
       <<"width 5 and height 1 is: "<
 
  //specify all arguments 
  cout <<"\n\nThe volume of a box with length 10,\n"
       <<"width 5 and height 2 is: "<
       <
 
  return 0; // indicates successful termination
 
} //end main
 
// function boxVolume calculates the volume of a box
int boxVolume( int length, int width, int height )
{ 
  return length * width * height;
} // end function boxVolume

   خروجی برنامه فوق به صورت زير می باشد .

The default box volume is: 1
 
The volume of a box with length 10,
width 1 and height 1 is: 10
 
The volume of a box with length 10,
width 5 and height 1 is: 50
 
The volume of a box with length 10,
width 5 and height 2 is: 100

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

int boxVolume (int = 1 , int = 1 , int = 1 );

   در اولين فراخوانی تابع boxVolume در برنامه فوق هيچ آرگومانی به آن داده نشده است لذا هر سه مقدار پيش فرض آرگومان ها مورد استفاده قرار می گيرد و حجم جعبه عدد 1 می شود . در دومين فراخوانی آرگومان length ارسال می گردد ، لذا مقادير پيش فرض آرگومان های width وheight استفاده می شوند . در سومين فراخوانی آرگومان های width و length ارسال می گردند لذا مقادير پيش فرض آرگومان height مورد استفاده قرار می گيرد . در آخرين فراخوانی هر سه آرگومان ارسال می شوند لذا از هيچ مقدار پيش فرضی استفاده نمی شود .

   پس هنگامی که يک آرگومان به تابع فرستاده می شود ، آن آرگومان به عنوان length در نظر گرفته می شود و هنگامی که دو آرگومان به تابع boxVolume فرستاده می شود تابع آنها را به ترتيب از سمت چپ به عنوان آرگومان length و سپس width در نظر می گيرد و سرانجام هنگامی که هرسه آرگومان فرستاده می شود به ترتيب از سمت چپ در length و width و height قرار می گيرند .

قوانین حوزه


    قسمتی از برنامه که در آن متغيری تعريف شده و قابل استفاده می باشد، حوزه آن متغير گفته می شود. در زبان ++C به قسمتی از برنامه که با يک علامت ( } ) شروع شده و با علامت ( { ) به پايان می رسد يک بلوک می گويند. به عنوان مثال هنگامی که متغيری را در يک بلوک تعريف می کنيم، متغير فقط در آن بلوک قابل دسترسی می باشد ولذا حوزه آن متغير بلوکی که در آن تعريف شده است ، می باشد. به مثال زير توجه کنيد :

#include 
 
void main( )
{
   {
     int x= 1;
     cout << x;
   }
   cout << x;
}

   اگر برنامه فوق را بنويسيم و بخواهيم اجرا کنيم پيغام خطای Undefined symbol 'x' را دريافت خواهيم کرد ودليل اين امر اين است که متغير x فقط در بلوک درونی تابع main تعريف شده است، لذا در خود تابع قابل دسترسی نمی باشد. در اين مبحث به بررسی حوزه تابع، حوزه فايل و حوزه بلوک می پردازيم.

   متغیری که خارج از همه توابع تعریف می شود، دارای حوزه فایل می باشد و چنین متغیری برای تمام توابع، شناخته شده وقابل استفاده می باشد. به مثال زیر توجه کنید:

#include 
 
int x=1;
int f();
 
void main( )
{
   cout << x;
   cout << f();
   cout << x;
}
int f(){
  return 2*x;
}

   متغیر x دارای حوزه فایل می باشد. لذا در تابع main و تابع f قابل استفاده می باشد. خروجی برنامه فوق به صورت زير می باشد.

121

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

static int x=1;

    دستور فوق متغیر x را از نوع عدد صحیح تعریف می کند و این متغیر با اولین فراخوانی تابع مقدار دهی می شود و در دفعات بعدی فراخوانی تابع مقدار قبلی خود را حفظ می کند. به مثال زیر توجه کنید:

#include 
 
int f();
 
void main( )
{
   cout << f();
   cout << f();
   cout << f();
}
int f(){
  static int x=0;
  x++;
  return x;
}

   خروجی برنامه فوق به صورت زیر می باشد:

123

   برنامه با اولین فراخوانی تابع f به متغیر محلی x مقدار 0 را می دهد، سپس به x یک واحد اضافه می شود و به عنوان خروجی برگردانده می شود. پس ابتدا عدد1 چاپ می گردد. در بار دوم فراخوانی تابع f ، متغیر x دوباره مقداردهی نمی شود، بلکه به مقدار قبلی آن که عدد 1 است، یک واحد اضافه گشته و به عنوان خروجی برگردانده می شود. پس این بار عدد 2 چاپ می گردد و در نهایت با فراخوانی تابع f برای بار سوم عدد 3 چاپ خواهد شد. اگر برنامه فوق را بدون کلمه static بنويسيم، خروجی 111 خواهد بود.

یکی از نکاتی که می توان در قوانین حوزه بررسی کرد، متغیرهای همنام در بلوک های تو در تو می باشد. به مثال زیر توجه کنید:

#include 
 
void main( )
{
   int x=1;
   cout << x;
   {
     int x= 2;
     cout << x;
   }
   cout << x;
}

    در برنامه فوق متغیر x یک بار در تابع main تعریف شده است و با دیگر در بلوک درونی. خروجی برنامه به صورت زیر می باشد:

121

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

   برنامه زیر تمام موارد ذکر شده در این مبحث را شامل می شود. بررسی آن و خروجی برنامه شما را در فهم بهتر این مبحث یاری می نماید.

#include 
 
void useLocal( void ); // function prototype
void useStaticLocal( void ); // function prototype
void useGlobal( void ); // function prototype
 
int x = 1; // global variable
 
void main()
{
   int x = 5; // local variable to main
 
   cout <<"local x in main's outer scope is "<
 
   { // start new scope
 
     int x = 7;
 
     cout <<"local x in main's inner scope is "<
 
   } // end new scope
 
   cout <<"local x in main's outer scope is "<
 
 useLocal(); //useLocal has local x
 useStaticLocal(); //useStaticLocal has static local x
 useGlobal(); //useGlobal uses global x
 useLocal(); //useLocal reinitializes its local x
 useStaticLocal();//static local x retains its prior value
 useGlobal(); //global x also retains its value
 
   cout << "\nlocal x in main is " << x << endl;
 
} // end main
 
//useLocal reinitializes local variable x during each call
void useLocal( void )
{
   int x = 25; //initialized each time useLocal is called
 
   cout << endl << "local x is " << x 
        << " on entering useLocal" << endl;
   ++x;
   cout << "local x is " << x 
        << " on exiting useLocal" << endl;
 
} // end function useLocal
 
// useStaticLocal initializes static local variable x 
// only the first time the function is called; value 
// of x is saved between calls to this function
void useStaticLocal( void )
{
// initialized first time useStaticLocal is called.
   static int x = 50; 
 
   cout << endl << "local static x is " << x 
        << " on entering useStaticLocal" << endl;
   ++x; 
   cout << "local static x is " << x 
        << " on exiting useStaticLocal" << endl;
 
} // end function useStaticLocal
 
// useGlobal modifies global variable x during each call
void useGlobal( void )
{
   cout << endl << "global x is " << x 
        << " on entering useGlobal" << endl;
   x *= 10;
   cout << "global x is " << x 
        << " on exiting useGlobal" << endl;
 
} // end function useGlobal

   خروجی برنامه به صورت زیر می باشد:

local x in main's outer scope is 5
local x in main's inner scope is 7
local x in main's outer scope is 5
 
local x is 25 on entering useLocal
local x is 26 on exiting useLocal
 
local static x is 50 on entering useStaticLocal
local static x is 51 on exiting useStaticLocal
 
global x is 1 on entering useGlobal
global x is 10 on exiting useGlobal
 
local x is 25 on entering useLocal
local x is 26 on exiting useLocal
 
local static x is 51 on entering useStaticLocal
local static x is 52 on exiting useStaticLocal
 
global x is 10 on entering useGlobal
global x is 100 on exiting useGlobal
 
local x in main is 5

   در برنامه فوق سه تابع با نام های useLocal ,useGlobal ,useStaticLocal داریم. متغیر x تعریف شده در ابتدای برنامه با مقدار 1 به عنوان یک متغیر عمومی می باشد و دارای حوزه فایل است. در تابع main، متغیر x  با مقدار 5 تعریف شده است. لذا متغیر عمومی x با مقدار 1 نادیده گرفته می شود و هنگام اجرای دستور cout ، متغير x با مقدار 5 در خروجی چاپ می شود. در بلوک درونی، متغیر x با مقدار 7 تعریف شده است. لذا x عمومی و x محلی تابع main نادیده گرفته می شوند و تنها x با مقدار 7 توسط دستور cout چاپ می گردد. پس از آنکه بلوک حوزه x با مقدار 7 به اتمام می رسد، دوباره x محلی تابع main با مقدار 5 نمایان می گردد.

   تابع useLocal متغیر محلی x را با مقدار 25 در خود تعریف می کند. هنگامی که این تابع در برنامه فراخوانی می شود، تابع ، متغیر x را چاپ می کند، سپس یک واحد به آن اضافه کرده و دوبارهx را چاپ می کند. هر بار که این تابع فراخوانی می شود، متغیر x با مقدار 25 در آن تعریف می شود و هنگام خروج از تابع از بین می رود.

   تابع useStaticLocal متغیرمحلی x را از نوع static تعریف کرده و با عدد 50 مقداردهی می کند و سپس آن را چاپ کرده و یک واحد به آن اضافه می کند و دوباره چاپش می کند. اما هنگام خروج از تابع مقدار x از بين نمی رود. و با فراخوانی مجدد تابع ، مقدار قبلی متغير x محلی ، برای اين تابع موجود می باشد و دوباره از نو مقداردهی نمی شود. در اينجا هنگامی که تابع دوباره فراخوانی می شود، x حاوی 51 خواهد بود.

   تابع useGlobal هيچ متغيری را در خود تعريف نمی کند. لذا هنگامی که به متغير x  مراجعه می کند ، متغيرx عمومی مورد استفاده قرار می گيرد. هنگامی که اين تابع فراخوانی می شود مقدار متغير x عمومی چاپ می شود. سپس در 10 ضرب شده و دوباره چاپ می گردد. هنگامی که برای بار دوم تابع useGlobal فراخوانی می شود x عمومی حاوی عدد 100 می باشد.

   پس از اينکه برنامه هر يک از توابع فوق را دوبار فراخوانی کرد ، مجددا متغير x تابع main با مقدار 5چاپ می گردد و اين نشان می دهد که هيچ يک از توابع ، تاثيری روی متغير محلی تابع mainنداشتند.


توابع بدون خروجی و آرگومان


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

void function (int num)
{
   cout << "My input is" << num << endl;
}

   همانطور که می بينيد اين تابع نيازی به استفاده از دستور return ندارد چون قرار نيست چيزی را به عنوان خروجی تابع برگرداند. تابع فوق بر اساس مقدار داده ورودی، پيغامی را بر روی صفحه نمايش چاپ می کند.

   حال که با void آشنا شديد می توانيم از اين به بعد تابع main را از نوع void تعريف کنيم. در اين صورت ديگر نيازی به استفاده از دستور return 0;در انتهای برنامه نداريم :

void main()
{
   دستورات برنامه
}

   به عنوان مثال برنامه برج هانوی را که در مبحث توابع بازگشتی نوشتيم با استفاده از نوع voidبازنويسی می کنيم.

#include 
 
void hanoi(int, char, char, char);
 
void main( )
{ 
   cout<<"Moving 4 disks form tower A to C."<
   hanoi(4,'A','B','C');
}
 
void hanoi(int n, char first, char help, char second) {
   if (n == 1) {
       cout << "Disk " << n << " from tower " << first
            << " to tower " << second << endl;
   } else {
       hanoi(n-1, first, second, help);
       cout << "Disk " << n << " from tower " << first
            << " to tower " << second << endl;
       hanoi(n-1, help, first, second);
   }
}

   همانطور که در برنامه فوق می بينيد تابع hanoi بدون دستور return نوشته شده است، زيرا نوع تابع void می باشد، يعنی تابع بدون خروجی است و توابع بدون خروجی را می توانيم مستقيماً همانند برنامه فوق فراخوانی کنيد. يعنی کافی است نام تابع را همراه آرگومانهای مورد نظر بنويسيم.

   برای ايجاد توابع بدون آرگومان می توانيد در پرانتز تابع کلمه void را بنويسيد يا اينکه اين پرانتز را خالی گذاشته و در آن چيزی ننويسيد.

void function1();
int  function2(void);

   در دو دستور فوق تابع function1 از نوع توابع بدون خروجی و بدون آرگومان ايجاد می شود. و تابع function2 از نوع توابع بدون آرگومان و با خروجی از نوع عدد صحيح می باشد، برای آشنايی با نحوه کاربرد توابع بدون آرگومان به برنامه زير توجه کنيد :

#include 
 
int function(void);
 
void main( )
{
   int num, counter = 0;
   float average, sum = 0;
 
   num=function();
 
   while (num != -1){
      sum += num ;
      ++counter;
      num=function();
   }
 
   if (counter != 0){
      average = sum / counter;
      cout << "The average is " << average << endl;
   }
   else
      cout << "No numbers were entered." << endl;
}
 
int function(void){
  int x;
  cout << "Enter a number (-1 to end):";
  cin >>x;
  return x;
}

   همانطور که در برنامه فوق مشاهده می کنيد تابع function از نوع توابع بدون آرگومان می باشد و دارای خروجی صحيح می باشد. اين تابع در برنامه دو بار فراخوانی شده است و وظيفه اين تابع دريافت متغيری از صفحه کليد و برگرداندن آن متغير به عنوان خروجی تابع می باشدو دستورnum=function() عدد دريافت شده از صفحه کليد را در متغير num قرار می دهد اگر به ياد داشته باشيد اين برنامه قبلاً بدون استفاده از تابع در مبحث ساختار تکرار while نوشته بوديم. برای درک بهتر اين برنامه توصيه می شود آن را با برنامه موجود در مبحث ساختار تکرار while مقايسه کنيد، و متوجه خواهيد شد که تابع function  ما را از دوباره نويسی بعضی از دستورات بی نياز کرده است و نيز برنامه خلاصه تر و مفهوم تر شده است.


نوع داده ای enum


   enum يک نوع داده ای تعريف شده توسط برنامه نويس را که به آن نوع داده شمارش می گويند، ايجاد می کند. نحوه ايجاد يک نوع داده شمارش به صورت زير می باشد.

enum {ثابت n و ... و ثابت 2 و ثابت 1} نام نوع داده

   اين دستور به ترتيب در ثابت 1 ، ثابت 2 و ... و ثابتn اعداد صحيح متوالی تا n را قرار می دهد . به صورت پيش فرض مقداردهی متغيرها در اين دستور از صفر شروع می شود.

enum TrueFalse {FALSE , TRUE}

   دستور فوق به ثابت FALSE ، عدد صفر و به ثابت TRUE عدد 1 را تخصيص می دهد. حال اگر بخواهيم مقداردهی از عددی غير از صفر شروع شود بايد عدد مورد نظر را مشخص کنيم :

enum Days {SAT = 1, SUN, MON, TUE, WED, THU, FRI}

   دستور فوق به روزهای هفته به ترتيب اعداد 1 تا 7 را نسبت می دهد. توصيه می شود که نام ثابت های شمارشی را با حروف بزرگ بنويسيد ، بدين صورت اين ثابتها با متغيرهای برنامه ، اشتباه نمی شوند. ضمناً enum را در ابتدای برنامه به کار ببريد.

   در حقيقت اين نوع داده به هر يک از موارد ليستی از اعداد نامی را نسبت می دهد. به عنوان نمونه در مثال روزهای هفته هر يک از اعداد 1 تا را با يکی از روزهای هفته نام گذاری کرديم.

مقدار دهی موارد ليست به صورت های مختلف امکان پذير می باشد.

enum Days { MON, TUE, WED, THU, FRI, SAT , SUN = 0}

   دستور فوق SUN را با عدد صفر و SAT را با عدد 1- و ... و MON را با عدد   -6 مقدار دهی می کند.

enum Colors {BLACK = 2, GREEN = 4, RED = 3,
             BLUE = 5, GRAY,WHITE = 0}

   در دستور فوق هر يک از موارد با عدد نسبت داده شده مقدار دهی می شوند و GRAY با عدد 6مقدار دهی می شود چون بعد از BLUE = 5 آمده است.

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

TrueFalse  tf1,tf2;
Days       day1, day2 = SUN;
Colors     color1 = BLACK , color2 = GRAY;

   همچنين متغيرها را می توان هنگام ايجاد نوع داده، تعريف کرد. به عنوان مثال :

TrueFalse {FALSE, TRUE} tf1 ,tf2;

   نکته : تبديل داده ای از نوع enum به عدد صحيح مجاز می باشد ولی بر عکس اين عمل غير مجاز است. به عنوان مثال :

enum MyEnum {ALPHA, BETA, GAMMA};
int   i = BETA;
int   j = 3+GAMMA;

   دستورات فوق مجاز می باشند، و اين دستورات عدد 1 را در i و 5 را در j قرار می دهند.

enum MyEnum {ALPHA, BETA, GAMMA};
MyEnum  x = 2;
MyEnum  y = 123;

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

   برنامه زير نحوه کاربرد نوع داده enum را نشان می دهد.

#include  
int main()
{
  enum PizzaSize{SMALL,MEDIUM,LARGE,EXTRALARGE};
  PizzaSize size;
  size=LARGE;
 
  cout<<"The small pizza has a value of "<
  cout<<"\nThe medium pizza has a value of "<
  cout<<"\nThe large pizza has a value of "<
 
  return 0;
}

   خروجی برنامه به صورت زير می باشد:

The small pizza has a value of 0
The medium pizza has a value of 1
The large pizza has a value of 2

 


 

تعریف بازگشتی


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

2 , 5 , 11 , 23 , ...

   جمله پنجم دنباله اعداد فوق چه عددی می باشد؟ حدس شما چيست؟ اگر کمی دقت کنيد متوجه خواهيد شد که هر جمله از دنباله فوق برابر است با دو برابر جمله قبلی بعلاوه يک. پس جمله پنجم برابر است با 2*23+1=47 دنباله فوق را توسط فرمول زير نيز می توان مشخص کرد :

d1 = 2
dn = 2*dn-1+1

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

d(1) = 2
d(n) = 2*d(n-1)+1

   همانطور  که  در  تابع فوق  می  بينيد يک  حالت پايه  وجود دارد که  همان d(1)=2 می باشد و يکه حالت بازگشتی که تابع با يک واحد کمتر دوباره فراخوانی می شود d(n) = 2*d(n-1)+1 . توابع بازگشتی به طور کلی دارای يک يا چند حالت پايه و يک بخش بازگشتی می باشند. که معمولاً در بخش بازگشتی تابع با مقداری کمتر مجدداً فراخوانی می شود. تابع بازگشتی فوق به زبان ++Cبه صورت زير می باشد :

long int d(long int n)
{
   if (n == 1) 
      return 2;
   else 
      return 2*d(n-1)+1;
}

   در زير برنامه ای می نويسيم تا با استفاده از تابع فوق 20 جمله اول دنباله مذکور را نمايش دهد.

#include 
 
long int d(long int);
int main( )
{ 
   for (int i=1;i<=20;i++)
     {
      cout<
      if (i%5==0) cout<
     }
 
   return 0;
}
 
long int d(long int n)
{
   if (n == 1) 
      return 2;
   else 
      return 2*d(n-1)+1;
}
2       5       11      23      47      
95      191     383     767     1535
3071    6143    12287   24575   49151   
98303   196607  393215  786431  1572863

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

#include 
 
int hanoi(int, char, char, char);
 
int main( )
{ int disks;
 
  cout<<"Moving disks form tower A to C."<
  cout<<"How many disks do you want to move?";
  cin>>disks;
  cout<
 
  return 0;
}
 
int hanoi(int n, char first, char help, char second) 
{
  if (n == 1) {
    cout << "Disk " << n << " from tower " << first
         << " to tower " << second << endl;
  } 
  else {
     hanoi(n-1, first, second, help);
     cout << "Disk " << n << " from tower " << first
          << " to tower " << second << endl;
     hanoi(n-1, help, first, second);
  }
  return 0;
}

   خروجی برنامه با فرض اينکه می خواهيم مراحل انتقال چهار ديسک را ببينيم به صورت زير می باشد :

Moving disks form tower A to C.
How many disks do you want to move?4
Disk 1 from tower A to tower B
Disk 2 from tower A to tower C
Disk 1 from tower B to tower C
Disk 3 from tower A to tower B
Disk 1 from tower C to tower A
Disk 2 from tower C to tower B
Disk 1 from tower A to tower B
Disk 4 from tower A to tower C
Disk 1 from tower B to tower C
Disk 2 from tower B to tower A
Disk 1 from tower C to tower A
Disk 3 from tower B to tower C
Disk 1 from tower A to tower B
Disk 2 from tower A to tower C
Disk 1 from tower B to tower C
0


 

پیش تعریف توابع

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

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

 نوع آرگومانهای تابعنام تابع    نوع داده خروجی );

   توجه داشته باشيد که پيش تعريف تابع شامل دستورات تابع نمی شود و تنها شامل نوع داده خروجی ، نام تابع و نوع آرگومانها می باشد و در پايان نياز به علامت (;) دارد. به عنوان مثال پيش تعريف تابع power2 در مبحث قبلی به صورت زير می باشد:

long int power2( int );

   ويا پيش تعريف تابع maximum به صورت زير است :

int maximum( int, int, int );

   در اينجا برنامه تابع maximum در مبحث قبلی را با روش پيش تعريف تابع باز نويسی می کنيم :

#include 
 
int maximum (int ,int,int);
 
int main ()
{
  int num1,num2,num3;
 
  cout << "Enter three numbers: ";
  cin >> num1>>num2>>num3;
  cout << "Max is :"
       << maximum(num1,num2,num3)<
  cout << "Max of 5,20,1 is "
       << maximum(5,20,1)<
 
  return 0;
}
 
int maximum (int x,int y, int z)
{
  int max=x;
 
  if (y>max)
      max=y;
  if (z>max)
      max=z;
 
  return max;
}
Enter three numbers: -5 20 150
Max is :150
Max of 5,20,1 is 20

   همانطور که در برنامه می بينيد، تابع main قبل از تابع maximum نوشته شده است و اين امکانی است که پيش تعريف تابع maximum به ما داده است.

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

تولید اعداد تصادفی

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

   برای توليد اعداد تصادفی زبان ++C تابعی با نام rand() را که در فايل کتابخانه ای stdlib.h قرار دارد، در اختيار ما گذاشته است. به عنوان مثال دستور زير :

i = rand();

   يک عدد تصادفی بين 1 تا 32767 را در متغير i قرار می دهد . تابع rand() اعداد را با احتمال مساوی در اين بازه انتخاب می کند پس شانس انتخاب هر عددی در اين بازه با اعداد ديگر برابر است.

   معمولاً بازه اعدادی که توسط تابع rand توليد می شود، با آنچه که مورد نياز ماست متفاوت می باشد. به عنوان مثال برای شبيه سازی پرتاب سکه به دو عدد تصادفی و برای تاس به شش عدد تصادفی نياز داريم. فرض کنيد که می خواهيد عدد 31250 را به عددی بين 1 تا 6 تبديل کنيد. چه راه کاری را در نظر می گيريد؟ راهی که برای اين تبديل وجود دارد استفاده از باقيمانده صحيح می باشد، همانطور که می دانيد باقيمانده صحيح تقسيم هر عددی بر 6 يکی از اعداد 0 تا 5 می باشد. پس با اضافه کردن 1 واحد به باقيمانده ، عددی بين 1 تا 6 خواهيم داشت.

   حال اگر به جای متغير a ، تابع rand() را قرار دهيم عبارت rand()%6+1 عددی تصادفی بين 1تا 6 به ما می دهد به طور کلی برای بدست آوردن عددی تصادفی در بازه [a,b] می توانيم از فرمول زير استفاده کنيم.

rand()%(b-a+1)+a

   به عنوان مثال خروجی قطعه برنامه زير عدد صحيحی در بازه [20,100] می باشد.

int a = 20 , b = 100;
cout<< rand()%(b-a+1)+a;

   برنامه زير 20 عدد تصادفی بين 1 تا 6 را ايجاد می کند. که اين برنامه را می توان 20 بار پرتاب يک تاس در  نظر گرفت :

#include 
#include 
 
int main()
{
   for (int i = 1; i<= 20; i++ )
    {
     cout << rand() % 6 + 1<<"\t";
 
     if ( i % 5 == 0 )
        cout << endl;
    }
   return 0;
}

   خروجی برنامه فوق به صورت زير می باشد :

5       5       3       5       5
2       4       2       5       5
5       3       2       2       1
5       1       4       6       4

   يک بار ديگر برنامه فوق را اجرا کنيد و خروجی را مجدداً بررسی کنيد. خواهيد ديد خروجی دقيقاً همان اعداد قبلی می باشد. خروجی تابع rand() اعداد تصادفی می باشد ولی با اجرای دوباره برنامه همان اعداد مجدداً به همان ترتيب قبلی تکرار می شوند. اين تکرار يکی از قابليتهای تابع می باشد ودر اشکال زدايی برنامه کاربرد دارد.

   اگر بخواهيم که تابع rand() اعداد کاملاً تصادفی ايجاد کند بايد از تابع srand() استفاده کنيم. اين تابع ورودی از نوع اعداد صحيح بدون علامت می گيرد و باعث تصادفی شدن تابع rand() بر اساس مقدار ورودی تابع srand() می شود. تابعsrand() نيز در فايل کتابخانه ای stdlib.h قرار دارد. در برنامه زير به نحوه استفاده از تابع srand() پی خواهيد برد.

#include 
#include 
 
int main()
{
  unsigned int num;
 
  cout<<"Enter a number: ";
  cin>>num;
 
  srand(num);
 
  for (int i = 1; i<= 20; i++ )
   {
    cout << rand() % 6 + 1<<"\t";
 
    if ( i % 5 == 0 )
      cout << endl;
   }
  return 0;
}

    خروجی برنامه به صورت زير می باشد.

Enter a number: 251
3       4       1       4       6
6       4       6       2       5
5       3       1       4       5
1       6       6       6       1
Enter a number: 350
1       4       3       4       1
2       6       2       6       2
4       2       5       3       5
4       4       5       2       3
Enter a number: 251
3       4       1       4       6
6       4       6       2       5
5       3       1       4       5
1       6       6       6       1

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

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

srand(time(0));

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

#include 
#include 
#include 
 
int main()
{
  srand(time(0));
 
  for (int i = 1; i<= 20; i++ )
   {
    cout << rand() % 6 + 1<<"\t";
    
    if ( i % 5 == 0 )
      cout << endl;
   }
  return 0;
}

   مثال : برنامه ای بنويسيد که پرتاب سکه ای را شبيه سازی کند ، بدين صورت که سکه را 2000بار پرتاب کند و دفعات رو يا پشت آمدن سکه را چاپ کند.

#include 
#include 
#include 
 
int main()
{
  int back=0,front=0,face;
 
  srand(time(0));
 
  for (int i = 1; i<= 2000; i++ )
    {
      face=rand()%2+1;
      switch(face)
        {
          case 1:
            ++back;
            break;
          case 2:
            ++front;
            break;
          default:
            cout<<"Error!";
        }
    }
 
  cout<<"Front: "<< front<
  cout<<"Back : "<< back<
 
  return 0;
}

دانلود حل تمرین ریاضی عمومی 1 مهمیانی احمدپور

برای دانلود می توانید از لینک زیر استفاده کنید.

DOWNLOAD