خوش آموز درخت تو گر بار دانش بگیرد، به زیر آوری چرخ نیلوفری را


آموزش زبان ++C : نوع داده Char

آموزش زبان ++C : نوع داده Char
نویسنده : امیر انصاری
با وجود اینکه نوع داده Char یک نوع integer می باشد و بنابراین از تمامی قوانین integer ها نیز پیروی می کنید، اما ما معمولاً با نوع داده Char به شکل متفاوتی از integer ها کار می کنیم. یک نوع داده Char می تواند 1 بایت مقدار integer را در خودش نگهداری کند. با این حال، به جای اینکه مقدار موجود در یک داده از نوع char به صورت integer تفسیر گردد، معمولاً مقدار آن به عنوان یک کاراکتر اسکی (ASCII character) تفسیر می گردد.

سیستم یکپارچۀ سازمانی راهکار



کلمه ASCII در واقع سرنام کلمات American Standard Code for Information Interchange می باشد و یک روش خاص برای ارائه کاراکترهای انگلیسی بعلاوه چندین نماد دیگر در قالب اعداد بین 0 تا 127 می باشد. هر کدام از این اعداد یک کد اسکی (ASCII code) و یا code point نامیده می شوند. به عنوان مثال کد اسکی کاراکتر ‘a’ عدد 97 می باشد. کد اسکی کاراکتر ‘b’ عدد 98 می باشد. در این روش کاراکترها را همواره بین یک جفت تک کوتیشن (single quotes) قرار می دهند.

در تصویر زیر، جدول کامل کاراکترهای اسکی (ASCII characters) را مشاهده می کنید :

آموزش زبان ++C : نوع داده Char
کدهای 0 تا 31 کاراکترهای غیر قابل چاپ (unprintable chars) نامیده می شوند، از این کدها معمولاً برای قالب بندی (formatting) و کنترل پرینترها استفاده می گردد. البته اکثر اینها امروزه منسوخ شده اند.

کدهای 32 تا 127 کاراکترهای قابل چاپ (printable characters) نامیده می شوند، و حروف، اعداد و نشان گذاری ها در این کدها ارائه می شود، اکثر کامپیوترها برای نمایش متن های ساده انگلیسی از این کدها استفاده می کنند.

در هر دو مقدار دهی اولیه (initialization) که در مثال زیر مشاهده می کنید متغیر از نوع char ما با مقدار integer که 97 می باشد، مقدار دهی می گردد :

char ch1(97); // initialize with integer 97
char ch2('a'); // initialize with code point for 'a' (97)

در مورد یک نکته مهم احتیاط کنید و آن اینکه، مراقب باشید کاراکترهای عددی را با اعداد واقعی قاطی نکنید. دو مقدار دهی اولیه زیر، یکسان نمی باشند :

char ch(5); // initialize with integer 5
char ch('5'); // initialize with code point for '5' (53)

چاپ کردن مقادیر char


هنگامی که با استفاده از تابع cout مقدار یک متغیر از نوع char را چاپ می کنید، تابع cout کاراکتر معادل آن مقدار char را از طریق معادل یابی در کدهای اسکی (ASCII) چاپ می کند و عدد معادل آن را چاپ نخواهد کرد :

#include "iostream"

int main()
{
char ch(97); // even though we're initializing ch with an integer
std::cout << ch; // cout prints a character
return 0;
}

خروجی این برنامه :

a

ما همچنین می توانیم مقادیر کاراکترهای char را مستقیماً به صورت لیترال مقدار دهی و چاپ کنیم :

cout << 'b';

خروجی این برنامه :

b

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

چاپ کردن char ها به صورت integer از طریق تبدیل نوع داده آنها (type casting)


اگر بخواهیم تا معادل عددی یک کاراکتر اسکی به جای کاراکتر آن چاپ گردد، باید به تابع cout بگوییم تا نوع داده char را به صورت integer چاپ کند. یک روش ضعیف برای انجام این کار اینست که نوع داده char را به یک نوع داده integer انتساب بدهیم و سپس آن integer را چاپ کنیم :

#include "iostream"

int main()
{
char ch(97);
int i(ch); // assign the value of ch to an integer
std::cout << i; // print the integer value
return 0;
}

