تماس درباره   صفحه اصلی
  زبان ++C > ساختمان و نوع شمارشی  
 
 

ساختمان و نوع شمارشی


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

ساختمان
typedef
يونيون
شمارشی
فيلدهای بيتی


انواع متغیرهائی که تاکنون استفاده شدند (مانند int، float، char، ...) نوع های پيش ساخته (built-in) هستند که تنها یک مقدار تکی را در خود نگه می دارد. می توان متغيرهائی در برنامه تعريف کرد که از نوع های داده کامل تری هستند و اجازه می دهند چند مقدار مرتبط بهم تحت یک نام ذخیره شوند. چون برنامه نويس اين نوع داده ها را به عنوان نوع داده جدیدی در برنامه ايجاد می کند user-defined ناميده می شوند و شامل انواع زير هستند:

• ساختمان
• Typedef
• یونیون
• شمارشی
• فيلذهای بيتی


ساختمان

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

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

struct structurename
{
   vartype varname;
   vartype varname;
} variable ;

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


مثال. تعريف نوع ساختمان کارمند به نام employee با اجزای lastname، firstname و salary.

struct employee {
   char lastname[30];
   char firstname[30];
   float salary;
};


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

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


مثال. اعلان متغير ساختمان MyEmployee از نوع employee بلافاصله بعد از تعريف ساختمان.

struct employee {
   char lastname[30];
   char firstname[30];
   float salary;
}MyEmployee;

مثال. اعلان متغير ساختمان SecondEmployee از نوع ساختمان موجود employee.

struct employee SecondEmployee;


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

دسترسی به اجزای ساختمان

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


مثال. مقداردهی جزء salary از متغير ساختمان MyEmployee.

MyEmployee.salary=4000.44;


يکی از مزايای ساختمان نسبت به متغيرهای مجزا کپی داده های يک متغير ساختمان در متغير ديگر از همان نوع توسط يک عبارت انتساب است.


مثال. دستور زير کليه اجزای ساختمان MyEmployee را در ساختمان SecondEmployee کپی می کند.

SecondEmployee = MyEmployee;


مقداردهی اوليه ساختمان

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


مثال. مقداردهی اوليه ساختمان کارمند.

struct employee {
   char lastname[30];
   char firstname[30];
   float salary;
}MyEmployee ={ "Adams", "Amy", 1000.00};

Employee Structure

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


مثال. برنامه زير برای ذخيره اطلاعات تلفن افراد است. آرايه list از نوع ساختمان entry است.

#include <iostream.h>
struct entry { // Define a structure to hold entries.
   char fname[20];
   char lname[20];
   char phone[10];
};
struct entry list[4]; // Declare an array of structures.
main(){
   for (int i = 0; i < 4; i++) {
      cout << "\nEnter first name: ";
      cin >> list[i].fname;
      cout << "Enter last name: ";
      cin >> list[i].lname;
      cout << "Enter phone in 123-4567 format: ";
      cin >> list[i].phone;
      }
   cout << "\n\n";
   for (int i = 0; i < 4; i++){
      cout << "Name:" << list[i].fname << list[i].lname;
      cout << "\t\tPhone: " << list[i].phone;
      }
   return 0;
}


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


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

#include <iostream.h>
struct coord {
   int x; int y;
};
struct rectangle {
   struct coord topleft;
   struct coord bottomrt;
} mybox;
main() {
   int length, width;
   long area;
   cout << "\nEnter the top left x coordinate: ";
   cin >> mybox.topleft.x;
   cout << "\nEnter the top left y coordinate: ";
   cin >> mybox.topleft.y;
   cout << "\nEnter the bottom right x coordinate: ";
   cin >> mybox.bottomrt.x;
   cout << "\nEnter the bottom right y coordinate: ";
   cin >> mybox.bottomrt.y;
   width = mybox.bottomrt.x - mybox.topleft.x;
   length = mybox.bottomrt.y - mybox.topleft.y;
   area = width * length;
   cout << "\nThe area is " << area << " units.\n";
   return 0;
}


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


مثال. برنامه ای برای محاسبه سينوس، کسينوس و تانژانت زاويه. پارامتر و نوع برگشتی تابع compute هردو از نوع ساختمان هستند.

