• توجه: در صورتی که از کاربران قدیمی ایران انجمن هستید و امکان ورود به سایت را ندارید، میتوانید با آیدی altin_admin@ در تلگرام تماس حاصل نمایید.

++ C

!MAHSA!

کاربر ويژه
توابع بدون خروجی و آرگومان

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


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

void function (int num)
{
cout << "My input is" << num << endl;
}
همانطور که می بينيد اين تابع نيازی به استفاده از دستور return ندارد چون قرار نيست چيزی را به عنوان خروجی تابع برگرداند. تابع فوق بر اساس مقدار داده ورودی، پيغامی را بر روی صفحه نمايش چاپ می کند.

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

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

#include <iostream.h>

void hanoi(int, char, char, char);

void main( )
{
cout<<"Moving 4 disks form tower A to C."<<endl;
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 <iostream.h>

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 ما را از دوباره نويسی بعضی از دستورات بی نياز کرده است و نيز برنامه خلاصه تر و مفهوم تر شده است.
 

!MAHSA!

کاربر ويژه
قوانین حوزه

قوانین حوزه


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

#include <iostream.h>

void main( )
{
{
int x= 1;
cout << x;
}
cout << x;
}
اگر برنامه فوق را بنويسيم و بخواهيم اجرا کنيم پيغام خطای Undefined symbol 'x' را دريافت خواهيم کرد ودليل اين امر اين است که متغير x فقط در بلوک درونی تابع main تعريف شده است، لذا در خود تابع قابل دسترسی نمی باشد. در اين مبحث به بررسی حوزه تابع، حوزه فايل و حوزه بلوک می پردازيم.

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

#include <iostream.h>

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 <iostream.h>

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 <iostream.h>

void main( )
{
int x=1;
cout << x;
{
int x= 2;
cout << x;
}
cout << x;
}
در برنامه فوق متغیر x یک بار در تابع main تعریف شده است و با دیگر در بلوک درونی. خروجی برنامه به صورت زیر می باشد:

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

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

#include <iostream.h>

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 "<<x<<endl;

{ // start new scope

int x = 7;

cout <<"local x in main's inner scope is "<<x<<endl;

} // end new scope

cout <<"local x in main's outer scope is "<<x<< endl;

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 نداشتند.
 

!MAHSA!

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

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


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

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

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

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

#include <iostream.h>

// 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: "<<boxVolume();

//specify length; default width and height
cout <<"\n\nThe volume of a box with length 10,\n"
<<"width 1 and height 1 is: "<<boxVolume(10);

//specify length and width; default height
cout <<"\n\nThe volume of a box with length 10,\n"
<<"width 5 and height 1 is: "<<boxVolume(10,5);

//specify all arguments
cout <<"\n\nThe volume of a box with length 10,\n"
<<"width 5 and height 2 is: "<<boxVolume(10,5,2)
<<endl;

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 قرار می گيرند .
 

!MAHSA!

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

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


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

#include <iostream.h>

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 می باشد چاپ خواهد شد .
 

!MAHSA!

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

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


تا به حال ، در تمام توابعی که نوشتيم آرگومان ها با مقدار به توابع فرستاده می شدند . اين بدان معناست که هنگامی که توابع با آرگومانها فرا خوانی می شدند ، چيزی که ما به عنوان ورودی تابع ارسال می کرديم مقدار يا عدد بود و هرگز خود متغير به تابع فرستاده نشد ، به عنوان مثال تابع 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 <iostream.h>

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 <iostream.h>
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 <iostream.h>

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 انجام می گيرد و توسط تابع مقدار دهی می شوند .
 

!MAHSA!

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

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


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

#include <iostream.h>

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 );
فراخوانی می شود .

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

!MAHSA!

کاربر ويژه
اعلان آرایه ها

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

طول آرايه] نام آرايه نوع داده آرايه];
به عنوان مثال دستور زير آرايه ای به طول 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 <iostream.h>