با این حال این روش دلپذیر است. یک روش بهتر اینست که از تبدیل نوع داده (type cast) استفاده کنیم. با استفاده از تبدیل نوع داده (type cast) می توانیم یک مقدار را از یک نوع داده به نوع داده دیگری تبدیل کنیم. برای تبدیل یک نوع داده (به عنوان مثال از char یه integer و یا برعکس آن) از یک نوع تبدیل نوع داده (type cast) استفاده می کنیم که به آن static cast گفته می شود.

نحوه نگارش (syntax) در روش static cast کمی خنده دار به نظر می رسد :

static_cast<new_type>(expression)

static_cast مقدار یک عبارت (expression) را به عنوان ورودی دریافت می کند، و آن را به نوع داده ای که در قسمت new_type ارائه می شود، تبدیل می کند. شما می توانید در قسمت new_type از انواع داده اصلی مانند int، boolean ، char، double و ... استفاده کنید.

در مثال زیر با روش static cast یک مقدار char را به یک مقدار integer تبدیل کرده ایم :

#include "iostream"

int main()
{
char ch(97);
std::cout << ch << std::endl;
std::cout << static_cast<int>(ch) << std::endl;
std::cout << ch << std::endl;
return 0;
}

خروجی برنامه :

a
97
a

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

همچنین توجه داشته باشید که طی عملیات static cast هیچ نوع کنترلی روی محدوده مجاز مقادیر متغیرها (range checking) صورت نمی پذیرد، به عنوان مثال اگر یک integer را به یک char تبدیل کنید و مقدار آن integer بزرگتر از مقداری باشد که می تواند در نوع داده char قرار بگیرد، شما با خطای سرریز (overflow) مواجه خواهید شد.

در مورد static cast و انواع مختلف تبدیل ها (casts) در درس های آینده بیشتر صحبت خواهیم کرد.

دریافت مقادیر char به عنوان ورودی (Inputting chars)


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

#include "iostream"

int main()
{
std::cout << "Input a keyboard character: ";

char ch;
std::cin >> ch;
std::cout << ch << " has ASCII code " << static_cast(ch) << std::endl;

return 0;
}

خروجی این برنامه در یکبار اجرای آن به شکل زیر می باشد :

Input a keyboard character: q
q has ASCII code 113

توجه داشته باشید که با وجود اینکه تابع cin می تواند چندین کاراکتر را بخواند، اما متغیر ch تنها می تواند 1 کاراکتر را در خودش نگهدارد. در نتیجه، تنها اولین کاراکتر وارد شده در متغیر ch قرار می گیرد. بقیه ورودی های کاربر در بافر مورد استفاده توسط cin قرار می گیرد و با فراخوانی مجدد cin می تواند آنها را بخواند.

شما می توانید این رفتار را در مثال زیر مشاهده کنید :

#include "iostream"

int main()
{
std::cout << "Input a keyboard character: "; // assume the user enters "abcd" (without quotes)

char ch;
std::cin >> ch; // ch = 'a', "bcd" is left queued.
std::cout << ch << " has ASCII code " << static_cast(ch) << std::endl;

// Note: The following cin doesn't ask the user for input, it grabs queued input!
std::cin >> ch; // ch = 'b', "cd" is left queued.
std::cout << ch << " has ASCII code " << static_cast(ch) << std::endl;

return 0;
}

خروجی این برنامه در یکبار اجرای آن به شکل زیر می باشد :

Input a keyboard character: abcd
a has ASCII code 97
b has ASCII code 98

اندازه، محدوده و علامت نوع داده char


نوع داده Char توسط زبان برنامه نویسی ++C معرفی شده است تا همیشه 1 بایت اطلاعات را بتواند در خودش نگهداری کند. به صورت پیش فرض نوع داده Char می تواند با علامت (signed) و یا بدون علامت (unsigned) باشد، که البته معمولاً دارای علامت (signed) می باشد. اگر از نوع داده Char برای نگهداشتن کاراکترهای اسکی (ASCII characters) استفاده می کنید، شما نیازی به تعیین علامت برای آن ندارید، چرا که هم نوع دارای علامت و هم نوع بدون علامت می توانند مقادیر 0 تا 127 را در خود نگهداری کنند.

