[ بستن ]

سیستم وبلاگ پارسی باکسسیستم مدیریت فروش هاست و دامینسایت شخصی محسن داوری برنامه نویس PHPهماهنگی با موتورهای جستجو , رنکینگ گوگل , google pagerank , page rank , seo , search

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

بخش ها

نویسندگان

آرشیو

آمار
بازدید امروز : 85
بازدید دیروز : 106 ‍
بازدید این ماه : 191
بازدید امسال : 17863
بازدید کل : 28927
تعداد پست ها : 89
تعداد لینک های لینکستان : 26
تعداد نظر سنجی های وبلاگ : 2

 
سخن روز


اشاره گر ها / قسمت 7

جمع اشاره‌گرها (آدرسها و مقادیر)

دو راه برای مراجعه به آدرس یک عنصر از آرایه وجود دارد . یکی بصورت nums+k در فرم اشاره‌گر و دیگری بصورت nums[k] در فرم آرایه .

حال اجازه دهید با ارائه یک برنامه ساده ، رابطه بین عناصر آرایه و آدرس آنها را بررسی و ملاحظه نماییم .

 

مثال -  برنامه زیر را درنظر بگیرید :

# include <stdio.h>

main ( )

 {

  static int x[6] = {10 , 11 , 12 , 13 , 14 , 15};

  int  i ;

  for ( i=0 ; i<6 ; + +i )

     printf("\n i =%d  x[i] = %d   *(x+i) = %d  &x[i] = %x  x+i =%x", i , x[i] , *(x+i) , &x[i] , x+i) ;

}

(فرض بر این است که آدرس شروع آرایه ، 72 در مبنای 16 است) .

خروجی برنامه

i = 0

x[i] = 10

*(x+i) = 10

&x[i] = 72

x+i = 72

i = 1

x[i] = 11

*(x+i) = 11

&x[i] = 74

x+i = 74

i = 2

x[i] = 12

*(x+i) = 12

&x[i] = 76

x+i = 76

i = 3

x[i] = 13

*(x+i) = 13

&x[i] = 78

x+i = 78

i = 4

x[i] = 14

*(x+i) = 14

&x[i] = 7a

x+i = 7a

i = 5

x[i] = 15

*(x+i) = 15

&x[i] = 7c

x+i = 7c

 

از خروجی بالا فرق بین x[i] که معرف i اُمین عنصر آرایه است ، با &x[i] که آدرس آن را نمایش می‌دهد ، مشخص می‌گردد . در ضمن مشاهده می‌شود که مقدار i اُمین عنصر آرایه را می‌توان با :

x[i]

و یا :

*( x + i )

معرفی نمود . در ضمن می‌توان تفاوت بین :

x + i   و   *( x + i )

را ملاحظه کرد که اولی معرف آدرس و دومی نشان ‌دهندة محتوای آن آدرس است . همچنین نتیجه گرفته می‌شود که اگر x[i] در سمت چپ یک دستور جایگذاری باشد ، می‌توان به جای آن :

*( x + i )

را بکار برد . اصولاً همه جا می‌توانیم به جای x[i] هم‌ارز آن *(x+i) را بکار ببریم . به هرحال عباراتی مشابه :

x   و   x + i  و  &x[i]

که معرف آدرس هستند ، نمی‌توانند در سمت چپ دستور جایگذاری بکار برده شوند . همچنین آدرس یک آرایه نمی‌تواند بطور دلخواه تغییر یابد . بنابراین عبارتی مشابه ++x مجاز نمی‌باشد .

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

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

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

مثال - اگر بخواهیم a را بصورت یک آرایه 10 عنصری از مقادیر صحیح تعریف کنیم ، می‌توان آن را به جای :

int  a[10] ;

بصورت :

int  *a ;

نوشت . یعنی a را بعنوان متغیر اشاره‌گر تعریف کرد .

به هرحال در روش دوم ، به a بعنوان آرایه 10 عنصری یک بلوک حافظه اختصاص داده نمی‌شود ، بلکه a بصورت یک متغیر اشاره‌گر تعریف شده است .

برای اختصاص حافظه مورد نیاز به a جهت معرفی یک آرایة 10 عنصری ، می‌توان از تابع malloc بصورت زیر استفاده نمود :

a = malloc (10 * sizeof(int)) ;