#include <cmath.h>
#include <iostream.h>
struct geometry_data {
   float radius;
   double angle;
}; struct geometry_answers {
   float area;
   double sine;
   double cosine;
   double tangent;
};
geometry_answers compute(struct geometry_data mystruct);
int main () {
   geometry_data input;
   geometry_answers output;
   cout << "Enter the radius of the circle \n";
   cin >> input.radius;
   cout << "Enter the angle in rads \n";
   cin >> input.angle;
   output = compute(input);
   cout << " \nThe area is " << output.area << "\n";
   cout << " \nThe sine of the angle is " << output.sine << "\n" ;
   cout << " \nThe cosine of the angle is " << output.cosine << "\n";
   cout << " \nThe tangent of the angle is " << output.tangent << "\n";
   return 0;
}
geometry_answers compute(struct geometry_data mystruct) {
   geometry_answers answer;
   answer.area = 3.14f * pow(mystruct.radius,2);
   answer.sine = sin(mystruct.angle);
   answer.cosine = cos(mystruct.angle);
   answer.tangent = tan(mystruct.angle);
   return answer;
};


typedef

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

typedef datatype label;

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

typedef می تواند با هر نوع داده ای بکار رود حتی نوع های پایه مثل int. البته توصیه می شود با نوع های پيچيده مانند آرایه یا ساختمان استفاده شود.


مثال. تغيير نام int به Integer.

typedef int Integer;
int i,j;
Integer min;

مثال. اعلان a و b از نوع آرايه صحيح.

typedef int MyArray[10];
MyArray a,b;

مثال. اعلان متغيرهای topleft و bottomright از نوع ساختمان. دقت کنيد با استفاده از typedef کلمه struct قبل از اسم متغير ديگر لازم نيست ذکر شود.

typedef struct {
   int x;
   int y;
} Coord;
Coord topleft, bottomright;


برنامه ارسال ساختمان به تابع


يونيون

يک يونيون (union) مجموعه ای از چند متغير است که تحت يک نام گروه بندی می شوند و از يک فضای حافظه بطور مشترک استفاده می کنند. يک يونيون مشابه ساختمان تعريف و استفاده می شود فقط به جای کلمه struct کلمه کليدی union نوشته می شود.

union tag
{
   union_member(s);
} instance;

کلمه کليدی union برای اعلان يونيون است. tag نامی است که به يونيون داده می شود. اجزای يونيون درون آکولاد قرار می گيرند. instance يک متغير يونيون است که می تواند درون برنامه هم با فرمت زير اعلان شود.

union tag instance;

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


مثال.

union NumericType {
   int ivalue;
   long lvalue;
   double dvalue;
}

مثال. تنها اولين جزء متغير يونيون هنگام اعلان می تواند مقداردهی اوليه شود.

union date_tag {
   char full_date[9];
   struct part_date_tag {
      char month[2];
      char break_value1;
      char day[2];
      char break_value2;
      char year[2];
   } part_date;
}date = {"01/01/97"};


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


برنامه کاربرد يونيون


شمارشی

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

enum typename { enumeration list };

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


مثال.

enum colors {red, blue, green};
enum colors c;
c= red;
cout << c;


فيلدهای بيتی

به طور نرمال در هر زبان برنامه نویسی هر متغیری از نوع های شناخته شده است و تعداد بایت های معینی می گیرد. ++C یک نوع دیگر ارائه می دهد که در اکثر زبان های دیگر موجود نیست. فیلدهای بیتی (bit fields) اجازه دسترسی به بیت های تکی را می دهد.

یک فیلد بیتی در یک ساختمان عادی به صورت یک جزء unsigned به همراه علامت (:) و یک عدد که نشاندهنده تعداد بیت های فيلد است تعريف می شود.


مثال. متغير linestatus يک بايت فضا اشغال می کند.

#include <iostream.h>
struct status {
   unsigned changeinline: 1;
   unsigned cleartosend:1;
   unsigned inactive:1;
   unsigned ringing:1;
   unsigned signalreceived:1;
};
int main() {
   status linestatus;
   if (linestatus.cleartosend) senddata();
   if (linestatus.inactive) dialnumber();
   if(linestatus.ringing) answerphone();
   return 0;
}


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


 


 


صفحه اصلی| PDF| درباره| تماس