void main()
{
const int x = 7;

cout << "The value of constant variable x is: "
<< x << endl;

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

#include <iostream.h>

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 <iostream.h>

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
 

!MAHSA!

کاربر ويژه
چند مثال از آرایه ها

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


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

#include <iostream.h>

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 <iostream.h>

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 <iostream.h>
#include <stdlib.h>
#include <time.h>

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 <iostream.h>

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 <iostream.h>

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 مقدار دهی اوليه می شود و با خروج از تابع مقدار خود را از دست می دهد.
 

!MAHSA!

کاربر ويژه
ارسال آرایه ها به توابع

برای ارسال يک آرايه به عنوان آرگومان به يک تابع ، کافيست نام آرايه را بدون علامت براکت ([]) به کار ببريد . به عنوان مثال اگر آرايه ای با نام 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 <iostream.h>

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 <iostream.h>

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
 

!MAHSA!

کاربر ويژه
مرتب کردن آرایه ها

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


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

2 , 5 , 4 , 3 , 6 , 1

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

int a[] = { 2 , 5 , 4 , 3 , 6 , 1};
حال کافی است آرايه a را به صورت صعودی مرتب کنيم . برای انجام اين کار از روشی به نام مرتب کردن حبابی استفاده می کنيم . اين تکنيک به دليل اينکه مقادير کوچکتر همانند حبابی در آب به سمت بالا حرکت می کنند ، مرتب کردن حبابی گفته می شود . برای مرتب کردن آرايه چندين بار بايد روی آرايه حرکت کنيم و در هر بار حرکت عناصر دو به دو با هم مقايسه می شوند ، و در صورتی که به صورت نزولی قرار داشته باشند مقاديرشان جابه جا می گردد و در غير اين صورت به همان ترتيب باقی می مانند .

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

#include <iostream.h>

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<arraySize ;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 می گردد و دفعات بعدی مقايسه انجام گرفته و در انتهای هر بار مقايسه ترتيب عناصر به صورت زير می شود . که سرانجام با به انتها رسيدن حرکت روی آرايه عناصر به صورت صعودی مرتب می شوند
 

!MAHSA!

کاربر ويژه
جستجو در آرایه ها

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


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

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

#include <iostream.h>

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 <iostream.h>

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
 

!MAHSA!

کاربر ويژه
آرایه های چند بعدی

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


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

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


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

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

int b[2][2] = {{1,2},{3,4}};
دستور فوق آرايه b را به صورت زير مقدار دهی می کند :

1
2

3
4


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

#include <iostream.h>

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 <iostream.h>
void main( )
{

int a[10][10],i,j;

for (i=0;i<10;i++)
for (j=0;j<10;j++)
a[j]=(i+1)*(j+1);


for (i=0;i<10;i++){
for (j=0;j<10;j++)
cout <<a[j]<<"\t";
cout<<endl;
}
}

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

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
 

!MAHSA!

کاربر ويژه
تعریف اشاره گر ها

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


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


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


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

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

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

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

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

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

!MAHSA!

کاربر ويژه
عملگرهای اشاره گر ها

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


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

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


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

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

#include <iostream.h>

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 تغيير می يابد .
 

!MAHSA!

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

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


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

#include <iostream.h>

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

!MAHSA!

کاربر ويژه
اعمال محاسباتی با اشاره گرها

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


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

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

فرض کنيد که آرايه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 می گردد . محاسبات اشاره گرها تنها هنگامی که اشاره گرها به خانه های يک آرايه اشاره می کنند ، معنا دار هستند . همچنين مقايسه اشاره گرها نيز هنگامی مفهوم دارد که به خانه های يک آرايه اشاره کنند به عنوان مثال مقايسه دو اشاره گر می تواند نشان دهد که يکی از اشاره گرها به خانه ای با انديس بزرگتر نسبت به اشاره گر ديگر ، اشاره می کند .
 

!MAHSA!

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

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


آرايه ها و اشاره گرها در زبان ++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 <iostream.h>

void main()
{
int b[] = { 10, 20, 30, 40 };
int *bPtr = b;
int i;

cout << "b:\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:\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:
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:
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
 

!MAHSA!

کاربر ويژه
آرايه ای از اشاره گرها

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


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

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


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

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

!MAHSA!

کاربر ويژه
اشاره گربه تابع

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


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

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

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

#include <iostream.h>

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 <iostream.h>

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 به عنوان آرگومان به تابع ارسال میشود.
 

!MAHSA!

کاربر ويژه
پردازش رشته ها

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


در اين مبحث تعدادی از توابع پردازش رشته را که در فايل کتابخانه ای 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 <iostream.h>
#include <string.h>

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 <iostream.h>
#include <string.h>

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 <iostream.h>
#include <string.h>

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 <iostream.h>
#include <string.h>

void main()
{
char sentence[] ="This is a sentence with 7 tokens";
char *tokenPtr;

cout << "The string to be tokenized is:\n"<<sentence
<< "\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 ="<<sentence<<endl;

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

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 <iostream.h>
#include <string.h>

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
 
بالا