PDA

View Full Version : چجوری یک متن رو رنگی بنویسم؟!



Cru3l.b0y
دوشنبه 06 خرداد 1387, 22:39 عصر
سلام دوستان

میخواستم بدونم چجوری میتونم یک متن رو با دستور Cout در توربو سی پلاس پلاس رنگی بنویسم؟


با دستور setcolor و textcolor که نشد!

A.S.Roma
سه شنبه 07 خرداد 1387, 08:58 صبح
با سلام

یه راحش اینه که تو کلاست عملگر >> رو Overload کنی و با textcolor رنگ کاراکتر رو عوض کنی و با putch رو صفحه بگذاریش .

یه راه دیگرش هم اینه که با استفاده از Pointer مستقیما رو LCD بنویسی و تنظیماتشو عوش کنی که یکم سخت تر از اولیه .

احتمالا راه دیگر و البته ساده تری نیز وجود دارد که اساتید می فرمایند.

emad_67
سه شنبه 07 خرداد 1387, 10:34 صبح
اینجوری بنویس:


#include <stdlib.h>
#include<iostream.h>
void main()
{
system("color 3");
cout<<"c++";
}

توی system باید شماره رنگ رو بدی که در اینجا من 3 دادم.

amir_civil
سه شنبه 07 خرداد 1387, 12:06 عصر
اینجوری بنویس:

کد:
#include <stdlib.h>
#include<iostream.h>
void main()
{
system("color 3");
cout<<"c++";
}
با سلام
این کار باعث میشه تمام خط ها به یه رنگ در بیاد اگر بخاهیم هر خط یک رنگ داشته باشه باید چیکار کرد؟

emad_67
سه شنبه 07 خرداد 1387, 18:39 عصر
با سلام
این کار باعث میشه تمام خط ها به یه رنگ در بیاد اگر بخاهیم هر خط یک رنگ داشته باشه باید چیکار کرد؟برای اینکه چند بار رنگ رو عوض کنید تو یه سایت دیدم این جوری نوشته بود:

#include <windows.h>
#include <iostream.h>

void main()
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HA NDLE), 9); //replace the 0 with a number for the color you want
cout << "Your text here" << endl;

SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HA NDLE), 5);
cout << "Your text here" << endl;
}و برای ساده شدن استفاده یه تابع میشه تعریف کرد:


#include<windows.h>
#include<iostream.h>
enum Colors { blue=1, green, cyan, red, purple, yellow, grey, dgrey, hblue, hgreen, hred, hpurple, hyellow, hwhite };
void coutc(int color, char* output)
{
HANDLE handle= GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute( handle, color);
cout<< output<<flush;
}

void main()
{
coutc(red, "This is in red!");
coutc(purple, "This is purple!");
}

bsng110
شنبه 02 شهریور 1387, 22:15 عصر
هوالحکیم.
سلام.
جسارتاً شما دوستان محیط برنامه نویسی را در نظر نگرفتید! حق با دوست عزیزمان emad_67 است و در محیط هایی مانند Visual Studio می توان از این تابع کمک گرفت ولی در TC چی؟ آخه emad_67 جان می دونند که من هنوز این کامپایلر محبوب را رها نکردم پس در اونجا چی؟ من قبلاً یک نیم صفحه ای در این مورد برای دوستانم نوشته بودم. گفته شاید بد نباشه این جا هم اون مطالب را بگذارم. فقط باید ببخشید چونکه من این متن را خیلی وقت پیش نوشته ام و مخاطبان آن هم علمایی چون شما دوستان نبودند ولی خوب، گفتم شاید بودن این مطالب در اینجا، برای تازه کارانی چون خودم بد نباشد!
به نقل از http://enghelper.com/forum/viewtopic.php?t=33&start=24:

باسمه تعالی
- رنگی نمودن صفحه نمایش :