این تابع یک بلوک حافظه برای ذخیره‌ کردن 10 مقادیر صحیح رزرو می‌کند . در دستور بالا ، اپراتور sizeof بزرگی نوع داده int را برحسب بایت برمی‌گرداند . این مقدار در 10 (تعداد عناصر آرایه) ضرب می‌شود تا فضای مورد نیاز برحسب بایت تعیین و رزرو شود . a ، بصورت اشاره‌گر به مقدار صحیح تعریف شده است و تابع malloc یک اشاره‌گر به کاراکتر برمی‌گرداند و می‌دانیم که در زبان C مقادیر صحیح و کاراکترها ، معادل هستند . لذا دستور بالا قابل قبول است . اگرچه از لحاظ اطمینان کامل می‌توان از تبدیل نوع cast استفاده کرد و آن را بصورت زیر بکار برد :

a = (int *) malloc (10 * sizeof (int)) ;

این گونه اختصاص حافظه به روش اختصاص حافظه بصورت پویا موسوم است .

به هرحال اگر قرار باشد به عناصر آرایه ، مقدار اولیه نیز اختصاص یابد ، باید a  بجای متغیر اشاره‌گر بصورت آرایه توصیف گردد  مشابه زیر :

int  a[10] = {1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10} ;

یا :

int  [ ] = {1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10}

در برنامه‌نویسی با C ، ممکن است برای مراجعه به عناصر آرایه بجای روش معمول ، عباراتی برحسب اشاره‌گرها بکار ببریم . این روش در آغاز کار کمی غیرطبیعی به ‌نظر می‌آید ، ولی می‌توان با کمی تمرین ، به سادگی تجربه لازم را در این مورد بدست آورد . در مثال زیر ضمن اینکه روش استفاده از تابع malloc  نشان داده می‌شود ، به عناصر آرایه نیز با استفاده از این تکنیک دستیابی می‌گردد .

مثال -  مرتب کردن یک مجموعه اعداد (Sort  ) .

برنامه مورد نظر در زیر نشان داده شده است :

# include <stdio.h>

main ( )

 {

   int  k , m , *a ;

   void  sort (int k , int  *a) ;

   scanf ("%d" , &m) ;      /* read in a value for m */

   a = (int*) malloc (m * sizeof(int)) ;   /* allocate memory */

   for (k = 0 ; k<m ; + +k)   /* read in the list of numbers */

      scanf ("%d" , a + k) ;

   sort (m , a) ;

   for (k=0 ; k<m ; + +k)    /* display sorted list , elements */

      printf ("\n k=%d  a =%d" , k+1 , *(a+k)) ;

  }

void  sort (int m , int *a)    /* sort array in ascending order */

 {

   int  i , j , temp ;

   for ( i=1 ; i<m ; + +i )

      for ( j=0 ; j<m-i ; + +j )

          if (*(a+j) < *(a+j+1))

           {

             temp = *(a+j) ;

                   *(a+j) = *(a+j+1) ;

                   *(a+j+1) = temp;

           }

    return ;

  }

در این برنامه ، آرایه‌ای با عناصری از نوع مقادیر صحیح ، بصورت یک اشاره‌گر به یک مقدار صحیح تعریف شده است . در آغاز به کمک تابع کتابخانه‌ای malloc به متغیر اشاره‌گر ، حافظه ، اختصاص داده شده است . (یعنی حافظه مورد نیاز از سیستم گرفته شده و آدرس اولین بایت آن در a قرار داده شده است) . در هر دو تابع اصلی و فرعی برای پردازش هر عنصر از روش مراجعه به اشاره‌گر ، استفاده شده است . ملاحظه می‌کنیم که در تابع scanf نیز برای آدرس عنصر k اُم بجای :

&a[k]

 از :

a + k

 استفاده شده است . به طریق مشابه ، در تابع printf برای معرفی مقدار k اُمین عنصر ، بجای :

a[k]

از :

*(a + k)

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

اشاره‌گرها و آرایه‌های چند بعدی

      دیدیم که عناصر یک آرایة یک‌ بعدی می‌تواند برحسب یک اشاره‌گر (نام آرایه) و یک مقدار بعنوان آفست  به ‌منظور جبران کردن مقدار اندیس عنصر مورد نظر آرایه ، نمایش داده شود . مثلاً اگر نام آرایه ، a و عنصر مورد نظر ما :

a[5]

باشد ، می‌توان به آن بصورت :

*(a + 5)

 مراجعه کرد که در آن مقدار آفست همان 5 است که به نام آرایه افزوده شده است و به کمک اپراتور  *  به مقدار آن دسترسی پیدا می‌کنیم .

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

data-type    array[d1][d2] ;

