یکی از انواع دادههای اسکالر نوع شمارشی است. بعضی زبانهای دیگر مانند زبان پاسکال نیز این نوع دادهها را در میان انواع دادههای استاندارد پشتیبانی میکنند. دادهای از نوع شمارشی، مشابه ساختار یا اجتماع است و اعضای آن ثابتهاییاند که به عنوان شناسه نوشته میشوند، اگرچه مقدار یا ارزش آنها از نوع مقدار صحیح علامتدار است. این ثابتها مقادیری را معرفی میکنند که میتوان به متغیرهای شمارشی متناظر با آنها نسبت داد.
در حالت کلی نوع شمارشی به صورت زیر تعریف میشود.
enum tag {member 1 , member 2 , … , member m} ;
که در آن enum کلمهای کلیدی است و tag نیز اسمی است که داده شمارشی را مشخص میکند و دارای این ترکیب است و عناصر member 1 , member 2 , … , member m نیز شناسههایی را مشخص میکنند که ممکن است به متغیرهایی از نوع tag نسبت داده شود. اسامی اعضا باید متفاوت و متمایز از یکدیگر باشند.
وقتی که نوع شمارشی تعریف شد، میتوان متغیرهای شمارشی متناظر با آن را به صورت زیر اعلان کرد.
storage_class enum tag variable1 , variable 2 , … , variable n ;
که در آن storage_class گزینه اختیاری است و کلاس حافظه را مشخص میکند. enum نیز کلمهای کلیدی است که باید به کار برده شود. tag اسمی است که در تعریف نوع شمارشی ظاهر میگردد و بالاخره variable1 , variable 2 , … , variable n متغیرهای شمارشی از نوع tag اند.
تعریف شمارشی را میتوان با اعلان متغیرها ترکیب کرد و به صورت زیر به کار برد.
storage_class enum tag {member 1 , member 2 , … , member m}variable 1 , variable 2 , … , variable n ;
در این حالت، انتخاب نام برای مراجعه به آن اختیاری است و میتوان آن را به کار نبرد. صورت بالا را میتوان به اختصار چنین نوشت.
enum enum_type_name {enumeration list} variable_list ;
که در صورت مزبور به کار بردن نام نوع شمارشی، یعنی enum_type_name، اختیاری است. نام نوع شمارشی برای اعلان متغیرهایی از آن نوع است.
مثال قطعه برنامه زیر نوع شمارشیای به نام coin تعریف و نوع متغیر money را از این نوع اعلان میکند.
enum coin {penny , nickel , dime , quarter , half_dollar , dollar} ;
enum coin money ;
با داشتن این تعریف و اعلان، دستورهای زیر کاملاً درست و معتبر است.
money = dime ;
if (money = = quarter) prinf (“is a quarter”) ;
نکته مهمی که در اینجا باید در مورد نوع شمارشی توجه داشت آن است که هر سمبول معرف یک مقدار صحیح است و در هر عبارت از نوع مقادیر صحیح به کار میرود. برای مثال عبارت
printf (“the number of nickels in a quarter is %d” , quarter + 2) ;
کاملاً صحیح و معتبر است.
مقدار اولین سمبول شمارشی برابر صفر، مقدار دومین سمبول شمارشی برابر ۱، و بالاخره مقدار n اُمین سمبول شمارشی برابرn – ۱ است، مگر اینکه به طریق دیگری مقداردهی اولیه شده باشند. بنابراین عبارت printf (“%d %d” , penny , dime) ; مقادیر ۰ ۲ را در صفحه تصویر نمایش خواهد داد.
همچنین میتوان به هریک از سمبولها مقدار اولیه نسبت داد. برای این کار باید پس از سمبول مورد نظر علامت `=’ و سپس مقدار صحیح مطلوب را به کار ببریم. وقتی که به یکی از سمبولها به طریق مزبور مقدار اولیه نسبت داده شد، سمبول بعدی مقدار بعدی را خواهد داشت؛ یعنی یک واحد از آن بزرگتر خواهد بود. برای مثال دستور زیر مقدار ۱۰۰ را به quarter نسبت میدهد.
enum coin {penny , nickel , dime , quarter = 100 , half_dollar , dollar} ;
و اکنون مقادیر سمبولها به صورت زیر خواهند بود.
penny ۰
nickel ۱
dime ۲
quarter ۱۰۰
half_dollar ۱۰۱
dollar ۱۰۲
به طور متعارف این طور فرض میشود که سمبولهای یک نوع شمارشی میتوانند به طور مستقیم ورودی یا خروجی باشند. ولی این طور نیست. برای مثال قطعه برنامه زیر آنچه را انتظار داریم انجام نمیدهد.
money = dollar ;
printf (“%d” , money) ;
به خاطر داشته باشید سمبول dollar بهطور ساده مقدار رشته نیست، بلکه اسمی برای مقدار صحیح است. بنابراین تابع printf نمیتواند رشته “dollar” را نمایش دهد. به طریق مشابه نمیتوانید با به کار بردن رشته همارز، به متغیر شمارشی مقدار نسبت بدهید. برای مثال دستور زیر درست کار نمیکند.
money = “penny” ;
به هرحال به طریق دیگری میتوان مقدار رشتهای سمبولهای مورد نظر را ایجاد کرد.
مثال قطعه برنامه زیر نوع سکههایی را که متغیر money شامل است نمایش خواهد داد.
switch money {
case penny: printf (“penny”) ;
break ;
case nickel: printf (“nickel”) ;
break ;
case dime: printf (“dime”) ;
break ;
case quarter: printf (“quarter”) ;
break ;
case half_dollar: printf (“half_dollar”) ;
break ;
case dollar: printf (“dollar”) ;
}
همچنین ممکن است آرایهای از رشتهها تعریف کرد و مقدار متغیر شمارشی را شاخص یا index آن آرایه به کار برد تا مقدار شمارشی را به رشته متناظر آن ترجمه کند.
مثال قطعه برنامه زیر رشته مورد نظر را به عنوان خروجی تولید خواهد کرد.
char name[ ] = {
“penny” ,
“nickel” ,
“dime” ,
“quarter” ,
“half_dollar” ,
“dollar”
} ;
printf (“%c” , name [(int) money]) ;
البته این روش در صورتی درست کار میکند که به هیچ یک از سمبولها مقدار اولیه نسبت داده نشده باشد، زیرا شاخص آرایه رشتهها همیشه از صفر شروع میشود.
مثال فرض کنید که برنامه C شامل دستورهای زیر باشد.
enum colors { black , blue , cyan , green , magenta , red , white , yellow} ;
colors foreground , background ;
در سطر اول، نوع شمارشی به نام colors تعریف شده که شامل هشت ثابت است و اسامی آنها عبارتاند از black , blue , cyan , green , magenta , red , white , yellow. در سطر دوم متغیرهای foreground و background به عنوان شمارشی، از نوع colors اعلان شدهاند. بنابراین به هریک از این متغیرها میتوان هر یک از هشت ثابت black , blue , cyan ,… , yellow را نسبت داد.
میتوان دو دستور بالا را با یکدیگر ترکیب کرد و به صورت زیر نوشت.
enum colors {black , blue , cyan , green , magenta , red , white , yellow}foreground , background ;
در این مثال مقادیر صحیح هشت ثابت بالا به صورت زیر خواهد بود.
black ۰
blue ۱
cyan ۲
green ۳
magenta ۴
red ۵
white ۶
yellow ۷
به هرحال به طوری که گفتیم، اگر به برخی از ثابتها مقدار اولیه نسبت داده شود، مقادیر مزبور تغییر خواهد یافت. برای مثال اگر نوع شمارشی مزبور را به صورت
enum colors {black= -1 , blue , cyan , green , magenta , red = 2 , white , yellow} ;
تعریف کنیم، هشت ثابت مورد نظر مقادیر زیر را خواهند داشت.
black -۱
blue ۰
cyan ۱
green ۲
magenta ۳
red ۲
white ۳
yellow ۴
متغیرهای شمارشی نمیتوانند به طور کامل مشابه متغیرهای از نوع مقدار صحیح مورد پردازش قرار گیرند. مثلاً نمیتوان به آنها مقدار جدید نسبت داد یا آنها را مقایسه کرد. همین طور نمیتوان آنها را به عنوان ورودی به درون کامپیوتر خواند و به متغیر شمارشی دیگر نسبت داد. اما میتوان مقدار صحیح را از ورودی دریافت کرد و آن را به متغیر شمارشی نسبت داد. گرچه این شیوه متداول نیست. همچنین فقط میتوان مقدار صحیح متغیر شمارشی را به عنوان خروجی کامپیوتر نوشت.
حال دوباره دو دستور مذکور در آغاز این مثال را درنظر بگیرید. با درنظر گرفتن دو دستور مزبور میتوان دستورهای زیر را به عنوان نمونههایی از عملیات روی متغیرهای شمارشی به کار برد.
foreground = white ;
background = blue ;
if (background = = blue)
foreground = yellow ;
else
foreground = white ;
if (foreground = = background)
foreground = (enum colors) (+ + background % 8) ;
switch (background)
{
case black: foreground = white ;
break ;
case blue:
case cyan:
case green:
case magenta:
case red: foreground = yellow ;
break ;
case white: foreground = black ;
break ;
case yellow: foreground = blue ;
break ;
case default: printf (“Error in selection of background color “) ;
}