می خواستم طبق قولی که داده بودم، جریان ها را توضیح دهم اما دیدم که هنوز رنگی کردن صفحه نمایش را توضیح نداده ام، همچنین خیلی وقت است که قول نوشتن آن را داده ام اما این عمل را انجام ندادم بنابراین در این قسمت توابع مفیدی از فایل سرآمد conio.h را توضیح می دهم که از جمله آنها، توابع مربوط به رنگی نمودن صفحه نمایش می باشد . در این قسمت به دلیل اینکه نمی دانستم مخاطبم در چه سطح علمی قرار دارد، سعی کرده ام موضوعات جزئی را نیز بیان کنم اما چنانچه شما با بعضی مفاهیم آشنا می باشید، می توانید آن قسمت ها را نخوانید . امیدوارم که به بنده خرده نگیرید .
در ضمن باید متذکر شوم که بنده مطالب این قسمت را تکه تکه تایپ کرده ام بنابراین شاید در بعضی از جاها گسستگی مشاهده کنید یعنی احساس کنید که یه لحظه لحن بیان عوض شده است . به هر حال شرمنده ام . چنانچه پیشنهادی داشتید و یا مشکلی در متن یافتید، بنده را مطلع کنید .
دقت کنید که تمام امکاناتی که در این قسمت بیان می شود مربوط به حالت متن ( Text Mode ) می باشد و در حالت گرافیکی توابع دیگری برای اعمال مختلف حتی خواندن از ورودی و نوشتن در خروجی وجود دارد . فایل سرآمد این قسمت conio.h می باشد . دقت کنید، همانطور که گفته شد توابع این قسمت مربوط به پایگاه داس ( DOS Platform ) می باشند بنابراین اگر برنامه شما به وسیله فورم های ویندوز طراحی شده است، نمی توانید از این توابع استفاده کنید . توابع این قسمت توسط کامپایلر های TC++ 3.0 و Borland C++ 5.0 پشتیبانی می شوند . دقت کنید که در کامپایلر Borland C++ 5.0 باید پروژه شما برای پایگاه داس طراحی شده باشد که این امر را می توانید در قسمت پایین سمت چپ پنجره " New Target " (مربوط به ساخت یک پروژه که قبلاً توضیح داده شده است) انجام دهید . در این فایل توابع بسیاری وجود دارد که بنده آنها را به صورت زیر دسته بندی کرده و برای شما توضیح خواهم داد . دقت کنید که این توابع برای همدیگر ساخته شده اند و با دیگر توابع زبان هماهنگی ندارند مثلاً چنانچه شما رنگ متن و زمینه را تغییر دادید، اما متن خود را توسط printf و یا cout چاپ کردید، بر روی صفحه متن رنگی نخواهید دید بلکه مجبورید از توابع موجود در همین فایل استفاده کنید و یا چنانچه شما یک پنجره برای صفحه نمایش خود تعریف کردید و متن خود را با استفاده از cout یا printf چاپ کردید، پنجره شما اعمال نشده و ممکن است متن چاپی شما، از پنجره خارج شود .
الف) توابع رنگی :
- textcolor : اعلان این تابع به صورت ;(void textcolor(int newcolor می باشد . newcolor باید یک عدد صحیح بین صفر تا 15 باشد . این تابع رنگ متن چاپ شده توسط توابع همین فایل را تغییر می دهد . این تابع رنگ متن را با رنگ newcolor%16 عوض می کند یعنی چنانچه رنگ ورودی شما از 15 بزرگ تر باشد، باقیمانده آن بر 16 را حساب کرده و به عنوان newcolor در نظر می گیرد .
- textbackground : اعلان این تابع به صورت ;(void textbackground(int newcolor می باشد . newcolor باید یک عدد صحیح بین صفر تا 7 باشد . این تابع رنگ زمینه متن چاپ شده توسط توابع همین فایل را تغییر می دهد . دقت کنید که این تابع فقط هشت رنگ را پشتیبانی می کند و اصلاً نمی توان زمینه متن را با رنگ روشن پر کرد به همین دلیل این تابع فقط هشت رنگ پر رنگ را می پذیرد . همچنین چنانچه به این تابع و یا تابع textcolor رنگ غیر معمولی داده شود، نتیجه غیر قابل پیش بینی می باشد .
نکته : برای استفاده از رنگ ها یک Enum به صورت زیر در ++C تعریف شده است که شما می توانید از آن برای نام رنگ های خود استفاده کنید . دقت کنید که تمام ثابت های این enum با حروف بزرگ نوشته شده است و همچنین نام خود enum یعنی COLORS نیز با حروف بزرگ تعریف شده است بنابراین چنانچه خواستید متغییری از این تایپ شمارشی تعریف کنید، نام تایپ را با حروف بزرگ تایپ کنید :
كد:

enum COLORS {
/* dark colors */
BLACK, // 0 = 0000 : مشکی
BLUE, // 1 = 0001 : آبی
GREEN, // 2 = 0010 : سبز
CYAN, // 3 = 0011 : آبی آسمانی
RED, // 4 = 0100 : قرمز
MAGENTA, // 5 = 0101 : زرشکی : قرمز مایل به آبی
BROWN, // 6 = 0110 : قهوه ای
LIGHTGRAY, // 7 = 0111 : خاکستری روشن : سفید پر رنگ
DARKGRAY, // 8 = 1000 : خاکستری تیره یا خاکستری
/* light colors */
LIGHTBLUE, // 9 = 1001 : آبی روشن یا آبی کم رنگ
LIGHTGREEN, // 10 = 1010 : سبز روشن
LIGHTCYAN, // 11 = 1011 : آبی آسمانی روشن
LIGHTRED, // 12 = 1100 : قرمز روشن
LIGHTMAGENTA, // 13 = 1101 : زرشکی روشن یا صورتی
YELLOW, // 14 = 1110 : زرد
WHITE // 15 = 1111 : سفید یا سفید براق
};
در ضمن چنانچه بخواهید متن شما به صورت چشمک زن بر روی صفحه نمایش داده شود، کافیست رنگی که به تابع textcolor می دهید را با ثابت BLINK که توسط دستور #define تعریف شده است جمع کنید . این ثابت معادل عدد 128 می باشد . برنامه نویسانی که زبان ماشین و اسمبلی خوانده اند بهتر دلیل این موضوع را درک می کنند . بنابراین دستور ;(textcolor(RED+BLINK موجب می شود که متن چاپی با رنگ متن قرمز و به صورت چشمک زن چاپ شود .
- textattr : اعلان این تابع به صورت ;(void textattr(int newattribute می باشد . این تابع خیلی به وقفه زبان ماشین خودش نزدیک است ؟! می دانید که هر عدد int دارای 2 یا 4 بایت و یا به عبارت بهتر 16 یا 32 بیت می باشد . شما فقط به هشت بیت سمت راست عدد نگاه کنید، بقیه بیت ها مهم نیست . فرض کنید هشت بیت سمت راست عدد B به صورت B7B6B5B4B3B2B1B0 می باشد . چهار بیت سمت راست یعنی B3B2B1B0 مربوط به رنگ متن و سه بیت بعدی یعنی B6B5B4 مربوط به رنگ زمینه می باشد و اما بیت آخر یعنی B7 مربوط به چشمک زن بودن متن می باشد . می دانید که 2 به توان 7 برابر است با 128، به همین دلیل است که ثابت BLINK را برابر 128 در نظر گرفته اند . اما سوال دیگر اینکه این بیت ها معادل چه رنگی می باشند، مثلاً 0101 معادل چه رنگی است ؟! اول آنکه باید بدانید همانطور که گفته شد رنگ زمینه فقط سه بیت می باشد یعنی با آن می توان هشت رنگ را معرفی کرد . دقت کنید که این هشت رنگ، به صورت تیره می باشند یعنی پر رنگ می باشند . همین سه بیت، در رنگ متن نیز وجود دارند یعنی بیت های B2B1B0 نیز مانند سه بیت B6B5B4 بیان گر رنگ های تیره برای رنگ متن می باشند . بدیهی است چنانچه یک رنگ یکسان را به عنوان رنگ متن و زمینه تعیین کنید، بر روی صفحه نمایش چیزی مشاهده نمی کنید . اما بیت B3 چه عملی انجام می دهد ؟! این بیت باعث می شود که رنگ مشخص شده توسط سه بیت B2B1B0 که مربوط به رنگ متن می باشند، به صورت روشن در آیند نه تیره یعنی چنانچه سه بیت 001 معرف رنگ آبی باشند، رشته بیت 0001 معرف رنگ آبی پر رنگ و رشته بیت 1001 معرف آبی کم رنگ برای رنگ متن می باشند . این بیت معروف به بیت Intensity یا بیت شدت نور می باشد . اما رنگ های معادل سه بیت رنگ را چگونه تشخیص دهیم ؟! آیا تا به حال RGB به گوش شما رسیده است ؟! R مخفف Red یعنی قرمز، G مخفف Green به معنای سبز و B مخفف Blue به معنای آبی ؟! این سه حرف در اصل معرف همان سه بیت رنگ ما می باشند بنابراین رشته بیت های 001 و 010 و 100 به ترتیب معرف رنگ های آبی، سبز و قرمز می باشند مثلاً در مورد 100 می بینید که بیت های مربوط به G و B صفر می باشند یعنی در رنگ معادل رشته 100، رنگ های آبی و سبز وجود ندارد و بیت 1 مشخص می کند که رنگ قرمز وجود دارد . از ترکیب آنها نیز به راحتی می توانید رنگ های دیگر را بسازید مثلاً می دانید که از ترکیب رنگ های آبی و قرمز، رنگ بنفش بدست می آید بنابراین رشته بیت 101 معادل رنگ بنفش می باشد . حتماً آشنا هستید که رشته بیت 000 معادل رنگ سیاه و رشته بیت 111 معادل رنگ سفید می باشد . یادآوری می کنم که ترکیب رنگ های آبی و سبز، رنگ را بوجود می آورد و ترکیب رنگ های سبز و قرمز، رنگ زرد یا قهوه ای را بوجود می آورد . دقت کنید که رشته بیت 0110 معادل رنگ قهوه ای است و رشته بیت 1110 معادل رنگ زرد می باشد به عبارتی رنگ زرد همان رنگ قهوه ای روشن می باشد . اما چگونه با بیت ها کار کنیم یعنی چنانچه خواستیم رشته بی 0000,0000,0101,1101 (جهت خوانایی بهتر، بیت ها را چهار تا چهار تا، جدا کرده ام) را به تابع textattr بدهیم، چگونه می توانیم در یک متغییر int (با فرض دو بایتی بودن) بیت ها را دستکاری کنیم؟!
راه اول : ثابت شمارشی زیر را در نظر بگیرید :
كد:
enum Bits {Bit0=1,Bit1=2,Bit2=4,Bit3=8,Bit4=16,Bit5=32,Bit6= 64,Bit7=128};
با عمل OR بیتی ('|') می توانیم به راحتی یک رشته برای خود خلق کنیم . جمع بیتی یک عملگر دوگانی می باشد یعنی دو عملوند دارد و به این صورت تعریف می شود :
كد:
0|0=0 , 1|*=*|1=1
منظور از * در تعریف بالا هر بیتی (صفر یا یک) می باشد به عبارتی در اثر جمع بیتی بیت 1 با هر بیت دیگری، حاصل همان یک می باشد و در صورتی که صفر با صفر جمع بیتی شود، حاصل برابر صفر می شود . این عملگر دارای خاصیت جابجایی می باشد .
بنابراین رشته مورد نظر ما برابر است با :
كد:
int MyColor=Bit0 | Bit2 | Bit3 | Bit4 | Bit6;
اکنون در متغییر MyColor همان رشته رنگ مورد نظر ما ذخیره شده است، چگونه ؟! می دانید که Bit0 برابر است با عدد یک و این عدد برابر است با رشته بیت 0000,0001 (جهت خلاصه نویسی فقط همان هشت بیت سمت راست عدد را می نویسم و هشت بیت سمت چپ بدیهی است که برابر صفر می باشد)، یعنی عدد 2 به توان صفر به همین دلیل نام آن را نیز Bit0 گذاشته ام . برای مثال Bit2 نیز برابر است با 4 که معادل رشته بیت 0000,0100 یعنی عدد 2 به توان 2 و یا Bit4 نیز برابر است با 16 یعنی عدد 2 به توان 4 که معادل رشته بیت 0000,1000 می باشد . حال در مرحله اول مثال بالا، بیت های صفر و دو با هم جمع بیتی می شوند و می دانیم که 0000,0001 | 0000,0100 برابر است با 0000,0101، می بینید که سه بیت سمت راست رشته مورد نظرمان تولید شده است . به همین صورت با جمع بیتی شدن بقیه بیت ها، رشته 0000,0000,0101,1101 تولید می شود . البته می توانید جهت درک بهتر، اسامی بهتر برای متغییر ها استفاده کنید :
كد:
enum Bits {TxtB=1,TxtG=2,TxtR=4,Int=8,BGB4=16,BGG=32,BGR=64, BLK=128};
اومدیم ابروش را درست کنید زدیم چشمش را نیز کور کردیم ؟!!! مثلاً در تایپ شمارشی بالا، TxtB مخفف رنگ آبی مربوط به متن می باشد و یا BGG مخفف BackGroundGreen می باشد و یا Int مخفف همان Intensity و یا BLK مخفف همان Blink می باشد البته شما می توانید برای خود هر نامی را که دوست داشتید بگذارید اما سعی کنید که نامی انتخاب کنید که استفاده از آن برای خودتان و دیگران راحت باشد به قول استادی، نام ها را تقی و نقی و ... نگذارید ؟!!
راه دوم : شما تا کنون با عملگر های << و >> آشنا شده اید . به ترتیب به آنها عملگر های درج در جریان و استخراج از جریان می گویید و اولی را همراه شیء cout و دومی را همراه شیء cin جهت چاپ و یا دریافت عبارات و متغییر ها استفاده می کنید . اما این عملگر ها در اصل بر روی اعداد تعریف شده اند و وظیفه آنها انتقال بیت ها می باشد . مثلاً ;x=3<<1 موجب می شود که رشته بیت معادل عدد 3 به اندازه یک واحد به سمت چپ انتقال پیدا کند یعنی رشته بیت 0000,0011 به رشته بیت 0000,0110 تبدیل شود . البته شما بدون این عملگر نیز می توانستید این عمل را انجام دهید، چگونه ؟! در مثال ما رشته بیت حاصل یعنی رشته بیت 0000,0110 معادل عدد 6 می باشد . کمی دقیق که به این موضوع فکر کنید می بینید که در اثر هر انتقال (شیفت) به سمت چپ، در اصل ارزش مکانی بیت ها را یک واحد اضافه می کنیم یعنی بیتی که در خانه سوم بوده، پس از انتقال یک بیت به سمت چپ، به خانه چهارم می رود . می دانید که ارزش مکانی خانه چهارم، در مبنای دو، دو برابر ارزش مکانی خانه سوم می باشد و به همین دلیل است که پس از انتقال بیت ها به سمت چپ، حاصل دو برابر شده است یعنی 3*2=6 بنابراین هنگامی که خواستید یک رشته بیت را به سمت چپ شیفت دهید می توانید متغییر مربوط به آن را در عدد 2 ضرب کنید . عملگر << می تواند به هر تعدادی بیت های ما را شیفت دهد مثلاً x=5<<4; موجب می شود که رشته بیت مربوط به عدد 5 به اندازه 4 مرتبه به سمت چپ شیفت پیدا کنید . چنانچه خواستید این عمل را توسط عملگر ضرب انجام دهید باید عدد 5 را در عدد 16 (2 به توان 4) ضرب کنید . عملگر >> عکس عملگر << می باشد یعنی بیت ها را به سمت راست شیفت می دهد . هر بار شیفت به سمت راست معادل یک مرتبه تقسیم بر دو می باشد . حال چگونه رشته بیت خود یعنی رشته بیت 0000,0000,0101,1101 را تولید کنیم :
كد:
int MyColor=(1<<6) | (1<<4) | (1<<3) | (1<<2) | 1;
در عبارت بالا، ابتدا عدد یک را شش مرتبه به سمت چپ شیفت داده ایم به عبارتی آن را در 2 به توان 6 یعنی 64 شرب کرده ایم بنابراین حاصل برابر است با 0100,0000 به همین ترتیب چنانچه یک را 4 مرتبه به سمت چپ شیفت دهید، حاصل برابر است با 16 یعنی 0001,0000 و ... . در اثر جمع بیتی نمودن پرانتز های بالا با عدد یک، همان رشته بیت مورد نظر تولید می شود اما یک سوال ؟! این روش چه مزیتی دارد ؟! در این روش به جای ثابت های شمارشی قبلی فقط یک پرانتز آمده است، پس تفاوتش در چیست ؟! شما می توانید در این روش چنانچه مطمئن هستید که یک رنگ انتخاب کرده اید و قصد تغییر آن را نیز ندارید، بیت خود را سریع تر خلق کنید :
كد:
int MyColor=(1<<6) | (7<<2) | 1;
دقت کنید که عدد 7 معادل رشته بیت 111 می باشد و چنانچه این رشته بیت را به اندازه دو واحد به سمت چپ شیفت دهیم به رشته بیت 0001,1100 می رسیم . چنانچه این رشته را با رشته مورد نظر یعنی 0101,1101 مقایسه کنید، می بینید که سه عدد از یک های رشته بیت حاصل، تولید شده است .
راه سوم : شما می توانید اعداد هگزادسیمال یعنی اعداد مبنای شانزده را به صورت مستقیم در کامپایلر های ++C وارد کنید . برای این منظور کافیست که پیشوند 0x را به عدد خود اضافه کنید . مثلاً برای رشته مورد نظر ما، چنانچه متغییر int را دو بیتی در نظر بگیریم، بایت سمت راست رشته بیت 0101,1101 یعنی 1101 معادل عدد 13 می باشد که این عدد در مبنای 16 با حرف D یا d نمایش داده می شود . بایت سمت چپ رشته مورد نظر ما یعنی 0101 نیز معادل عدد 5 می باشد بنابر این می توانیم از دستور ;int MyColor=0x5d برای مقدار دهی به رنگ مورد نظر خود استفاده کنیم .
البته در عمل شما می توانید از تلفیق راه های گفته شده نیز استفاده کنید اما روش دوم باعث خلق رنگ های مختلف می شود مثلاً حلقه زیر را در نظر بگیرید :
كد:

for(int i=0;i<=8;i++)
MyColor=i+((i+5)<<4);

در این حلقه دائماً رنگ های متنوعی تولید می شود که با هم رابطه به خصوصی ندارند . اما دو نکته :
اول آنکه حق تقدم عملگر های شیفت بیتی، از تمام عملگر های محاسباتی پایین تر است یعنی در مثال بالا چنانچه می نوشتیم ;MyColor=i+(i+5)<<4 مثل این بود که نوشته باشیم ;MyColor=(i+(i+5))<<4 یا به طور خلاصه ;MyColor=(2*i+5)<<4 . نکته دوم آنکه عملگر های << و >> بر روی عملگر های محاسباتی پخش می شوند یعنی ;(2*i+5)<<4=(2*i<<4)+(5<<4) . دقت کنید که چنانچه پرانتز ها را نگذاریم به خصوص پرانتز دوم را، حاصل با نتیجه مورد نظر ما برابر نمی باشد چرا که همانطور که گفتم در کلمپایلر های ++C حق تقدم این عملگر های بیتی، پایین ترین حق تقدم می باشد . همچنین می توان عبارت حاصل را باز هم ساده کرد یعنی : (2*i<<4)+(5<<4)= (i<<5)+(5<<4) . می دانیم که I از صفر شروع می شود و تا 8 جلو می رود . چنانچه I پنج مرتبه به سمت چپ شیفت بخورد، به اندازه پنج بیت سمت راست حاصل، قطعاً برابر صفر است . همچنین حاصل 5<<4 همواره برابر است با 0101,0000 . می دانید که تابع textcolor و textbackground اعداد محدودی می پذیرند مثلاً textcolor اعداد بین صفر تا 15 را قبول می کند یعنی حداکثر رشته مورد قبول این تابع چهار بیتی می باشد چرا که توسط چهار بیت می توان اعداد صفر تا 15 را نمایش داد . با توجه به نکات گفته شده، مشاهده می کنید که حاصل رنگ ذخیره شده در متغییر MyColor چنانچه از دستور ;MyColor=i+(i+5)<<4 استفاده کنیم، همواره رنگ مشکی می باشد چرا که در جمع (i<<5)+(5<<4) قطعاً چهار بیت سمت راست حاصل، برابر است با صفر و رشته بیت 0000 معادل رنگ سیاه می باشد . منظور اینکه چنانچه اشتباهاً از این عملگر استفاده کنید، حاصل ممکن است اصلاً آن چیزی که مورد نظر شما بوده، نباشد بنابراین در طریقه نوشتن عبارات شامل عملگر << و >> دقت لازم را نمایید . نکته دیگر در ارتباط با عملگر های << و >> معکوس بودن آنها می باشد یعنی همانطور که عملگر های ضرب و تقسیم معکوس همدیگر می باشند، این دو عملگر نیز رابطه معکوس دارند و همدیگر را خنثی می کنند مثلاً a<<5>>6=a>>1 همانطور که a*28/7=a*4 .
ب) توابع مربوط به ورودی و خروجی :
- getch : اعلان این تابع به صورت ;()int getch می باشد . نام این تابع مخفف get character می باشد . این تابع یک کاراکتر را از فایل ورودی استاندارد خوانده و بدون نمایش بر روی خروجی استاندارد، بر می گرداند . دقت کنید که در اعلان بعضی از توان مانند getch در فایل سرآمد conio.h یک کلمه کلیدی void به عنوان پارامتر برای این تابع نوشته شده است یعنی اعلان getch به صورت ;(int getch(void می باشد . این موضوع اصلاً شما را گیج نکند، در قدیم (C) توابع بدون پارامتر را با void نشان می دادند یعنی کلمه void داخل پرانتز مقابل getch نشانگر این است که این تابع هیچگونه پارامتری دریافت نمی کند . از این تابع می توانید برای دریافت رمز از کاربر استفاده کنید . فرض کنید از این تابع به صورت زیر برای دریافت رمز استفاده کنید :
كد:

for(int i=0;i<6;i++)
password[i]=getch();

در اینصورت، کاربر چیزی بر روی صفحه نمایش مشاهده نکرده و فقط رمز مورد نظر خود را وارد می کند . اما شما می توانید از قطعه کد زیر نیز برای رمز استفاده کنید :
كد:

for(int i=0;i<6;i++)
{ password[i]=getch();
cout<<'*';
}

که در اینصورت کاربر به هنگام وارد نمودن رمز خود، به ازای هر کاراکتر یک عدد ستاره بر روی صفحه نمایش مشاده می کند . البته چنانچه بخواهید تابع خوبی برای دریافت رمز بنویسید بهتر است در آن تابع، شرط حلقه خود را وارد نمودن کاراکتر به خصوصی مانند ('Enter ('\n قرار دهید . همچنین برای BackSpace نیز شرط هایی بگذارید یعنی چنانچه کاربر رمز خود را به صورت اشتباه وارد کرد، بتواند از BackSpace نیز استفاده کرده و رمز خود را تغییر دهد . دقت کنید در حالت معمولی چنانچه شما دستور ;()ch=getch را اجرا کنید و کلید BackSpace را فشار دهید، مقدار 'b\' در متغییر شما ذخیره می شود بنابراین با کنترل کردن این مقدار می توانید رمز خود را اصلاح کنید . به تابع زیر دقت کنید :
كد:

char password[SIZE];
int i=0;
while()
{ password[i]=getch();
if(password[i]=='\n')
break;
else if(password[i]!='\b')
{ cout<<'*';
i++;
}
}

البته باز هم می توانید این قطعه کد را قوی تر کنید یعنی برای کنترل عبارات ورودی نیز شرایطی قائل شوید مثلاً اگر i مساوی SIZE-1 شد، یک بوق زده و چیزی در خانه SIZE-1 ذخیره نکنیم . خانه SIZE-1 را برای '0\' می توانیم در نظر بگیریم و رمز خود را به یک رشته تبدیل کنیم . با خانه SIZE چه کنیم ؟! دقت کنید که آرایه ما از صفر تا SIZE-1 اندیس بندی می شود پس خانه SIZE در محدوده غیر مجاز می باشد یعنی هیچی .
- getche : اعلان این تابع به صورت ;(int getche(void می باشد . این تابع مانند تابع getch عمل می کند با این تفاوت که کاراکتر خوانده شده را بر روی صفحه نمایش نیز نشان می دهد . حرف e در نام این تابع مخفف echo به معنی نمایش می باشد .
- putch : اعلان این تابع به صورت ;(int putch(int ch می باشد . این تابع کاراکتر ch را بر روی صفحه نمایش (مانیتور) نمایش می دهد . دقت کنید که این تابع بر اساس رنگ متن و زمینه تنظیم شده عمل می کند یعنی کاراکتر چاپ شده با رنگ متن و رنگ زمینه جاری چاپ می شود . البته بنده تا کنون موفق به تغییر مکان خروجی آن نشده ام یعنی هر چه سعی کردم تا به جای صفحه مانیتور، کاراکتر خروجی در یک فایل دیگری ذخیره شود، موفق نشده ام . فکر کنم این موضوع به دلیل استفاده از وقفه مربوط به صفحه نمایش می باشد که شنیده ام به سختی می توان با برنامه های زبان ماشین مسیر آن را تغییر داد . منظور آنکه چنانچه از این تابع استفاده کردید، باید بدانید که خروجی فقط بر روی صفحه نمایش می رود و حتی استفاده از دستور myfile >[path]\testfile.txt در سیستم عامل نیز موجب قرار گرفتن نتایج در فایل testfile.txt نمی شود . خروجی این تابع در صورت شکست برابر است با EOF . EOF یک ثابت نمادی می باشد که با دستور define# تعریف شده است و برابر است با عدد -1 . در صورتی که کاراکتر ch با موفقیت بر روی صفحه نمایش چاپ شد، خروجی تابع همان کاراکتر ch می باشد . در مورد این توابع (فقط توابع مربوط به conio.h مانند putch و cputs و cprintf) باید گفت که تنها نکته مهم این است که کاراکتر 'n\' مکان نما را به سطر بعد می برد ولی به ابتدای سطر نمی برد و به عبارتی می توان گفت اشاره گر را به موقعیت (x,y+1) می برد که این عمل با دستور ;(gotoxy(wherex(),wherey()+1 برابر است (با توابع این دستور بعداً آشنا می شوید) . اگر بخواهیم به ابتدای سطر برویم، می توانیم از کاراکتر کنترلی 'r\' استفاده کنیم به عبارتی رشته "n\r\" در این توابع معادل کاراکتر 'n\' در توابع مربوط به فایل های سرآمد iostream.h و stdio.h می باشد . اگر توانستید حدس بزنید چرا چنین تفاوتی بین این دو دسته از توابع وجود دارد ؟! حتماً در این مورد جوابی بدهید تا ببینم شما نیز حدس مرا می زنید یا شاید نظر بهتری دارید ؟!!
- kbhit : اعلان این تابع به صورت ;(int kbhit(void می باشد . نام این تابع مخفف keyboard hit می باشد . این تابع در صورتی که کلیدی از صفحه کلید فشرده شده باشد، مقدار غیر صفر (معمولاً 1-) بر می گرداند و در صورتی که کلیدی از صفحه کلید فشرده نشده باشد، مقدار صفر بر می گرداند . پس از آنکه از فشرده شدن کلید مطلع شدید، می توانید توسط تابع getch آن کاراکتر را خوانده و پردازش کنید . این تابع بیشتر هم در همین حالت کاربرد دارد یعنی به عبارتی ()kbhit! بیشتر مفید است . مثلاً می توان یک حلقه با شرط ()kbhit! درست کرد که در هر ثانیه در کنار صفحه نمایش، ساعت جاری را چاپ کند . در صورتی که کلیدی از صفحه کلید فشرده شد، آن کلید را پردازش کند و دوباره به حلقه قبلی برگردد و ساعت را تنظیم (refresh) کند .
كد:

while(1)
{ while(!kbhit())
Refresh();
char ch=getch();
process(ch); // e.g : putch(ch);
}

تابع refresh را به خاطر داشته باشید، باز هم با آن کار داریم .
- cgets : اعلان این تابع به صورت ;(char *cgets(char *str می باشد . این تابع یک رشته به عنوان پارامتر می گیرد و وظیفه آن نیز خواندن یک رشته از صفحه کلید می باشد . رشته str حداقل باید دارای سه خانه باشد، چرا ؟! خانه اول آن باید حداکثر طول رشته را در خود ذخیره کند مثلاً ;str[0]=21 یعنی اینکه طول رشته با احتساب '0\' به اندازه 21 خانه از حافظه می باشد به عبارتی رشته ورودی می تواند حداکثر دارای 20 کاراکتر باشد . پس از خواندن اطلاعات از صفحه کلید، طول رشته خوانده شده در خانه دوم آرایه یعنی [str[1 ذخیره می شود بنابراین رشته خوانده شده از خانه سوم آرایه یعنی از خانه [str[2 آرایه به بعد ذخیره می شود . بدیهی است که حداکثر طول آرایه شما می تواند 258 خانه از حافظه باشد و به عبارتی حداکثر طول رشته خوانده شده از صفحه کلید می تواند 255 کاراکتر باشد چرا که در یک متغییر char نمی توان عددی بزرگ تر از 255 وارد کرد . سه خانه هم برای '0\' و ماکزیمم طول و طول رشته خوانده شده نیاز می باشد .
- cputs : اعلان این تابع به صورت ;(char *cputs(const char *str می باشد . این تابع رشته str را بر روی صفحه نمایش چاپ می کند . این تابع تمام خصوصیات تابع putch را دارد یعنی رنگ را در نظر گرفته و فقط بر روی صفحه نمایش کار می کند .
شرمنده، صفحه جای کافی برای متن بنده را ندارد . ادامه در پاسخ بعدی مطالعه شود .

bsng110
شنبه 02 شهریور 1387, 22:21 عصر
ادامه پست قبلی :
- cscanf : اعلان این تابع به صورت ;(...,int cscanf(const char *format می باشد . این تابع را به همراه تابع بعدی توضیح می دهم :
- cprintf : اعلان این تابع به صورت ;(...,int cprintf(const char *format می باشد . این دو تابع را خوب یاد بگیرید چرا که در php نیز استفاده می شوند و چنانچه نحوه عملکرد این دو تابع را یاد بگیرید به جرأت می توانم بگویم حدود 12 تابع دیگر را نیز فرا گرفته اید . 12 تابع مذکور فقط در نوع پارامتر ها متفاوت می باشند . یاد آور می شوم که این توابع مربوط به زبان C می باشد و از آن زبان به ++C ارث رسیده است . بد نیست بدانید قبل از پیدایش جریان ها، چگونه داده ها کنترل می شدند، شاید در اینصورت قدر عافیت را بیشتر درک کنید . با عملگر '…' که آشنایید . همانطور که قبلاً نیز گفته ام این عملگر موجب می شود که بتوانید به تعداد نا محدود آرگومان برای این دو تابع ارسال کنید . با نحوه پیاده سازی این توابع آشنا شدید اما همانطور که آنجا نیز گفتم، در این توابع، کاربر باید به نحوی به برنامه نویس بفهماند که چند آرگومان ارسال می کند . ساده ترین حالت استفاده از این توابع، همان چاپ یک رشته و یا خواندن یک رشته می باشد . فعلاً دستورات مربوط به cprintf را بررسی می کنیم :
مثلاً چنانچه رشته "The number is : " را به تابع cprintf فرستادیم، این رشته را به همین صورت بر روی صفحه نمایش (تأکید می کنم فقط بر روی صفحه نمایش به همراه رنگ متن و رنگ زمینه) چاپ می کند . چنانچه بخواهیم در مقابل این رشته یک عدد را چاپ کنیم، می توانیم مجدداً این تابع را صدا زده و به آن atoi(intNumber,s) را بفرستیم . اما می بینید که این کد انعطاف پذیری کمی داشته و تازه بدتر آنکه، نیاز به یک رشته (s) نیز دارد . شما می توانید در هر قسمت از رشته فرمتی که به تابع cprintf می فرستید، با استفاده از علائمی، به این تابع بفهمانید که باید مقادیری را بر روی صفحه نمایش چاپ کند . مثلاً احضار ;(cprintf("The number is : %d",12 به تابع می فهماند که باید رشته " : The number is" را بر روی صفحه نمایش چاپ کرده و پس از آن یک عدد صحیح که به عنوان پارامتر دریافت می کند، چاپ کند بنابراین خروجی تابع که بر روی صفحه نمایش چاپ می شود برابر است با : "The number is : 12" البته علامت های کوتیشن (") بر روی صفحه چاپ نمی شود بلکه بنده جهت تشخیص عبارت چاپ شده بر روی صفحه نمایش از آنها استفاده می کنم . حال بیایید به مشخصه های تبدیل مختلف نگاهی بیاندازیم .
انواع مشخصه های تبدیل قابل قبول این تابع را می توان به سه دسته تقسیم کرد :
1) دسته اول : اعداد صحیح : همانطور که اشاره شد جهت چاپ اعداد دسیمال یا صحیح می توانید از مشخصه تبدیل d% (مخفف decimal) و یا i% (مخفف integer) استفاده کنید . چنانچه بخواهیم عدد بدون علامت چاپ کنیم، از مشخصه تبدیل u% (مخفف unsigned) استفاده می کنیم . چنانچه بخواهید عدد (مثبت) شما در مبنای هشت چاپ شود از مشخصه تبدیل o% (مخفف octal) استفاده کنید . همچنین برای چاپ اعداد مثبت در مبنای شانزده می توانید از یکی از مشخصه های تبدیل x% یا X% استفاده کنید .
2) اعداد اعشاری : مشخصه تبدیل اعداد اعشاری که به صورت معمولی چاپ می شوند، f% (مخفف float) می باشد . چنانچه بخواهیم عدد ما به صورت نماد علمی نمایش داده شود، از یکی از مشخصه های تبدیل e% یا E% استفاده می کنیم . مشخصه تبدیل e% موجب می شود که حرف e در نمایش عدد به صورت نماد علمی، به صورت کوچک یعنی با حرف کوچک انگلیسی نمایش داده شود و مشخصه تبدیل E% موجب می شود که علامت توان به صورت E یعنی با حرف بزرگ انگلیسی نمایش داده شود . مشخصه تبدیل g% موجب می شود که تابع بر اساس دقت اعشار و میدان عدد شما، یکی از مشخصه های تبدیل f% یا e% را اختیار کرده و عدد شما را در آن قالب چاپ کند . مشخصه تبدیل G% مانند g% می باشد با این تفاوت که به جای مشخصه تبدیل e% از مشخصه تبدیل E% استفاده می کند .
3) کاراکتر ها و رشته ها : از مشخصه تبدیل c% برای چاپ کاراکتر ها استفاده می شود . از مشخصه تبدیل s% نیز برای چاپ رشته ها استفاده می شود .
البته مشخصه های li و ld و lo و lx و lX و lu و lf و le و lE و lg و lG نیز به ترتیب برای اعداد long int و long int و long int و long intو long int و unsigned long و long double و long double و long double و long double و long double و به کار می روند به عبارتی مانند مخصه های قبلی خود برای اعداد long به کار می روند . مشخصه تبدیل p% برای چاپ اشاره گر ها استفاده می شود که مانند x% عمل می کند به عبارتی اشاره گر متناظر با p% را در مبنای شانزده چاپ می کند .
بنابراین تا کنون شما با تمام مشخصه های تبدیل توابع ورودی و خروجی به سبک C آشنا شدید اما چند نکته :
اول آنکه در مورد توابع ورودی مانند scanf چنانچه بخواهید رشته ای را عیناً از کاربر بخوانید می توانید آن را در رشته فرمت خود بفرستید مثلاً در دستور ;(cscanf("My name is %s",str کاربر باید ابتدا (عیناً و با رعایت بزرگ و کوچک بودن حروف) رشته "My name is " را (بدون کوتیشن) وارد کرده و سپس نام خود را وارد کند که در این صورت نام او در متغییر str ذخیره می شود . چنانچه کاربر کاراکتر غیر مجازی وارد کند مثلاً رشته "My name is " را اشتباه وارد کند و یا تابع منتظر خواندن یک عدد باشد و کاربر یک کاراکتر حروف الفبا وارد کند، عبارات وارد شده در فایل ورودی مانده و تابع با شکست خارج می شود و در متغییر str مقداری ذخیره نمی کند که در مورد تشخیص خطا ها بعداً صحبت می کنم .
برگردیم به همان مبحث چاپ . ببینیم خروجی دستور زیر چیست ؟
كد:

cprintf("Hello \"%s\"\nYour username : %d\n\\\\ your avg : %f \n\r percent : #i %%"
,"Good Boys",1245,12.5);

در این دستور جهت سادگی، پارامتر ها را به صورت مستقیم برای تابع فرستاده ام اما شما می توانید به جای مقادیر 1245 و 12.5 و یا رشته "Good Boys" هر متغییری را برای تابع بفرستید مثلاً متغییر str را که حاوی عبارت "Good Girls" به جای "Good Boys" می باشد . بیایید از ابتدای رشته فرمت تک تک عبارات را بررسی کرده و خروجی را تشخیص دهیم . اولین چیزی که بر روی صفحه نمایش چاپ می شود عبارت "Hello " می باشد . فرض کنید بخواهید کاراکتر کوتیشن را چاپ کنیم، می دانید که این کاراکتر از کاراکتر های زبان می باشد که برای کامپایلر دارای مفهوم به خصوصی است یعنی چنانچه شما بنویسید رشته "? Hello "Ahmad" . How are you" را به عنوان رشته فرمت برای تابع ارسال کنید، کامپایلر از شما خطا می گیرد چرا که رشته "Hello " را به عنوان یک رشته پذیرفته، سپس به عبارت Ahmad می رسد که هیچ ارتباطی با رشته قبلی نداشته و تابع نیز نمی تواند آن را به این صورت بپذیرد بنابراین به عبارت Ahmad شما گیر داده و پیغام خطا صادر می کند . فکر می کنید اگر رشته "? Hello ""Ahmad"" . How are you" را به عنوان رشته فرمت می فرستادیم، چه اتفاقی می افتاد ؟ در رشته جدید عبارت Ahmad را نیز بین دو کوتیشن قرار داده ایم . در این موارد کامپایلر دو رشته را به هم پیوند می دهد یعنی به جای رشته ما، رشته "? Hello Ahmad . How are you" را در نظر می گیرد بنابراین همین رشته بر روی صفحه نمایش داده می شود . تا کنون با چند نکته آشنا شدید اما هنوز موفق به چاپ کاراکتر کوتیشن بر روی صفحه نمایش نشده اید . در مورد این کاراکتر های خاص، کامپایلر تدابیری اندیشیده است . به جای کاراکتر " باید از زوج کاراکتر "\ استفاده کنید که این زوج کاراکتر، برای کامپایلر به معنی کاراکتر کوتیشن می باشد . همچنین زوج کاراکتر \\ به معنی کاراکتر \ برای کامپایلر می باشد به همین دلیل است که در نام فایل ها به جای "c:\a.txt" باید بنویسیم "c:\\a.txt" . از جمله زوج کاراکتر های دیگر می توان به n\ و r\ و t\ و v\ و f\ و a\ و b\ و ?\ و '\ و 0\ اشاره کرد . چنانچه کاراکتر a\ را چاپ کنید، یک صدای بوق از بلند گوی داخل رایانه (چنانچه متصل باشد) به گوش می رسد . کاراکتر b\ معادل backspace می باشد یعنی چنانچه آن را به عنوان ورودی دریافت کردید، می فهمید که کاربر کلید backspace را فشار داده است اما چنانچه این کاراکتر را چاپ کنید، مکان نما یک ستون به سمت عقب یعنی به سمت چپ صفحه نمایش (در صورت امکان) جابجا می شود به عبارتی چنانچه بخواهید یک کاراکتر از صفحه نمایش را پاک کنید باید رشته "b\ " را چاپ کنید که در اثر چاپ این رشته ابتدا مکان نما یک مکان به سمت چپ منتقل شده و سپس یک کاراکتر space چاپ می کند حال اگر می خواهید که مکان نما به مکان کاراکتر پاک شده برود، باید دوباره 'b\' را چاپ کنید . کاراکتر 't\' موجب می شود که مکان نما به ستون بعد صفحه نمایش برود . به طور کلی در پایگاه داس و برنامه های قدیمی، هر پرش (tab) معادل هشت کاراکتر می باشد بنابراین صفحه نمایشی که دارای 80 ستون است دارای ده ستون، هشت کاراکتری می باشد . چنانچه شما در ستون اول باشید و یک عدد 't\' چاپ کنید به ستون 9=8+1 می روید اما چنانچه در بین یکی از ستون های یک تا هشت نیز باشد و مجدداً 't\' را چاپ کنید، باز هم به ستون نهم می روید یعنی چاپ 't\' موجب می شود که مکان نما در ابتدای ستون بعدی صفحه نمایش قرار گیرد . توسط این کاراکتر می توانید جداول خود را تنظیم کنید . کاراکتر بعدی 'r\' می باشد . این کاراکتر موجب می شود که مکان نما به ابتدای سطر جاری برود . زوج کاراکتر '\ موجب چاپ شدن کاراکتر نقل قوی می شود مثلاً چنانچه بخواهید در تابع putch علامت نقل قول را چاپ کنید، به جای استفاده از دستور ;(''')putch باید از دستور ;(''\')putch استفاده کنید . زوج کاراکتر ?\ با کاراکتر ? برابر است . زوج کاراکتر 0\ را نیز می شناسید، این زوج کاراکتر در انتهای رشته ها قرار می گیرد . تا کنون 12 مورد از زوج کاراکتر ها را معرفی کرده ام و از بین آنها 9 مورد را توضیح داده ام . در مورد زوج کاراکتر های 'f\' و 'v\' توضیحی نمی دهم چرا که ظاهراً در مورد صفحه نمایش عمل نمی کنند و عملی که برایشان تعریف شده است را انجام نمی دهند اما زوج کاراکتر 'n\' می ماند . در مورد این زوج کاراکتر برای آخرین بار و به صورت مفصل توضیح می دهم . این زوج کاراکتر در مورد صفحه نمایش موجب می شود که مکان نما به یک سطر پایین تر از مکان جاری مکان نما منتقل شود یعنی چنانچه مکان نما در نقطه (2,7) صفحه نمایش است، به نقطه ( 2,8 ) صفحه نمایش منتقل شود . اما چنین رفتاری از این کاراکتر فقط در مورد توابع این فایل سرآمد دیده می شود و در توابع سایر فایل های سرآمد مانند stdio.h و iostream.h این کاراکتر موجب می شود که مکان نما به ابتدای سطر بعد برود . چنانچه بخواهید چنین عملی را در مورد توابع conio.h انجام دهید، خیلی راحت است کافیست که کاراکتر های r\ و n\ را با هم چاپ کنید اما چنانچه در توابع فایل های سرآمد stdio.h و iostream.h بخواهیم که مکان نما به سطر بعدی بدون تغییر ستون برود، مجبوریم که از توابع انتقال مکان نما استفاده کنیم . اما در مورد این دوگانگی چه توضیحی وجود دارد ؟ توابع داخل فایل conio.h مستقیماً بر روی صفحه نمایش عمل می کنند اما توابع مربوط به فایل های سرآمد stdio.h و iostream.h مستقیماً بر روی صفحه نمایش چیزی قرار نمی دهند بلکه عبارات ما را داخل فایلی ذخیره می کنند که این فایل به صورت استاندارد در سیستم عامل، به خروجی استاندارد که در حالت عادی صفحه نمایش می باشد و همچنین ورودی استاندارد که در حالت عادی به صفحه کلید متصل می باشد، متصل است . تمام عبارات ما ابتدا داخل این فایل قرار گرفته و سپس خوانده و یا چاپ می شوند . نمی دانم تا چه حد با فایل ها آشنایی دارید اما چنانچه در NotePad یک سند ساده به زبان انگلیسی نوشته و ذخیره کنید و آن را در C یا ++C باز کرده و تک تک کاراکتر های آن را خوانده و مشاهده کنید، می بینید که هر جا شما enter زده اید، به جای enter شما زوج کاراکتر n\ ذخیره شده است نه زوج کاراکتر های n\r\ ؟! به همین دلیل بنده فکر می کنم که در توابع مربوط به فایل های سرآمد stdio.h و iostream.h به جای r\n\ فقط n\ را ذخیره می کنند . البته شاید این دلیل قانع کننده نباشد و بگویید چرا در فایل ها چنین رفتاری دارند اما به هر حال این دوگانگی در میان این توابع وجود دارد . برگردیم سراغ رشته خود در دستور زیر :
كد:

cprintf("Hello \"%s\"\nYour username : %d\n\\\\ your avg : %f \n\r percent : %i %%"
,"Good Boys",1245,12.5,50);

گفتیم در این دستور ابتدا رشته "Hello " چاپ می شود . همانطور که فهمیدید، به جای "\ کاراکتر " چاپ می شود . سپس تابع به مشخصه تبدیل s% برخورد می کند بنابراین پارامتر اول را به صورت یک رشته در نظر گرفته و آن را چاپ می کند . دقت کنید چنانچه شما پارامتری به تابع ارسال نکنید و یا پارامتر غیر مجازی به تابع ارسال کنید، مثلاً یک عدد به جای رشته، خروجی غیر قابل پیش بینی می باشد چرا که همانطور که قبلاًٌ در مورد آرگومان های متغییر گفتم، تابع اولین پارامتر را به صورت کنترل شده دریافت نمی کند (بر خلاف زبان هایی مانند #C که بر روی تعداد و نوع پارامتر ها کنترل دارند) بلکه مکانی از حافظه را به عنوان مکان پارامتر های ارسالی در نظر گرفته و از آنجا شروع به خواندن متغییر ها می کند بنابراین چنانچه شما توسط آرگومان های خود، این پارامتر ها را پر نکنید، نتیجه غیر قابل پیش بینی می باشد . اما ما در تابع خود پارامتر ارسال کرده ایم بنابراین رشته "Good Boys" چاپ می شود در نتیجه تا کنون بر روی صفحه نمایش داریم : 'Hello "Good Boys' (از این به بعد از کاراکتر ' جهت نمایش عبارتی که بر روی صفحه چاپ می شود استفاده می کنم تا با متن عبارت چاپ شده اشتباه نشود) . سپس دوباره کاراکتر کوتیشن چاپ می شود . حال به دلیل وجود زوج کاراکتر n\ مکان نما به سطر بعد منتقل می شود . سپس عبارت ' : Your username' چاپ می شود . دوباره به یک مشخصه تبدیل برخورد کردیم یعنی d% بنابراین تابع مجدداً یک پارامتر خوانده و آن را به صورت عدد صحیح چاپ می کند . مجدداً مکان نما به سطر بعدی می رود و دو عدد \ چاپ می کند . دقت کنید که هر زوج کاراکتر \\ برابر است با یک عدد کاراکتر \ . سپس عبارت ' : Your avg' چاپ می شود و مجدداً تابع به یک عدد مشخصه تبدیل بر خورد کرده و عددی اعشاری از پارامتر بعدی خود خوانده و آن را چاپ می کند . سپس توسط اجرای دستورات n\r\ مکان نما را به ابتدای سطر بعد می برد . حال رشته ' : percent' را چاپ کرده و عددی صحیح از پارامتر های خود خوانده و آن را چاپ می کند . یک سوال ؟ همانطور که گفتیم برای چاپ \ باید از زوج کاراکتر \\ استفاده کنیم اما چنانچه بخواهیم کاراکتر % را چاپ کنیم باید چه عملی انجام دهیم . در این تابع (تأکید می کنم فقط در توابع مربوط به ورودی و خروجی به سبک C نه در سایر توابع) به جای % باید زوج کاراکتر %% را به تابع ارسال کرد که در اینصورت تابع می فهمد که باید یک عدد کاراکتر % چاپ کند . بنابراین خروجی دستور بالا به صورت زیر می باشد :
كد:

Hello "Good Boys"
Your username : 1245
\\ your avg : 12.5
Percent : 50 %

به نظر بنده در بعضی موارد، توابع قدیمی مانند printf و ... بهتر از اشیاء cout می باشد مثلاً برای اجرای دستور بالا (که در زیر مجدداً آورده شده است) توسط شیء cout باید دستور زیر را می نوشتیم (صرف نظر از نحوه عملکرد زوج کاراکتر n\ که در cout به شکل دیگری عمل می کند) :
كد:

cprintf("Hello \"%s\"\nYour username : %d\n\\\\ your avg : %f \n\r percent : %i %%"
,"Good Boys",1245,12.5,50);
cout<<"Hello \""<<"Good Boys"<<"\nYour username : "<<1245<<"\n\\\\ your avg : "<<12.5<<"\n\r percent : <<50<<"%";

البته این موضوع سلیقه ای می باشد یعنی شاید شما از شیوه نوشتن cout بیشتر خوشتان می آید اما چنانچه مطالب بعدی را بخوانید شاید کمی نظر شما نیز تغییر کند . البته این موضوع را نیز بیان می کنم که شیء cout انعطاف پذیری بیشتری دارد که با آن در جلسه بعدی بیشتر آشنا می شویم . باز هم تأکید می کنم که این مطالب را ساده نگیرید چرا که حداقل در php می توانید از آنها استفاده کنید . شاید تا کنون با مفاهیمی مثل میدان و دقت آشنا شده باشید . این دو مفهوم در مورد اعداد کاربرد دارند . شما می توانید مکان یک نقطه بر روی محور مختصات در بازه (100-,100) را به صورت ثابت با دو رقم اعشار و مجموعاً شش کاراکتر نشان دهید که 2 کاراکتر آن رقم اعشار، 2 کاراکتر رقم صحیح، 1 کاراکتر علامت عدد و یک کاراکتر اضافی هم جهت فاصله گذاری (مثلاً برای زیبایی خروجی) قرار دهید، چگونه ؟! تأکید می کنم که بعضی از این مطالب فقط در مورد اعداد کاربرد دارد و چنانچه در مورد کاراکتر ها و رشته ها استفاده شوند، تأثیری ندارند مثلاً استفاده از دقت برای یک رشته بی معناست اما میدان یک رشته را نیز می توان تنظیم کرد .
جهت تنظیم میدان کافیست بین کاراکتر '%' و مشخصه تبدیل خود، میدان را بیان کنید . یک سوال ؟! چنانچه میدان بزرگتر، کوچکتر یا مساوی طول عدد یا رشته باشد، چه اتفاقی رخ می دهد . چنانچه میدان کوچکتر یا مساوی طول عبارت باشد، هیچ تغییری در طول عبارت چاپ شده رخ نداده و به همان طول اصلی عبارت یا عدد چاپ می شود اما چنانچه طول میدان بزرگتر از طول عبارت یا عدد باشد، مکان های اضافی توسط کاراکتر ' ' پر می شوند .
در مورد اعداد می توان به تابع گفت که به جای کاراکتر ' ' از کاراکتر '0' استفاده کند . برای این منظور کافیست یک عدد کاراکتر '0' قبل از میدان (بعد از کاراکتر '%' و قبل از عدد مربوط به میدان) وارد کنید .
نکته دیگر اینکه به صورت پیش فرض کاراکتر های اضافی در سمت چپ رشته یا عدد ما قرار می گیرند به عبارتی رشته "Ali" با طول میدان 6 به صورت " Ali" چاپ می شود . چنانچه بخواهیم موقعیت رشته یا عدد ما در سمت چپ قرار گرفته و کاراکتر های اضافی در سمت راست رشته قرار گیرند، از کاراکتر '-' در بین کاراکتر '%' و مشخصه فرمت استفاده می کنیم که در این صورت نتیجه به صورت "Ali " خواهد بود .
همچنین چنانچه بخواهیم در مورد اعداد، علامت عدد حتماً ذکر شود باید از کاراکتر '+' استفاده کنیم .
چنانچه بخواهیم به جای کاراکتر '+' در مورد اعداد مثبت، یک فاصله خالی قرار بگیرد از کاراکتر ' ' (فضای خالی) استفاده می کنیم در این صورت به جای علامت '+' کاراکتر ' ' چاپ می شود .
چنانچه کاراکتر '#' را در رشته فرمت خود برای اعداد قرار دهیم، قبل از اعداد مبنای هشت کاراکتر '0' و قبل از اعداد مبنای 16 کاراکتر های '0x' قرار می گیرد .
اما دقت چگونه تنظیم می شود ؟! کافیست بعد از طول میدان یک کاراکتر '.' گذاشته و عدد مربوط به دقت خود را بنویسید . چنانچه میدان را نمی خواهید تنظیم کنید می توانید قبل از مشخصه تبدیل خود کاراکتر '.' و سپس دقت خود را بنویسید مثلاً "3f.%" . دقت کنید که دقت فقط در مورد اعداد اعشاری معنی دارد و در مورد اعداد صحیح تأثیری ندارد .
نکته دیگر اینکه ممکن است بخواهید میدان و دقت در طول برنامه برای یک تابع دائماً تغییر کند و یا اینکه در زمان اجرا مقدار آن ها مشخص شود ولی با روش گفته شده، این کار بسیار مشکل می باشد . برای این منظور کافیست از کاراکتر '*' استفاده کرده و متناظر آن عدد صحیح مربوط به میدان یا دقت خود را ارسال کنید، مثلاً احضار ;(cprintf("My Number : %+-0*.*f",5,2,15.1257 با احضار ;(cprintf("My Number : %+-05.2f",15.1257 مساوی است با این تفاوت که در احضار اول می توان دو متغییر به تابع ارسال کرد که مقدار آنها در زمان اجرا معلوم می شود . البته باید دقت کنید که اعداد متناظر با '*' باید حتماً صحیح باشد . همچنین بنده در مثال خود هر دو اعداد مربوط به میدان و دقت را به صورت متغییر در نظر گرفته ام که این موضوع الزامی نمی باشد یعنی می توانید فقط یکی از آنها را نیز به صورت متغییر دریافت کنید مثلاً به صورت ;(cprintf("My Number : %+-05.*f",2,15.1257 .
چند نکته دیگر در ارتباط با این توابع می ماند که به دلیل اختصار از ذکر آنها خود داری می کنم اما در مورد تابع cscanf باید دقت کنید که آرگومان هایی که به تابع ارسال می کنید باید از نوع اشاره گر یا به عبارتی آدرس متغییر های خود باشد بنابراین برای خواندن عدد صحیحی از ورودی باید تابع ;(cscanf("%d",&intNumber را صدا بزنید نه ;(cscanf("%d",intNumber را، دلیل آن نیز واضح است .
حال ببینیم خروجی این توابع چه می باشد ؟! تابع cscanf تعداد اعداد یا رشته هایی که با موفقیت خوانده است را بر می گرداند . تابع cprintf تعداد کاراکتر هایی که چاپ کرده است را بر می گرداند . هر دو تابع در صورت شکست (به هر دلیلی)، ثابت EOF که برابر است با -1 را بر می گدانند .
حال بیایید به آن 12 تابعی که قبلاً نیز اشاره کرده ام، نگاهی بیاندازیم . توابع زیر را در نظر بگیرید :
كد:

cscanf(const char *format,…);
fscanf(FILE *stream,const char *format,…);
scanf(const char *format,…);
sscanf(const char *buffer,const char *format,…);
vfscanf(FILE *stream,const char *format,va_list arglist);
vscanf(const char *format,va_list arglist);
vsscanf(const char *buffer,const char *format,va_list arglist);

و
كد:

cprintf(const char *format,…);
fprintf(FILE *stream,const char *format,…);
printf(const char *format,…);
sprintf(const char *buffer,const char *format,…);
vfprintf(FILE *stream,const char *format,va_list arglist);
vprintf(const char *format,va_list arglist);
vsprintf(const char *buffer,const char *format,va_list arglist);

با توابع cscanf و cprintf که آشنا شدید . توابع scanf و printf مشابه دو تابع قبل می باشند با این تفاوت که بر روی ورودی و خروجی استاندارد به عبارتی فایل CON عمل می کنند و در مورد 'n\' نیز عملکرد متفاوتی دارند که قبلاً توضیح داده شد . توابع fscanf و fprintf مانند scanf و printf عمل می کنند با این تفاوت که فایل مورد پردازش را به عنوان پارامتر دریافت می کنند . افرادی که با توابع مربوط به فایل های C آشنایی دارند، حتماً ساختار FILE را می شناسند که توابع fscanf و fprintf این ساختار را به عنوان اولین پارامتر دریافت می کنند . می بینید که با این دو تابع چقدر پردازش فایل ها راحت تر می شود . دقت کنید که می توان توابع scanf و printf را توسط توابع fscanf و fprintf پیاده سازی کرد به عبارتی احضار ;(...,fprintf(stdout,myformat,mydata با احضار ;(...,printf(myformat,mydata یکی می باشد چرا که stdin و stdout همان FILE * های مربوط به CON در C می باشند بنابراین دو احضار ;(...,fscanf(stdin,myformat,mydata و ;(...,scanf(myformat,mydata نیز مشابه می باشند . توابع sscanf و sprintf برای پردازش رشته ها استفاده می شوند به عبارتی ورودی در تابع sscanf یک رشته می باشد و خروجی در تابع sprintf یک رشته می باشد . در خاطرتان هست که پرسیدم به نظر شما ساده ترین راه برای پیاده سازی atof چیست ؟! حال شاید بتوانید حدس بزنید چگونه می توان چنین تابعی را پیاده سازی کرد . حال که در مورد رشته ها صحبت کردیم، باید بدانید که مشخصه تبدیلی به صورت []% نیز وجود دارد که در مورد رشته ها بیشتر استفاده می شود . می دانید که به صورت عادی چنانچه بخواهید یک رشته شامل نام و نام خانوادگی را بخوانید با مشکل مواجه می شوید چرا که در بین کاراکتر های موجود در این رشته، حداقل یک کاراکتر فضای خالی (مثلاً ' ') وجود دارد که موجب توقف خواندن ورودی می شود . از مشخصه تبدیل []% می توانید برای خواندن چنین رشته هایی استفاده کنید که در این صورت باید حتماً ابتدا و انتهای رشته را به نحوی مشخص کرد . مثلاً به کاربر می گوییم که نام و نام خانوادگی خود را بین دو کاراکتر < > بنویسد . در این صورت احضار تابع ;(scanf("<%[^>]>",mystring موجب می شود که رشته ورودی ما خوانده شود . در این احضار، ابتدا کاراکتر اول رشته یعنی < را خوانده و شناسایی می کنیم، از این به بعد هر چه که کاربر وارد کند خوانده شده و در رشته mystring قرار می گیرد تا هنگامی که کاراکتر > وارد شود . حال در رشته mystring به جای > کاراکتر '0\' قرار گرفته و کاراکتر > به ورودی بر گردانده می شود . سپس توسط کاراکتر > موجود در رشته فرمت، کاراکتر > موجود در فایل نیز خوانده می شود به عبارتی در این مشخصه تبدیل، تمام کاراکتر ها خوانده می شوند مگر آنانکه پس از علامت ^ در زوج کروشه مشخص شده است . چنانچه در داخل زوج کروشه کاراکتر ^ وجود نداشته باشد، یعنی فقط کاراکتر های موجود در [] مجاز به خواندن می باشند مثلاً می توان گفت معادل atoi مشخصه تبدیل [0123456789]% با d% (البته فقط تا حدودی) یکسان است .
توابعی که با کاراکتر 'v' شروع می شوند، مانند توابع بدون 'v' می باشند با این تفاوت که متغییر va_list را به صورت مستقیم دریافت می کنند . در مورد متغییر va_list قبلاً توضیح داده ام که جهت یادآوری به مبحت آرگومان های متغییر مراجعه کنید .
ج) توابع مربوط به دستکاری صفحه نمایش :
- wherex : اعلان این تابع به صورت ;(int wherex(void می باشد . این تابع موقعیت عمودی مکان نما را بر می گرداند یعنی مشخص می کند که مکان نما در کدام ستون قرار دارد، دقت کنید چنانچه صفحه نمایش را در ناحیه چهارم صفحه مختصات در نظر بگیرید، در اینصورت x مشخص کننده شماره ستون می باشد . خروجی این تابع بسته به حالت صفحه نمایش و موقعیت مکان نما، بین 1 تا 80 می باشد .
- wherey : اعلان این تابع به صورت ;(int wherey(void می باشد . این تابع موقعیت افقی مکان نما را بر می گرداند یعنی مشخص می کند که مکان نما در کدام سطر قرار دارد . خروجی این تابع بسته به حالت صفحه نمایش و موقعیت مکان نما، بین 1 تا 50 می باشد .
- gotoxy : اعلان این تابع به صورت ;(int gotoxy(int x,int y می باشد . توسط این تابع می توانید مکان نما را به هر نقطه دلخواهی از صفحه نمایش ببرید . چنانچه پارامتر غیر مجازی به این تابع بدهید، تابع هیچ عملی انجام نمی دهد . x و y را نیز با توجه به ناحیه چهارم صفحه نمایش باید مشخص کنید . بسته به نوع حالت صفحه نمایش x بین 1 تا 50 می باشد و y بین 1 تا 80 می باشد .
- clrscr : اعلان این تابع به صورت ;(int clrscr(void می باشد . این تابع موجب می شود که صفحه نمایش، با رنگ زمینه فعلی، پاک شود به عبارتی مثل این عمل می کند که از ابتدای صفحه نمایش تمام سطر ها و ستون ها را توسط تابع putch با کاراکتر space پر کنید . سپس مکان نما را در موقعیت (1,1) قرار می دهد .
- clreol : اعلان این تابع به صورت ;(int clreol(void می باشد . این تابع از موقعیت مکان نما تا انتهای سطر جاری را پاک کرده و مکان نما را در همان مکان جاری نگه می دارد به عبارتی فقط موجب می شود که در روبروی مکان نما، تا انتهای سطر جاری، تمام ستون ها را کاراکتر space پر شوند .
- insline : اعلان این تابع به صورت ;(int insline(void می باشد . این تابع موجب می شود که در موقعیت مکان نما، یک سطر جدید ایجاد شود و سطر های زیر مکان نما، به اندازه یک سطر، به سمت پایین منتقل شوند . چنانچه سطر آخر صفحه نیز دارای متن باشد، این خط حذف می شود .
- delline : اعلان این تابع به صورت ;(int delline(void می باشد . این تابع موجب می شود که سطر جاری از روی صفحه نمایش پاک شده و سطر های پایین تر از آن، به اندازه یک سطر به سمت بالا بیایند .
- window : اعلان این تابع به صورت ;(void window(int left,int top,int right,int down می باشد . رفتار این تابع بسیار جالب می باشد . توسط این تابع می توانید صفحه نمایش را محدود کنید . مثلاً فرض کنید صفحه نمایش شما در حالت استاندارد یعنی 25*80 باشد .
توسط دستور ;( window( 10,13,20,18 مکان نما به نقطه (10,13) منتقل می شود . توسط این دستور می توان مستطیلی در صفحه نمایش تعریف کرد که گوشه سمت چپ و بالای آن نقطه (10,13) و گوشه سمت راست و پایین آن نقطه ( 20,18 ) می باشد . حال هر چه که توسط توابعی مانند putch و cputs و cprintf چاپ کنید، فقط در این محدود چاپ می شود . مانند این است که صفحه نمایش فقط مستطیل تعریف شده می باشد بنابراین چنانچه متنی در این صفحه جدید چاپ کردید و صفحه پر شد، صفحه مستطیلی شما پیمایش (scroll) می شود و مانند صفحه نمایش به سمت بالا می رود تا سطر جدیدی برای متن بعدی آماده شود . خیلی جالب است ؟!
- gettext : اعلان این تابع به صورت ;(int gettext(int left,int top,int right,int down,void *dest می باشد . ابتدا باید کمی در مورد صفحه نمایش اطلاعات کسب کنیم . فرض کنید صفحه نمایش 25*80 باشد . در حافظه اصلی یعنی RAM به اندازه 25*80 خانه از حافظه وجود دارد که کاراکتر های صفحه نمایش را در خود ذخیره می کند و کارت گرافیک با خواندن این کاراکتر ها، هر لحظه صفحه نمایش را مجدداً تازه (Refresh) می کند . پس رنگ چی ؟! علاوه بر 25*80 خانه برای ذخیره کاراکتر ها، 25*80 خانه نیز برای صفت رنگ کاراکتر ها در نظر می گیرد و به عبارتی برای هر خانه از صفحه نمایش در حالت متنی (نه گرافیکی) دو بایت از حافظه را اشغال می کند که بایت اول مربوط به کاراکتر آن خانه بوده و بایت دوم که معروف به بایت صفت است و با آن در توضیح تابع textattr آشنا شدید، مربوط به رنگ متن و زمینه می باشد . نکته ای دیگر : آیا تا به حال در محیط TC++ 3.0 کلید های Alt+F5 را استفاده کرده اید . مثلاً فرض کنید برنامه ای نوشته اید و در حال ردیابی خط به خط آن می باشید . فرض کنید در دستور متنی بر روی صفحه نمایش چاپ کرده اید . حال می خواهید آن متن را مشاهده کنید . با فشار دادن کلید های Alt+F5 صفحه نمایش فعلی شما پاک شده و صفحه خروجی برنامه شما نشان داده می شود . به نظر شما در یک لحظه برنامه تمام حافظه را نسخه برداری کرده و آن را دوباره با کاراکتر های خروجی برنامه جایگزین می کند ؟! خیر اینطور نیست . معمولاً (بسته به ظرفیت رایانه ها و حافظه RAM و حالت صفحه نمایش و ...) در حافظه RAM چندین صفحه نمایش در نظر گرفته می شود به عبارتی چندین 2*25*80 خانه حافظه جهت صفحه نمایش در نظر گرفته می شود . در هر لحظه کاربر می تواند به سیستم بگوید که کدام صفحه را نمایش دهد با این عمل صفحه فعال یعنی صفحه ای که باید بر روی صفحه نمایش چاپ شود، تغییر کرده و صفحه مورد نظر او خواهد شد . این امر موجب تسهیل و سرعت بالا در پردازش تصاویر و عبارات می شود .
حال برگردیم به توضیح عملکرد این تابع . این تابع متن داخل مستطیلی که توسط (left,top) و (right,bottom) تعریف شده است را در آرایه dest به همان صورتی که شرح داده شد، ذخیره می کند یعنی از سمت چپ به راست و از بالا به پایین، ابتدا کاراکتر و سپس صفت هر خانه از صفحه نمایش را در آرایه قرار می دهد . چنانچه بخواهید اندازه مناسب آرایه خود را تشخیص دهید، می توانید از رابطه 2*(right-left)*(bottom-top) استفاده کنید . خروجی این تابع در صورت شکست عدد صفر در صورت موفقیت عددی مخالف صفر (اکثراً 1) می باشد .
- puttext : اعلان این تابع به صورت ;(int puttext(int left,int top,int right,int down,void *src می باشد . عملکرد این تابع واضح است . این تابع متن داخل آرایه src را که حاوی کاراکتر و صفت خانه های صفحه نمایش می باشد را داخل صفحه مستطیلی (left,top) و (rifht,bottom) چاپ می کند . خروجی این تابع در صورت شکست عدد صفر در صورت موفقیت عددی مخالف صفر (اکثراً 1) می باشد .
- movetext : اعلان این تابع به صورت ;(int puttext(int left,int top,int right,int down,int destleft,int desttop می باشد . این تابع متن داخل صفحه مستطیلی (left,top) و (rifht,bottom) را نسخه برداری کرده و یک کپی از آن را در مستطیلی به همان ابعاد که گوشه سمت چپ و بالای آن برابر است با (destleft,desttop) کپی می کند . دقت کنید متن داخل کادر مستطیلی (left,top) و (rifht,bottom) پاک نمی شود بلکه یک نسخه از آن در کادر مستطیلی (destleft,desttop) و (right+destleft-left,bottom+desttop-top) چاپ می شود . خروجی این تابع در صورت شکست عدد صفر در صورت موفقیت عددی مخالف صفر (اکثراً 1) می باشد . شما می توانید با ترکیب این توابع، اعمال متفاوتی بر روی صفحه نمایش انجام دهید اما باز هم تأکید می کنم که این توابع فقط بر روی صفحه نمایش عمل می کنند و تأثیری در فایل هایی مانند CON و ... ندارند .
- setcursortype_ : اعلان این تابع به صورت ;(void _setcursortype(int newtype می باشد . این تابع یکی از ثابت های زیر یا عدد معادل آنها را می پذیرد : NOCURSOR_ یا صفر ، SOLIDCURSOR_ یا یک ، NORMALCURSOR_ یا دو . در صورتی که به این تابع پارامتر غیر مجاز داده شود، رفتار تابع غیر قابل پیش بینی است . اما این پارامتر ها چه عملی انجام می دهند . اگر تا به حال با محیط Command Line و یا محیط DOS کار کرده اید، لابد تا به حال در یکی از این محیط ها کلید Insert را فشار داده اید و مشاهده کرده اید که حالت مکان نما به صورت ▓ در می آید . و یا ممکن است در برنامه های قدیمی مشاهده کرده اید که مکان نما وجود نداشته و چنانچه شما مقادیری را وارد کنید، در جای به خصوصی قرار می گیرد . شما می توانید با استفاده از پارامتر NOCURSOR_ مکان نما را حذف کنید و یا توسط پارامتر SOLIDCURSOR_ مکان نما را به شکل پر رنگ تر در آورید . همچنین می توانید توسط پارامتر NORMALCURSOR_ حالت مکان نما را به صورت معمول در آورید .
امیدوارم که از مطالب این قسمت لذت برده باشید .
در پناه حق
خداحافظ

siryahya
سه شنبه 21 آذر 1391, 11:37 صبح
خیلی ممنون. خیلی به دردم خورد