(که در آن منظور از d1 ، d2 به‌ترتیب بزرگی ابعاد اول و دوم آرایه است) بصورت زیر نوشت :

data-type   (*ptvar)[d2] ;

این ایده را می‌توان به‌ آرایه‌های n بعدی تعمیم داد و آن را به جای :

data-type   array [d1][d2]...[dn] ;

بصورت زیر نوشت :

data-type   (*ptvar)[d2][d3]...[dn] ;

که در آنها ، data-type ، نوع عناصر آرایه و array نیز نام آرایه است . و عناصر :

d1 , d2 , ..., dn

 نیز به ترتیب ماکزیمم عناصر هر اندیس یا هر بعد آرایه می‌باشند . درضمن توجه کنید که ptvar نیز نام متغیر اشاره‌گر است .

 

  • انتقال آرایه به تابع ( بعنوان آرگومان )

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

main ( )

 {

   float  func( ) ;

   float  x , array[15] ;

   .......

   .......

   x = func(array) ;    /* same as func (&array [0]) */

   .......

   .......

 }

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

 

راه دوم

 

راه اول

func(ar)

float  ar[ ] ;

    {

      .......

      .......

    }

 

 

func(ar)

float  *ar ;

    {

      .......

      .......

    }

 

 

راه دوم ، ar را به‌عنوان آرایه‌ای با اندازه (یا بزرگی) نامشخص ، توصیف می‌کند . آرایه هم‌اکنون در تابع اصلی ایجاد شده است ، آنچه گذر داده می‌شود ، یک اشاره‌گر به اولین عنصر از آرایه است . چون کامپایلر می‌داند که عبارت آرایه منتج به اشاره‌گر به اولین عنصر آرایه می‌گردد ، پس ar را مشابه توصیف ar در روش اول ، به یک اشاره‌گر از نوع float تبدیل می‌کند . بنابراین هر دو گونه ازنظر نحوة عملکرد ، معادل و هم‌ارز یکدیگر می‌باشند .

به هرحال ازنظر واضح‌تر بودن ، ممکن است روش دوم ترجیح داده شود . زیرا این روش تأکید می‌کند که آنچه که باید گذر داده شود آدرس پایه یا آدرس اولین عنصر یک آرایه است . در روش اول ، راهی برای تشخیص اینکه آیا ar به آغاز یک آرایه از نوع float و یا تنها به یک عنصر از نوع float اشاره می‌کند یا نه ، وجود ندارد .

  • مقایسه اشاره‌گرها

      دو اشاره‌گر را می‌توان در یک عبارت رابطه‌ای با یکدیگر مقایسه کرد . برای مثال اگر q و p دو اشاره‌گر باشند ، دستور زیر یک دستور درست می‌باشد :

if  (p<q)

   printf ("p  points to lower memory than  q") ;

else

     printf ("q  points to lower memory than  p") ;

 

  • آرایه‌هایی از اشاره‌گرها

     در زبان  C میتوان آرایه‌ای از اشاره‌گرها تعریف کرد. یعنی آرایه‌ای که عناصر آن اشاره‌گر باشند . دستور زیر آرایه‌ای 10 عنصری از اشاره‌گرها را توصیف می‌کند :

int  *x[10] ;

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

*x[2] = &z ;

همینطور برای بدست آوردن مقدار z از دستور  **x[2]  استفاده می کنیم .

آرایه‌ای از اشاره‌گرها را نیز می‌توان مشابه آرایه‌های معمولی به یک تابع انتقال داد . یعنی به سادگی ، نام آرایه را بدون اندیس یا زیرنویس آن بعنوان آرگومان تابع قرار می‌دهیم . برای مثال تابع display می‌تواند آرایه‌ x را بصورت زیر دریافت نماید :

void  display (int  *a[ ] )

 {

    int  k ;

    for ( k=0 ; k<10 ; k+ +)

       printf (" %p" , *a[k] ) ;

 }

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

      آرایه‌های اشاره‌گر اغلب برای نگهداری اشاره‌گرهایی به رشته‌ها بکار برده می‌شوند .

 

ادامه دارد ....


نوشته شده توسط محمد حسن بهجت | نظرات [0] | لینک به این مطلب |


 
تابلوی گفتمان



نظرسنجی

پیوندها

لوگو هـــا

خبرنامه ها





خبرنامه ویژه





خبرنامه عمومی


لوگو دوستان

پیوندهای روزانه

 
Copy Right 2007 ParsiBox.com ( Designed By ParsiBox Master Design )