اگر از نوع داده Char برای نگهداری مقادیر integer استفاده می کنید، شما همیشه باید تعیین کنید که آن متغیر دارای علامت (signed) یا بدون علامت (unsigned) می باشد. یک متغیر دارای علامت (signed) از نوع char می تواند مقادیر عددی بین 128- تا 127 را در خود نگهدارد. یک متغیر بدون علامت (unsigned) از نوع char می تواند مقادیر عددی بین 0 و 255 را در خودش نگهداری کند.

کاراکترهای از نوع Escape sequences


در زبان برنامه نویسی ++C چندین کاراکتر وجود دارند که معنای خاصی دارند. به این کاراکترهای خاص Escape sequences گفته می شود. کاراکترهای از نوع Escape sequences با یک بک اسلش (\) آغاز می شوند، و سپس با یک کاراکتر یا با یک عدد ادامه پیدا می کنند.

رایج ترین کاراکتر از نوع Escape sequences کاراکتر (n\) می باشد که برای اضافه کردن یک خط جدید (newline) در یک متن (string) به کار می رود.

#include "iostream"

int main()
{
std::cout << "First line\nSecond line" << std::endl;
return 0;
}

خروجی این برنامه به شکل زیر خواهد بود :

First line
Second line

یکی دیگر از کاراکترهای رایج Escape sequences کاراکتر (t\) می باشد که یک تب (TAB) را در متن قرار می دهد :

#include "iostream"

int main()
{
std::cout << "First part\tSecond part";
return 0;
}

خروجی این برنامه به شکل زیر می باشد :

First part        Second part

سه کاراکتر Escape sequences قابل توجه دیگر در ادامه آمده اند :

\’ prints a single quote
\” prints a double quote
\\ prints a backslash

در تصویر زیر جدولی از کاراکترهای Escape sequences آمده است :

آموزش زبان ++C : نوع داده Char
در ادامه چند مثال آمده است :

#include "iostream"

int main()
{
std::cout << "\"This is quoted text\"\n";
std::cout << "This string contains a single backslash \\" << std::endl;
std::cout << "6F in hex is char \'\x6F\'" << std::endl;
return 0;
}

خروجی :

"This is quoted text"
This string contains a single backslash \
6F in hex is char 'o'

مقایسه کاراکتر خاص n\ با تابع std::endl برای ایجاد خط جدید. کدام یک را باید استفاده کنیم؟


شما ممکن است در مثال آخر ما متوجه شده باشید که ما می توانستیم از کاراکتر n\ برای انتقال کرسر به خط بعدی استفاده کنیم، که به نظر می رسد عملکرد تابع std::endl را تکرار می کند. با این حال این دو کمی متفاوت هستند.

هنگامی که از تابع std::cout برای چاپ خروجی استفاده می کنیم، خروجی ما بافر می گردد، و تابع std::cout خروجی را بلافاصله به نمایشگر ارسال نمی کند. در عوض، این تابع خروجی ها را قبل از چاپ، مدت زمانی جمع آوری کرده و نگهداری می کند. این مساله به دلایل بالا بردن کارآیی (performance reasons) به این شکل انجام می شود، چرا که نوشتن یک بخش زیادی از داده ها سریعتر از نوشتن آنها به صورت خرد خرد انجام می شود.

هم کاراکتر n\ و تابع std::endl کرسر را به ابتدای خط بعدی می برند. بعلاوه std::endl اطمینان حاصل می کند که کلیه خروجی هایی که در صف ارسال به نمایشگر قرار دارند، قبل از این دستور به خروجی ارسال شده اند.

بنابراین چه وقتی باید از n\ و یا std::endl استفاده کنیم؟ پاسخ کوتاه اینست :

  • از std::endl زمانی استفاده کنید که می خواهید مطمئن شوید که خروجی برنامه شما فوراً نمایش داده شود (مانند زمانی که می خواهید رکوردی را در یک فایل ذخیره کنید، یا هنگامی که می خواهید وضعیت یک نوار پیشرفت (progress bar) را بروز رسانی کنید). توجه داشته باشید که استفاده از این روش می تواند کارآیی (performance) را کاهش دهد و موجب کندی عملیات شود، مخصوصاً اگر بخواهید خروجی را بر روی یک فایل در یک دیسک بنویسید.

  • از n\ در سایر موارد استفاده کنید.

تفاوت قرار دادن نمادها بین یک جفت تک کوتیشن و بین یک جفت گیومه در چیست؟


همانطور که در این درس یاد گرفتید، مقادیر مربوط به نوع داده Char را همیشه باید بین یک جفت تک کوتیشن قرار بدهید (برای مثال 'a' یا '+' و یا '5'). یک متغیر از نوع داده char تنها می تواند یک نماد را در خودش قرار بدهد (به عنوان مثال حرف a یا علامت + و یا عدد 5). چیزی شبیه مثال زیر غیر قانونی می باشد :

char ch('56'); // a char can only hold one symbol

متن هایی که بین یک جفت گیومه قرار می گیرند رشته (string) نامیده می شوند (برای مثال "Hello, World" یک string می باشد). یک رشته (string) یک توالی از کاراکترها می باشد و بنابراین یک رشته (string) می تواند چندین نماد (symbol) را در خودش نگهداری کند.

در حال حاضر شما می توانید لیترال های (literals) رشته ای را در کدتان استفاده کنید :

std::cout << "Hello, world!"; // "Hello, world!" is a string literal

با این حال، متغیرهای از نوع string کمی پیچیده تر از متغیرهای از نوع داده Char می باشند، بنابراین بحث در مورد رشته ها (strings) را به آینده موکول خواهیم کرد.

در مورد سایر انواع داده های char مانند wchar_t ، char16_t و char32_t چطور؟


از نوع داده wchar_t باید در همه موارد اجتناب کنید (مگر در هنگام ارتباط برقرار کردن با واسط های برنامه نویسی ویندوز (Windows API) که در این مورد خاص کاربرد دارند). اندازه نوع داده wchar_t بر اساس پیاده سازی ویندوز معرفی می شود و قابل اعتماد نمی باشد. نوع داده wchar_t تا حد زیادی از بین رفته است.

همانند کدهای اسکی که در مورد حروف انگلیسی در جدول اسکی و در کدهای بین 0 تا 127 مشاهده کردید، در زبان های دیگر نیز چنین کدینگ هایی برای کاراکترها وجود دارد. یکی از شناخته شده ترین رمزگذاری های اینچنینی استاندارد یونیکد (Unicode standard) می باشد، در استاندارد یونیکد (Unicode standard) بیش از 110 هزار integer به کاراکترها در زبانهای مختلف نسبت داده شده است. از آنجا که استاندارد یونیکد (Unicode standard) دارای کدهای بسیار زیادی می باشد، یک کد در این استاندارد نیاز به 32 بیت برای ارائه دارد (برای همین UTF-32 نامیده می شود). همینطور کاراکترهای یونیکد به صورت 16 بیتی و 8 بینی نیز ارائه شده اند که بترتیب UTF-16 و UTF-8 نامیده می شوند.

نوع داده char16_t و همینطور نوع داده char32_t در C++11 ارائه شده اند تا از کاراکترهای یونیکد 16 بیتی و 32 بیتی پشتیبانی کنند. ذکر این نکته لازم است که کاراکترهای یونیکد 8 بیتی هم اکنون در نوع داده char معمولی، پشتیبانی می شوند.

شما معمولاً نیازی به استفاده از نوع داده char16_t یا char32_t ندارید، مگر اینکه بخواهید برنامه تان با یونیکد سازگار باشد. از آنجا که موضوع یونیکد و بحث ساخت برنامه ها به صورت محلی (localization) خارج از محدوده این دوره آموزشی می باشد، بیشتر از این در آنها عمیق نخواهیم شد.

در حال حاضر و در طول این دوره آموزشی صرفاً از کاراکترهای اسکی استفاده خواهیم کرد. در صورت استفاده از کاراکترهایی خارج از محدوده کاراکترهای اسکی، ممکن است برنامه ها بدرستی کار نکنند.


آموزش قبلی : آموزش زبان ++C : مقادیر بولی و مقدمه ای بر بیانیه if

آموزش بعدی : آموزش زبان ++C : لیترال ها (Literals)



نمایش دیدگاه ها (3 دیدگاه)

دیدگاه خود را ثبت کنید:

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