kala-tamin آموزش پيشرفته C


آموزش پيشرفته C



اشاره گرها و رشته ها

چون رشته ها در زبان C بصورت آرايه تعريف مي شوند بين آنها و اشاره گرها نيز
ارتباط نزديكي وجود دارد . بطوري كه بسياري از توابع كتابخانه اي كه با رشته ها
سر و كار دارند ، ارتباط نزديكي با اشاره گرها پيدا مي كنند . بعنوان مثال تابع
()strchr كه محل اولين وقوع كاراكتري را در رشته اي پيدا مي كند بصورت زير
استفاده مي شود :
) <رشته > و <كاراكتر مورد جستجو>(= strchr اشاره گر

مثال 1: برنامه اي كه يك رشته و كاراكتري را از ورودي خوانده و محل اولين
وقوع اين كاراكتر را در رشته پيدا مي كند . main)(
{
char ch/line[81]/*ptr/*strchr )(;
printf("\nenter string to search:\n");
gets(line );
printf("\n enter a character: " );
ch=getche )(;
ptr=strchr(line/ch );
printf("\n the string start at " );
printf("address:%u/line" );
printf("\n first occurence of" );
printf(" <%c> is address:%u"/ch/ptr);
printf("\n this is position:" );
printf("%d( start from 0)"/ptr-line);
}

نمونه اي از خروجي برنامه مثال 1 : enter string to search:
c has no bound checking.
enter a character: k
the string start at address:3984

first occurence of is address:8291
this is position:20(start from 0 );

همانطوريكه ازخروجي برنامه مثال 1 پيداست تابع strchr با جستجوي يك كاراكتر
در يك رشته ، آدرس اين كاراكتر را بعنوان نتيجه عمل مشخص ميكند و در يك اشاره گر
برنامه مي دهد . همانطور كه قبلا" گفته شد ، اگر تابعي داراي نوعي غير از "صحيح "
باشد بايد در تابع فراخواننده ، نوع آن به كامپايلر اعلام گردد . لذا در مثال
(َ1) نوع تابع ()strchr بصورت اشاره گر به كاراكتر تعريف شده است . البته اگر با
استفاده از دستور پيش پردازنده # include فايل "string" به برنامه معرفي گردد
نيازي به تعريف اين تابع بصورت اشاره گر نيست .

مثال 2: برنامه اي كه رشته اي را از ورودي دريافت كرده و كليه حروف كوچك اين
رشته را به حروف بزرگ تبديل مي كند . main)(
{
char s[50] ;
printf("enter a string in");
printf(" lowercase:\n");
gets(s );
upper(s );
printf("\n uppercase of");
printf(" string is:\n");
puts(s );
}

upper(char *string)
{
while(*string)
{
if(*string>='a' && *string<='z')
*string=*string-32 ;
string++ ;
}
}

نمونه اي از خروجي برنامه مثال 2 : enter a string in lowercase:
in c all keyword are lowercase.
uppercase of string is:
IN C ALL KEYWORD ARE LOWERCASE.


مثال 3: برنامه اي كه رشته اي را از ورودي خوانده و كليه حروف بزرگ موجود در
رشته را به حروف كوچك تبديل مي كند : main)(
{
char s[50] ;
printf("enter a string in");
printf(" uppercase:\n");
gets(s );
upper(s );
printf("\n lowercase of string");
printf(" is:\n");
puts(s );
}

upper(char *string)
{
while(*string)
{
if(*string>='A' && *string<='Z')
*string+=32 ;
string++ ;
}
}

نمونه اي از خروجي برنامه مثال 3 : enter a string in uppercase:
THIS IS A TEST FOR CONVERT TO LOWER.
lowercase of string is:
this is a test for convert to lower.


مثال 4: برنامه اي كه يك رشته و كاراكتري را از ورودي خوانده و تعداد دفعات
تكرار اين كاراكتر را رشته مشخص مي كند . main)(
{
char string[40] / ch ;
int count ;
printf("enter string for search:\n");
gets(string );
printf("\n enter a character:" );
ch=getche )(;
count=char_count(string/ch );
printf("\n number of occurs of " );
printf("char <%c> is:%d"/ch/count );
}

char_count(char *s/char letter)
{
int count=0 ;
while(*s)
if(*s++==letter)
count ++ ;
return(count );
}

نمونه اي از خروجي برنامه مثال 4 : enter string for search:
this is a simple test.
enter a character:
number of occurs of char is:3


مثال 5: برنامه اي كه رشته عددي را از ورودي خوانده و سپس آن را به مقدار
عددي تبديل مي كند . main)(
{
int number ;
char s[10] ;
printf("\n string representation");
printf(" of numeric:" );
gets(s );
ascii_to_int(&number/s );
printf("\n numeric value of ");
printf("string is:%d"/number );
}

ascii_to_int(int *value/char *str)
{
int sign=1 ;
*value=0 ;
while(*str==' ' )str++ ;
if(*str=='-' || *str=='+')
sign=(*str++=='-' )?- 1:1;
while(*str)
if((*str>='0' )&&( *str<='9'))
*value=(*value*10)+(*str++- 48 );
else
{
printf("Watning: the<%c> is:"/*str);
printf(" invalid character." );
exit(0 );
}
*value *=sign ;
}


خروجي هاي حاصل از 4 بار اجراي برنامه مثال 5 : string representation of a numeric-:342( 1)
numeric value of string is-:342

string representation of a numeric:+2341( 2)
numeric value of string is:+2341

string representation of a numeric:543( 3)
numeric value of string is:543

string representation of a numeric:45y4( 4)
Watning: the is invalid character.


مثال 6: برنامه اي كه عددي را از ورودي خوانده و سپس آن را به رشته تبديل
مي كند . main)(
{
int number ;
char s[10] ;
printf("\n enter a number: " );
scanf("%d"/&number );
int_to_ascii(number/s );
printf("\n the string value is:%s"/s);
}

int_to_ascii(int*value/char *str)
{
int sign=value ;
char temp / *savestr=str ;
if(value<0)
value*=-1 ;
do{
*str++=(value % 10)+48 ;
value=value/10 ;
} while(value>0 );
if( sign<0)
*str++='-' ;
*str-- ='\0' ;
while(savestr {
temp=*str ;
*str--=*savestr ;
*savestr++=temp ;
}
}

نمونه اي از خروجي برنامه مثال 6 : enter a number:2341
the st



کمک برای Cookie manipulation در C یا #C

1:

ارزش دهي اوليه رشته ها به عنوان اشاره گر

در اين قسمت مي خواهيم مشخص كنيم كه چگونه ميتوان رشته ها را بعنوان اشاره گر
مقدار اوليه داد .


پر کردن یک بافر با ای دی پدر
براي روشن شدن موضوع ، به مثال 1 توجه نماييد .


کد بازی


مثال 1: main)(
{
char *text="your name is:";
char name[41] ;
printf("\n enter your name: " );
gets(name );
printf("\n\n %s text" );
puts(name );
}

نمونه اي از خروجي برنامه مثال 1 : enter your name:mohammad
your name is:mohammad

اولين دستور مثال 1 را بصورت زير نيز مي توان نوشت : static char text[] = "your name is:";

اين دو دستور از نظر اثري كه در حافظه مي گذارند تفاوتي با يكديگر ندارند .


تشکر

ولي چون دستوري كه در برنامه آمده هست متغير text را بصورت اشاره گر تعريف كرده
هست ، قابليت انعطاف بيشتري به اين متغير داده هست .


در خواست لينك دانلود برنامه Turbo C
اين امر باعث شده هست كه
با دستور ساده ;(text++)puts رشته text كاراكتر به كاراكتر به خروجي منتقل گردد
كه نتيجه زير حاصل خواهد شد : your name is:

وقتي كه رشته ها به صورت اشاره گر تعريف مي شوند ، بخصوص در مواقعي كه طول
عناصر مختلف اون ، متفاوت باشند موجب صرفه جايشاني در ميزان حافظه مي گردند ( مثال ( .


مشکل های کد stack
2


مثال 2: برنامه اي كه براي ذخيره كردن نام هاي تعدادي از افراد ، از آرايه اي
از اشاره گرها هستفاده مي كند.


میشه یه برنامه گرافیکی در ++c واسم بزارید (مثلا رسم نمودار و...)
اين برنامه با مطالعهنام 5 نفر از ورودي ، اونها
را در آرايه اي برنامه داده ، سپس نامي را از ورودي دريافت مي كند و تشخيص مي دهد
كه آيا اين نام در ليست وجود دارد يا خير .


آموزش (پیشرفته) : توابع بازگشتی در Pascal و C/C++
main)(
{
int dex / exist=0 /k ;
char name[21] ;
static char *list[5]=
{"ali"/
"ahmad"/
"alireza"/
"jalal"/
"mohammad"
} ;
printf("enter a name for search:");
gets(name);
for(dex=0;dex<5;dex++)
{
if(strcmp(list[dex]/name)==0)
{
exist=1 ;
break ;
}
}
if(exist==1)
printf("\n name <%s> exist."/name);
else
printf("\n name " );
printf("<%s> not exist."/name);
}

نمونه اي از خروجي برنامه مثال 2 : enter a name for search: ali
name exist.



اگر در مثال 2 فرض شود كه اولين عنصر آرايه list ( كه حاايشان 5 نام هست ) در
محل 1000 حافظه برنامه داشته باشد .

اين آرايه بصورتي كه در شكل (1) آمده هست در
حافظه برنامه مي گيرد .


اگر درمثال 2 بجاي تعريف آرايه اي از اشاره گرها، آرايه اي از رشته ها را تعريف
ميكرديم اونگاه مي بايست آرايه list بصورت آرايه اي دو بعدي تعريف ميشد كه تعداد
سطرهاي اون برابر با تعداد افراد ( تعداد عناصر آرايه ) و تعداد ستون هاي اون
برابر با طول طولاني ترين نام موجود بود ( شكل 2 و مثال 3 ) .


ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤ |A |h |m |a |d |\0|
1000ؤؤ > | 1000 List [0]
ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤ |A |l |i |\0|
1006ؤؤ > | 1006 List [1]
ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤ |A |m |i |n |\0|
1010ؤؤ > | 1010 List [2]
ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤ |y |a |f |a |r |n |e |z |h |a |d |\0|
1015ؤؤ > | 1015 List [3]
ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤ |B |a |h |r |a |m |i |\0|
1027ؤؤ > | 1027 List [4]
ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤ
شكل (1) .

نحوه برنامه گرفتن آرايه اي از اشاره گرها در حافظه ، شامل 5 نام


ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤ | | | | |
|
|A hh |m |a |d |\0| 1000ؤؤؤؤؤؤؤؤؤ > List [0]
ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤ | | | | | | |
|
|A ll |i |\0| 1012ؤؤؤؤؤؤؤؤؤ > List [1]
ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤ | | | | | |
|
|A mm |i |n |\0| 1023ؤؤؤؤؤؤؤؤؤ > List [2]
ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤ |y aa |f |a |r |n |e |z |h |a |d |\0|
1035ؤؤؤؤؤؤؤؤؤ > List [3]
ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤ | | |
|
|B aa |h |r |a |m |i |\0| 1047ؤؤؤؤؤؤؤؤؤ > List [4]
ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤ
شكل (2) .

نحوه برنامه گرفتن آرايه اي از رشته ها در حافظه ، شامل 5 نام

با توجه به نحوه ذخيره شدن اطلاعات در اشكال 1و 2و ذخيره كردن رشته ها بصورت
آرايه اي از اشاره گرها در صرفه جايشاني ميزان حافظه بسيار موثر هست ولي در همه حالات
اينطور نيست .

بعنوان مثال اگر طول همه رشته ها 12 باشد ( به اندازه بزرگترين
طول رشته در مثال 2 )، حافظه تخصيص يافته در روش اول ( آرايه اي از اشاره گرها )
داراي 5 اشاره گر اضافي خواهدبود كه حافظه بيشتري را نسبت به روش دوم ( آرايه اي
از رشته ها ) اشغال مي كند .

مزيت عمده بيان رشته ها بصورت آرايه اي از اشاره گرها
سرعت بالاتر و سهولت دسترسي به عناصر اونها هست .

زيرا نيازي به انجام محاسبات
جهت دسترسي به عناصر آرايه نيست .



مثال 3: برنامه اي كه نام تعدادي از افراد را از ورودي خوانده و در يك آرايه
برنامه مي دهد .

سپس با هستفاده از آرايه اي از اشاره گرها ، اون را مرتب مي كند و
نتيجه را به خروجي مي برد .

main)(
{
char name[30][81] ;
char *ptr[30]/*temp ;
const int k=30 ;
int in / out / count=0 ;
while(count {
printf("\n enter name of number");
printf(" %d:"/count+1 );
gets(name[count] );
if(strlen(name[count])==0)
break ;
ptr[count++]=name[count] ;
}
for(out=0 ; out for(in=out+1 ; in if(strcmp(ptr[out]/ptr[in])>0)
{
temp=ptr[in] ;
ptr[in]=ptr[out] ;
ptr[out]=temp ;
}
printf("<< the sorted list is:>>");
for(out=0 ; out printf("\n name %d is:"/out+1);
printf("%s"/ptr[out]);
}

نمونه اي از خروجي برنامه مثال 3 : enter name of number 1:bahrami
enter name of number 2:amin
enter name of number 3:jafar
enter name of number 4:sadeghi
enter name of number 5:
<< the sorted list is:>>

name 1 is:amin
name 1 is:bahrami
name 1 is:jafar
name 1 is:sadeghi

براي توضيح بيشتر در مورد چگونگي مرتب كردن رشته ها از طريق آرايه اي از
اشاره گرها ، به شكل هاي 3و 4و كه بيانگر نحوه برنامه گرفتن عناصر آرايه در حافظه
قبل و سپس مرتب شدن هستند توجه نماييد .


ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤ |B |a |h |r |a |m |i |\0|
ؤؤؤؤؤؤؤؤؤ > | ptr[0]
ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤ | |
|
|A |m |i |n |\0|ؤؤؤؤؤؤؤؤؤ > | ptr[1]
ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤ |
|
|y |a |f |a |r |\0|ؤؤؤؤؤؤؤؤؤ > | ptr[2]
ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤ |s |a |d |e |g |h |i |\0|
ؤؤؤؤؤؤؤؤؤ > | ptr[3]
ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤ
شكل (3) .

وضعيت اشاره گرها قبل از مرتب شدن


ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤ |B |a |h |r |a |m |i |\0|
ؤؤؤ ؤؤؤؤؤ > | ptr[0]
ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤ |
| | |A |m |i |n |\0|ؤؤؤؤؤؤؤؤؤ > | ptr[1]
ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤ |
| |y |a |f |a |r |\0|ؤؤؤؤؤؤؤؤؤ > | ptr[2]
ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤ |s |a |d |e |g |h |i |\0|
ؤؤؤؤؤؤؤؤؤ > | ptr[3]
ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤ
شكل (4) .

وضعيت اشاره گرها سپس مرتب شدن

نكته اي كه در مورد مثال 3 بايد مورد توجه برنامه گيرد اين هست كه آرايه name
بصورت دو بعدي تعريف شده هست ولي در حين دسترسي به عناصر اون ، بصورت يك بعدي
مورد هستفاده برنامه گرفته هست .

اين مساله بدين دليل هست كه در زبان C قسمتي از
آرايه را مي توان بصورت يك آرايه فرض كرد .

بعبارت ديگر ، در يك آرايه دو بعدي
هر سطر را مي توان بصورت يك آرايه يك بعدي در نظر گرفت .

لذا مي توان فرمود كه
آرايه دو بعدي ، آرايه اي از آرايه هاي يك بعدي هست .

بعنوان مثال در دستور : static char name[30][81];

آرايه name يك آرايه دو بعدي تعريف شده هست كه ميتوان اون را بصورت يك آرايه
يك بعدي با تعداد 30 عنصر در نظر گرفت كه هر عنصر اون نيز يك آرايه يك بعدي به

2:

اشاره گر به اشاره گر

اگر متغيري آدرس متغير ديگر را در خود نگهداري كند ، متغير اول يك اشاره گر
هست .

اگر متغير دوم ، از نوع اشاره گر باشد در اينصورت متغير اول يك اشاره گر
به اشاره گر هست ( شكل 1 ) .

يادآوري مي شود كه آرايه اي از اشاره گرها ، نوعي
اشاره گر به اشاره گر هست .


متغير اشاره گر
ؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤ |
مقدار |ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ آدرس >|
ؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤ
ؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤ |
مقدار |ؤؤؤؤؤؤؤؤؤؤؤؤؤؤ آدرس >|ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ آدرس >|
ؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤ
شكل (1) .

اشاره گر به اشاره گر

براي تعريف متغيرهاي اشاره گر به اشاره گر ، از دو علامت * هستفاده مي شود .



مثال : برنامه اي شامل اشاره گر به اشاره گر .

main)(
{
int x / *p /**q ;
x=10 ;
p=&x ;
q=&p ;
printf("\n the points to value:");
printf("%d"/**q );
}

خروجي حاصل از اجراي برنامه مثال بالا : the points to value:1

3:

نكاتي در مورد اشاره گرها

عليرغم قدرت زيادي كه هستفاده از اشاره گرها در زبان به برنامه نايشانس مي دهد
اشكالاتي را نيز مي تواند بوجود آورد كه برنامه نايشانس بايد اونها را در نظر داشته
باشد .


اشكال اول ) هستفاده از اشاره گرهايي كه قبلا" مقدار نگرفته اند .



مثال 1: main)(
{
int x/*p ;
x=10 ;
*p=x ;
}

دربرنامه مثال 1 عدد 10 به متغير x نسبت داده ميشود و دستور *p=x; به ماشين
مي گايشاند " محتايشانات متغير x را در آدرسي كه اشاره گر p به اون اشاره مي كند برنامه
بده " .

چون اشاره گر p بجايي در حافظه اشاره نميكند ( قبلا" مقدار نگرفته هست )
عمل مورد نظر انجام نخواهد شد.

براي رفع اين مشكل كافي هست در اشاره گر p مقدار
معتبري برنامه گيرد .



اشكال دوم ) عدم هستفاده صحيح از اشاره گرها

مثال 2: main)(
{
int x / *p ;
x=10 ;
p=x ;
printf("\n %d"/*p );
}

هدف برنامه مثال 2 اين بود كه مقدار متغيرx را كه برابر با 10 هست در خروجي
چاپ نمايد ولي به دليل نادرست بودن دستور p=x; ( با توجه به اشاره گر بودن p )
نتيجه مطلوب حاصل نخواهد شد .

اين دستور موجب مي شود تا عدد 10 ، نه بعنوان يك
مقدار بلكه بعنوان يك آدرس به اشاره گر p منتقل گردد .

براي رفع اين مشكل كافي
هست اين دستور را بصورت p=&x; نوشت تا آدرس متغير x به اشاره گر p منتقل شود .



اشكال سوم ) فرض هايي كه برنامه نايشانس در مورد محل برنامه گرفتن متغيرها در حافظه
دارد .



وقتي كه متغيرها در حافظه برنامه مي گيرند ، جاي اونها براي ما مشخص نيست و در
هر جايي كه فضايي كافي وجود داشته باشد اين متغيرها در اونجا ذخيره مي شوند .


به همين دليل مقايسه اشاره گرهايي كه به عناصري از يك نوع اشاره نمي كنند صحيح
نبوده و با مشكل مواجه مي گردد ( مثال هاي 3و 4و ) .



مثال 3: main)(
{
char s[80]/y[80] ;
char *p1 / *p2 ;
p1=s ;
p2=y ;
if(p1 printf("p1 points to lower addree.");
}

در مثال 3 مقايسه p1و p2و با يكديگر صحيح نيست ، زيرا محل برنامه گرفتن
رشته هاي sو yو براي ما مشخص نيست .



مثال 4: main)(
{
int first[10]/second[10] ;
int *p / t ;
p=first ;
for(t=0 ; t<20 ; t++)
*p++=t ;
}

در مثال 4 سعي شده كه به عناصر آرايه هاي firstو secondو اعداد 0 تا 19 نسبت
داده شود.

اگر چه ممكن هست اين عمل در بعضي از كامپايلرها به درستي انجام گيرد
ولي در حالت كلي اين طور نيست ، زيرا ممكن هست عناصر آرايه هاي firstو secondو
در محل هاي متوالي حافظه برنامه نگيرند .


با اشكالاتي كه تاكنون درمورد اشاره گرها فرموده شد برنامه نايشانس بايد در هستفاده ا دقت كافي بخرج دهد تا با مشكل مواجه نگردد .


4:

آرگومانهاي تابع اصلي (()main)

اولين تابع يك برنامه كه اجرا مي شود ، تابع ()main هست .

اين تابع همانند
توابع ديگر مي تواند داراي آرگومان باشد.

آرگومان هاي تابع اصلي را آرگومان هاي
خط فرمان نيز مي گايشانند .

اين نامگذاري بدين دليل هست كه :
وقتي برنامه زبان C توسط كامپايلر زبان ترجمه شد ، اين برنامه در خارج از
محيط C و در سطح سيستم عامل قابل اجرا هست و در حين اجراي اين برنامه اسامي
آرگومان ها نيز جهت انتقال به تابع اصلي ذكر مي شوند .

بعنوان مثال ، فرض كنيد
برنامه اي بنام test.c نوشته ، توسط كامپايلر C اون را ترجمه كرده و برنامه اي به
نام test.exe از اون ساخته ايم .

براي اجراي اين برنامه كافي هست در سطح سيستم
عامل بصورت زير عمل كنيم (با فرض اين كه اين برنامه در درايو جاري وجود دارد): A>test

اگر فرض شود كه اين برنامه داراي دو پارامتر باشد ، براي اجراي اون در سطح
سيستم عامل ، بايد اسامي آرگومان ها را با يك فاصله بصورت زير تايپ كنيم : A>test par1 par2
par1
و par2و اسامي آرگومان هايي هستند كه به تابع اصلي منتقل مي شوند .


تابع اصلي داراي دو پارامتر بنام هاي argcو argvو هست .

پارامتر argc از نوع
صحيح بوده و مشخص كننده تعداد آرگومان هاي خط فرمان هست .

چون نام برنامه به
عنوان يك آرگومان محسوب مي شود لذا حداقل مقدارargc برابر با 1 هست .

بنابراين
اگر برنامه اي مانند test داراي دو آرگومان باشد، عددي كه در پارامتر argv برنامه
مي گيرد برابر با 3 خواهد بود.

پارامتر argv به آرايه اي رشته اي اشاره ميكند كه
عناصر اون ، به آرگومان هاي خط فرمان اشاره مي كند .

لذا كليه آرگومان هاي تابع
اصلي بصورت رشته هاي فرض مي شوند .

بنابراين اگر خواسته باشيم از اعدادي كه به
عنوان آرگومان به تابع اصلي منتقل مي شوند هستفاده كنيم ، بايد به طريق مقتضي
( با هستفاده از توابع كتابخانه اي و يا توابعي كه خودمان مي نايشانسيم ) اونها را
از رشته اي ، به عددي تبديل كنيم .



مثال 1: برنامه اي كه نامي را به عنوان آرگومان پذيرفته و عبارت hello را در
جلايشان اون نام برنامه مي دهد .

main(argc/argv)
int argc ;
char *argv[] ;
{
if(argc!=2)
{
printf("\n number of parameter ");
printf("is wrong ." );
exit(0 );
}
printdf("\n\n hello %s"/argv[1] );
}

فرض كنيد نام برنامه مثال 1را name.cا انتخاب كرده ، سپس توسط كامپايلر زبان C
از اون ، برنامه name.exe را ساخته باشيم .

براي اجراي اين برنامه كافيست به
صورت زير عمل شود : A>name Ali

پس از اجراي برنامه name ، نتيجه زير حاصل خواهد شد : hello Ali

در مورد ترتيب دسترسي به آرگومان هاي تابع اصلي بايد دقت داشت كه : argv[0]
بنام برنامه ، argv[1] به اولين آرگومان ، argv[2] به دومين آرگومان
و argv[n]به n امين آرگومان اشاره مي كنند .



مثال 2: برنامه اي كه يك عدد را بعنوان آرگومان پذيرفته ، عمل شمارش معكوس از
اون عدد به صفر را انجام مي دهد .

اين برنامه مي تواند آرگومان دوم نيز داشته
باشد .

اگر آرگومان دوم برابر با "display" باشد ، نتيجه شمارش معكوس در صفحه
نمايش چاپ خواهد شد .

main(argc/argv)
int argc ;
char *argv[] ;
{
int disp/count ;
if(argc<=2)
{
printf("\n number of parameter ");
printf("is wrong ." );
exit(0 );
}
if(argc==3 && !strcmp[argv[2]/
"display"))
disp=1 ;
else
disp=0 ;
for(count=atoi(argv[1]);count
;-- count)
if(disp)
printf("\n %d "/count );
printf("%c"/7 );
}

نمونه اي از خروجي برنامه مثال 2 : C:\TC>6-23 5 display
5
4
3
2
1

در خروجي فوق ، 5 عددي هست كه بايد بطور معكوس شمارش شود و 6-23 نام برنامه
هست .


در مورد مثال 2 بايد دو مطلب زير را بخاطر داشت : 1
تابع ()atoi يكي از توابع كتابخانه اي هست كه مقدار عددي رشته اي را به
مقدار عددي صحيح تبديل مي كند.

بكار گرفتن اين تابع بدين دليل بود كه عدد وارد
شده بعنوان آرگومان تابع كه شمارش معكوس اون بايد انجام شود ، بصورت رشته اي به
تابع اصلي منتقل خواهد شد كه براي هستفاده از اون ، بايد بصورت عددي تبديل شود.

2
آخرين دستور ()printf پس از عمل شمارش معكوس جهت بصدا درآوردن زنگ سيستم
بكار گرفته شده هست .


اگر آرايه argv با دو انديس به كار گرفته شود ، موجب دسترسي به هر يك از
از كاراكترهاي آرگومان تابع ( بطور جداگانه ) مي گردد .

( مثال 3 ) .



مثال 3: برنامه اي كه چگونگي دسترسي به هر يك از كاراكترهاي آرگومان تابع
اصلي را نشان مي دهد .

main(int argc/char *argv[])
{
int t / i ;
if(argc<2)
{
printf("number of parameters");
printf("is wrong." );
exit(0 );
}
for(t=0 ; t {
i=0 ;
while(argv[t][i])
{
printf("\n %c "/argv[t][i] );
i++ ;
}
}
}

نمونه اي از خروجي برنامه مثال 3 : C:\TC>6-24 allah
a

l
l
a
h

در مثال 3 بايد دقت داشت كه اولين انديس آرايه argv[] يعني t به آرگومان
تابع اصلي ( مشخص كننده شماره آرگومان ) كه يك رشته هست اشاره مي كند، و دومين
انديس اين آرايه به كاراكتري از اين آرگومان اشاره مي كند كه شماره اون كاراكتر
با اين انديس مشخص مي شود .

بعنوان مثال ، منظور از argv[2][3] كاراكتر سوم از
آرگومان دوم مي باشد .


از نظر تئوري مي توان حداكثر از 32767 عدد آرگومان هستفاده نمود كه معمولا" تعداد را اجازه مي دهد .


5:

دستورات پيش پردازنده

پيش پردازنده ، نوعي مترجم هست كه دستورات توسعه يافته اي از يك زبان برنامه
سازي را گرفته و به دستورات قابل فهم براي كامپايلر همان زبان تبديل مي كند .


بعبارت ديگر، ورودي پيش پردازنده ، برنامه اي با دستورات توسعه يافته هست و خروجي
اون ، برنامه ديگري هست كه توسط پردازشگر اصلي قابل ترجمه و اجرا هست .

دستورات
توسعه يافته اي كه در زبان C وجود دارند وتوسط پردازشگر اصلي قابل ترجمه و اجرا
نيستند ، فقط توسط پيش پردازنده قابل فهم هستند و به دستورات پيش پردازنده
معروفند .

دستورات پيش پردازنده در زبان C از اهميت ايشانژه اي برخوردار بوده و اي تنوع خاصي هست .


6:

تعريف ماكرو

ماكرو، نامي براي يك رشته هست كه اين رشته مي تواند تركيبي از خروف ، ارقام
مقادير ثابت ، توابع و غيره باشد .

دستور پيش پردازنده # define براي تعريف
ماكرو هستفاده مي شود .

اين دستور قبل از تابع ()main به دو صورت بكار مي رود
كه يك روش اون بصورت زير هست :
<نام ماكرو> <رشته ># define
نام ماكرو همانند نام يك متغير در C هست كه حداقل بايد با رشته تعريف كننده
ماكرو ، يك فاصله داشته باشد و بهتر هست جهت مشخص بودن در برنامه با حروف بزرگ
انتخاب شود .

بعنوان مثال ، دستور # define MAX 20

موجب مي شود تا مقدار ماكرايشان MAX در سرتاسر برنامه برابر با 20 فرض شود .


يعني در هر جاي برنامه از ماكرايشان MAX هستفاده شود مثل اين هست كه از عدد 20
هستفاده شده هست .


در مورد دستورات پيش پردازنده در زبان C ، بايد اين نكته را در نظر داشت كه
اونها عليرغم ساير دستورات زبان C ، به ; ختم نمي شوند .



مثال 1: برنامه اي كه چگونگي هستفاده از ماكروها را نشان مي دهد.

اين برنامه
تعدادي عدد را از ورودي خوانده و مجموع اونها را محاسبه مي كند ( اگر عددي كه
وارد مي شود ، منفي باشد ، برنامه متوقف مي شود ) .

#define program main)(
#define FLOAT float
#define WHILE while(
#define DO)
#define BEGIN {
#define end }
#define formatout "the sum is %8.2f\n"
PROGRAM
BEGIN
FLOAT data/sum=0.0;
scanf(FORMATIN/& data);
WHILE data>=0.0 DO
BEGIN
sum+=data;
scanf(FORMATIN/&data);
END
printf(FORMAOUT/SUM);
END

نمونه اي از خروجي برنامه مثال 1 : enter a numbet: 12
enter a numbet: 45
enter a numbet: 83
enter a numbet-: 1
the sum is 140.00

در مثال 1 بجاي تابع اصلي ()mainاز PROGRAMز ، بجاي {از BEGINز ، بجاي } از END
و...

هستفاده شده هست .

بديهي هست كه انتخاب اين نام ها به نظر برنامه نايشانس
بستيگ دارد كه مي تواند هر چيز ديگري را بجاي اونها انتخاب نمايد .



مثال 2: برنامه اي كه با هستفاده از علامت * ، مثلثي را در صفحه نمايش رسم
مي كند .

#define NUMLINE 5
#define BLANK ' '
#define ASTRISK '*'
#define NEWLINE '\n'
main)(
{
int l/le/s ;
1=1;
while( l<=NUMLINE)
{
le=1 ;
while( le++<=NUMLINE-1)
printf("%c"/BLANK);
s=1;
while(s++<=2*1-1)
printf("%c"/ASTRISK);
printf("%c"/NEWLINE);
l++;
}
}

خروجي برنامه مثال 2 : *
* * *
* * * * *
* * * * * * *
* * * * * * * * *

كاربرد ديگر دستور# define در تعريف ماكروهايي هست كه داراي پارامتر باشند.


در اين مورد از دستور # define بصورت زير هستفاده مي شود .

# define READINT(I )scanf("%d/&I)

تعريف ماكرو ، مشخص مي كند كه چه عملي بايد توسط ماكرو انجام گيرد .

اسامي
پارامترها متغيرهايي هستند كه در حين اجراي ماكرو به اون منتقل مي شوند .

اگر
تعداد اونها بيش از يكي باشد ، با كاما از يكديگر جدا مي گردند .

برخلاف توابع
در ماكروها نيازي به تعريف نوع پارامترها نيست .

بعنوان مثال دستور # define READINT(I )scanf("%d/&I)

ماكرايشاني بنام READINT تعريف ميكند كه داراي پارامترI هست ، درهنگام فراخواني
اين ماكرو ( كه توسط نام اون انجام مي شود ) بايد آرگوماني را ذكر كنيم .

اين
آرگومان در عبارت ("%d"/&I)scanf بجاي متغير I منظور شده و تابع scanf عددي را
از ورودي خوانده و در متغيري كه بعنوان آرگومان ذكر شده هست برنامه مي دهد .

به
عنوان مثال اگر بخواهيم متغيري مثل distance رااز ورودي بخوانيم كافيست ماكرايشان
فوق را بصورت زير فراخواني كنيم : READINT( distance);

اگر تعريف ماكرو شامل عبارتي طولاني باشد ( به طوري كه در يك خط قابل بيان
نباشد ) مي توان اون را در دو يا چند خط همچنين گفت .

بدين منظور بايد در انتهاي
هر خط ناتمام ، از كاراكتر \(back slash() هستفاده نمود .

دستور زير را در نظر
بگيريد : # define IS_EQU( y )y% 4==0 && y %100 != 0 || \
y%400=0

همانطور كه در دستور فوق مشاهده مي گردد در انتهاي اولين خط ، از كاراكتر \
هستفاده شد تا بتوان بقيه عبارت ماكرو را در خط بعدي تايپ نمود .


اگر ماكرايشان IS_EQU با پارامتري بنام year فراخواني گردد ، اين متغير بجاي y
برنامه خواهد گرفت .

يعني فراخواني : if( IS_EQU( year))

معادل دستور زير هست : if( year %4= 0 && year %100 != 0 || year %400 == 0)

در فراخواني ماكروها بايد دقت كافي بخرج داد تا از اجراي اونها نتيجه مطلوبي
بدست آيد .

بعنوان مثال ماكرايشان نوشته شده براي انجام عمل توان يك عدد را درنظر
بگيريد : # define SQURE( x )x*x

اكنون به دو فراخواني ماكرو SQURE توجه نماييد : S= SQURE(b( )1)

( با فراخواني فوق ، حاصل b*b در متغيري s برنامه مي گيرد كه منظور برنامه نايشانس
برآورده مي شود ) .

S= SQURE(x+1( )2)

در اثر اين فراخواني ، عبارت x+1 * x+1 ارزيابي شده و نتيجه اون در s برنامه
مي گيرد كه با توجه به تقدم عملگرها ( كه تفدم عمل ضرب (*) بيشتر از تقدم عمل
جمع (+) هست ) .

نتيجه ارزيابي ، با توان عدد x+1 برابر نيست .

براي رفع اين
مشكل دو راه حل وجود دارد : راه حل اول x+1 را در يك متغير برنامه داده و سپس
اون متغير را بعنوان پارامتر به ماكرو منتقل كرد .

راه حل دوم ماكرو را طوري
تعريف نمود كه از ايجاد اين اشتباه جلوگيري شود : # define SQURE(( x )*( x))

اكنون اگر ماكرايشان فوق با x+1 فراخواني گردد عبارت زير حاصل مي شود كه نتيجه
ارزيابي اون ، صحيح هست .

S=(( x+1 )*( x+1))


مثال 3: برنامه اي كه با هستفاده از يك ماكرو ، مساحت دايره اي را محاسبه
مي نمايد .

# define PI 3.14159
# define AREA(X( )PI*X*X)
main)(
{
float radius ;
printf("\n enter radius: " );
scanf("%f"/&radius );
printf("\n area is:" );
printf("%.2f "/AREA(radius ));
}

نمونه اي از خروجي برنامه مثال 3 :

7:

ضميمه كردن فايل ها (file inclusion)

در زبان C مي توان در حين ترجمه (compile) برنامه ، يك يا چند فايل را به اون
ضميمه كرده و مورد پردازش برنامه داد.

به فايلهايي كه بدين طريق به برنامه ضميمه
ميشوند، header file فرموده ميشود.

ضميمه كردن فايل ها، توسط دستور پيش پردازنده #include
انجام مي شود .

اين دستور بصورت هاي زير مورد هستفاده برنامه مي گيرد : "
اسم فايل #include "
<اسم فايل >#include
فايلهاي header مي توانند به دو دسته تقسيم شوند :
الف ) فايلهايي هستند كه همراه كامپايلر C وجود دارند و انشعاب همه اونها h.


هست .


ب ) فايلهايي هستند كه توسط هستفاده كننده نوشته مي شوند .


از روش اول هستفاده دستور # include براي ضميمه فايلهايي هستفاده مي شود كه
توسط هستفاده كننده نوشته شده اند و از روش دوم ، براي ضميمه فايل هايي به كار
گرفته مي شود كه همراه كامپايلر C وجود داشته و معمولا" در فهرستي بنام include
برنامه دارند .


فايلهاي header از اهميت ايشانژه اي برخوردارند زيرا : 1
بسياري از توابع مثل ()getchar و ()putchar در فايل هاي header مربوط به
سيستم ، بصورت ماكرو تعريف شده اند .

2
با فايل هاي header معمولي ( مربوط به هستفاده كننده ) علاوه بر تعريف
ماكروها ، مي توان از بسياري از تعاريف تكراري جلوگيري كرد .



مثال 1: دستور زير ، موجب ضميمه شدن فايل stdio.h به برنامه مي گردد .

# include

فرض كنيد كار ما طوري هست كه همواره برنامه هايي مينايشانسيم كه نياز به محاسبه
مساحت هاي اشكال مختلفي مثل دايره ، بيضي و غيره دارد .

بهتر هست براي سهولت
كار ، مساحت كليه اشكال را بصورت ماكرو تعريف كرده و در يك فايل header برنامه
دهيم .

سپس در ابتداي برنامه مورد نظر، اون را توسط دستور # include معرفي كنيم
تا به برنامه ضميمه شود .

نام فايل header را كه براي اين منظور نوشته مي شود h
.ar انتخاب كرده ، محتايشانات اون را مي توان بصورت زير نوشت : #define PI #.14159
#define AREA_CITCLE(radius )\
( PI*radius*radius)
#define AREA_SQUARE(length/width )\
( length*width)
#define AREA_TRIANGLE(base/height )\
( base*height/2)
#define AREA_ELLIPS(radius1/radius2 )\
( PI*radius1*radius2)
#define AREA_TRAPEZOID(heigth/side1/ \
side2( )heigth*(side1+side2)/2)

پس از تشكيل فايل ar.h مي توان با ضميمه نمودن اين فايل به هر برنامه اي كه
نياز به محاسبه مساحت اشكال هندسي ذكر شده در اين فايل را دارد ، از ماكروهاي
تعريف شده در اين فايل هستفاده كرد .



مثال 2: برنامه اي كه با هستفاده از فايل ar.h مساحت مثلثي را محاسبه ميكند.

#include
#include
main)(
{
int bas/height/s;
float s;
base=10;
height=15;
s=AREA-TRIANGLE(base/hight);
printf("%f"/s);
}

نمونه اي از خروجي برنامه مثال 2 : the area of triangle

8:

دستورات پيش پردازنده شرطي

در حالت معمولي ، دستورif براي تصميم گيري در نقاط مختلف برنامه بكار ميرود.


شرطهايي كه در دستور if ذكر مي شوند در حين اجراي برنامه ارزشيابي مي شوند .


يعني اگر شرط ذكر شده در دستور if چه درست باشد يا نادرست ، اين دستور و كليه
دستورات ديگر كه در بلاك if برنامه دارند ترجمه مي شوند .

ولي در دستورات پيش
پردازنده شرطي ، شرطي كه در اون ذكر مي شود در حين ترجمه ارزشيابي مي شود .


دستورات پيش پردازنده شرطي عبارتند از : # if/ # else/ # endif/ # ifdef/ # ifnder

دستور #if بصورت زير بكار مي رود :
عبارت شرطي # if
مجموعه دستورات # endif

عبارت شرطي كه در دستور # if ذكر مي شود ، عبارتي هست كه مقدار اون در وقت
ترجمه معلوم هست .

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

چنانچه داراي ارزش "
درستي " باشد مجموعه دستورات موجود در بين # if ( ابتداي بلاك ) و # endif
( انتهاي بلاك ) ترجمه خواهد شد وگرنه اين مجموعه دستورات ترجمه نمي گردد .



مثال 1: #include "stdio.h"
#define max 100
main)(
{
#if max>90
printf("compiled for array" );
printf(" qreater than 90\n");
#endif
}

خروجي برنامه مثال 1 : compiled for array greater than 90

وقتي برنامه مثال 1 ترجمه ميگردد شرط 90>MAX تست ميشود، چون اين شرط بربرنامه
هست ، دستور بعدي ترجمه شده و آماده اجرا مي گردد كه نتيجه اجراي اون را نيز
مشاهده نموديد .


نحوه عمل #else همانند else در دستور if هست ( مثال 2 ) .



مثال 2: #include "stdio.h"
#define max 10
main)(
{
#if max>99
printf("compiled for array...\n" );
#else
printf("compiled for small array" );
#endif
}

خروجي برنامه مثال 2 : compiled for small array

در برنامه مثال 2 چون شرط 99>MAX بربرنامه نيست ، لذا دستور سپس اون ترجمه
نميشود.

اما دستور بعداز #else ترجمه شده و پس از اجرا نتيجه زير حاصل ميگردد: "Compiled for small array"
#elif
مشابه دستور else if رفتار مي كند و بصورت زير هستفاده مي شود :
عبارت شرطي 1 # if
مجموعه دستورات 1
عبارت شرطي # elif 2
مجموعه دستورات 2
عبارت شرطي # elif 3
مجموعه دستورات 3 .


.


.



عبارت شرطي # elif n
مجموعه دستورات n # endif

همانطور كه ملاحظه مي شود ، هر # elif به همراه يك عبارت شرطي هست كه اگر
نتيجه ارزيابي اون ارزش " درستي " داشته باشد مجموعه دستورات مربوط به اون ترجمه
شده و كنترل به دستور بعداز# endif برمي گردد، وگرنه شرطهاي موجود در#elif هاي
بعدي مورد بررسي برنامه مي گيرند ، اگر هيچكدام از عبارات شرطي ذكر شده در اين
ساختار داراي ارزش " درستي " نباشند ، هيچيك از مجموعه دستورات 1تا nا ترجمه
نخواهد شد .



مثال 3: #define US 0
#define ENGLAND 1
#define IRAN g
#define ACTIVE_COUNTRY US
main)(
{
#if ACTIVE_COUNTRY==US
char currency[]="dolar";
#elif ACTIVE_COUNTRY==ENGLAND
char curreney[]="pound";
#else
char curreney[]="rials";
#endif
printf("\n currency is:");
printf("%s"/currency);
}

خروجي برنامه مثال 3 : currency is:dolar

هستفاده از #ifdefو #ifndefو روش ديگري براي پياده سازي ترجمه شرطي دستورات
هست ( #ifdef يعني "if defined"و #ifndefو يعني "if not defined" ) .


دستور #ifdef بصورت زير بكار مي رود :
نام ماكرو #ifdef
مجموعه دستورات #endif

اگر ماكرايشاني كه نام اون در جلايشان #ifndef ذكر شده هست در يك دستور #define
تعريف شده باشد در اين صورت مجموعه دستورات ذكر شده ، ترجمه خواهند شد وگرنه
اين دستورات ترجمه نمي گردند .


دستور # ifndef كه عكس دستور #ifedf عمل مي كند بصورت زير هستفاده مي شود :
نام ماكرو #ifndef
مجموعه دستورات #endif

اگر ماكرايشاني كه نام اون در جلايشان # ifndef ذكر شده هست در يك دستور # define
تعريف نشده باشد مجموعه دستورات ذكر شده ، ترجمه مي گردند وگرنه ترجمه نخواهند
شد .



مثال 4: #include "stdio.h"
#define TEN 10
main)(
{
#ifdef TEN
printf("\n TEN defined.");
#else
printf("\n TEN not defined.");
#endif
#ifndef ALPHA
printf("\n ALPHA is not defined.");
#endif
}

در برنامه مثال 4 دستور# ifedf تست مي كند كه آيا ماكرايشان TEN تعريف شده هست
يا خير .

چون اين ماكرو در اين برنامه تعريف شده هست ، دستور سپس اون ترجمه
شده و پس از اجراي نتيجه زير حاصل مي شود : TEN defined

دستور #ifndef تعريف يا عدم تعريف ماكرايشان ALPHA را تست مي كند كه چون اين كرو تعريف نشده هست موجب خروجي زير مي شود :

9:

حذف ماكروهاي تعريف شده

اگر در برنامه ، ماكرايشاني توسط دستور # define تعريف گردد ، دستور # undef
مي تواند از يك نقطه دلخواه برنامه ( از نقطه اي كه اين دستور برنامه مي گيرد )
به بعد ، تعريف ماكرو را بي اثر سازد .

اين دستور بصورت زير بكار مي رود :
<نام ماكرو># undef
تعريف ماكرايشاني كه نام اون در دستور # undef آمده هست از جايي كه اين دستور
در برنامه ظاهر مي گردد به بعد ، منتفي مي شود .



مثال : #define LEN 100
#define WIDTH 100
main)(
{
char array[LEN][WIDTH];
#undef LEN
#undef WIDTH
.


.


.


10:

اسامي ماكروهاي از پيش تعريف شده

اسامي تعداد 5 ماكرو ( قبلا"تعريف شده هست ) كه به همراه كامپايلر هستاندارد
زبان C وجود دارند ، عبارتند از : - LINE( -1
- FILE( -2
- DATE( -3
- TIME( -4
- STDC( -5

ماكرايشان -LINE- حاايشان شماره دستوري از فايل برنامه هست كه در حال ترجمه شدن
مي باشد .


ماكرايشان -FILE- حاايشان نام فايلي هست كه اكنون در حال ترجمه شدن مي باشد .


ماكرايشان -DATE- حاايشان رشته اي بصورت mm/dd/yy هست و حاايشان تاريخي هست كه فايل
برنامه ، ترجمه شده هست ( mm براي بيان ماه ، dd براي بيان روز و yy براي بيان
سال هست ) .


ماكرايشان -TIME- حاايشان رشته اي بصورت hh:mm:ss هست و شامل وقتي هست كه فايل
برنامه ، ترجمه شده هست ( hh براي بيان ساعت ، mm براي بيان دقيقه و ss براي
بيان ثانيه هست ) .


ماكرايشان -STDC- مشخص مي كند كه كامپايلر مورد هستفاده هستاندارد هست يا خير.


اگر محتايشانات اين ماكرو برابر با يك (1) باشد ، كامپايلر هستاندارد و در غير د هستاندارد نيست .


11:

دستور پيش پردازنده #line

دستور # line محتايشانات دو ماكرايشان -LINE و -FILE - را تغيير مي دهد .

دستور # line
به صورت زير بكار مي رود : "
نام فايل " <شماره > # line
شماره ، يك عدد صحيح مثبت هست كه مقدار جديد ماكرايشان -LINE- را مشخص مي كند
و " نام فايل " كه اختياري نيز هست ، محتايشانات جديد ماكرايشان -FILE- را تعيين
مي كند .

ماكرايشان # line براي اشكال زدايي برنامه مفيد هست .



مثال : #include "stdio.h"
#line 100
main)(
{
printf("\nprintf start at address:");
printf("%d\n"/_LINE)_;
}

در مثال بالا مقدار اوليه اي كه در ماكرايشان -LINE- برنامه مي گيرد برابر با 100
هست .

لذا شماره دومين دستورprintf برابر با 105 خواهد بود.

اين مطلب از خروجي امه كه چاپ محتايشانات ماكرايشان -LINE- هست مشخص مي گردد .


12:

دستور پيش پردازنده # error

دستور # error موجب جلوگيري از ادامه ترجمه برنامه توسط كامپايلر شده و به
زير بكار مي رود :
پيام خطا # error
پيام خطا ، جمله اي هست كه كامپايلر پس از رسيدن به اين دستور ، اون را بصورت
زير در صفحه نمايش ظاهر مي كند :
پيام خطا:Error directive شماره خط نام فايل :Error

مثال : main)(
{
int arr[4] / i ;
for( i=0 ; i < 100 ; i++)
{
if ( i > 4)
#error enter less than 20 ;
else
scanf("%d"/&arr[i] );
}

در حين ترجمه برنامه مثال بالا پيام زير صادر مي شود : Error directive : enter less than 20

13:

ساختمان ها

قبلا" مشاهده كرديم كه چگونه يك متغير ، يك قلم از داده را در خود نگهداري
مي كند و همينطور ديديم كه چگونه مي توان چند عنصر همنوع را در يك آرايه ذخيره
كرد .

گاهي لازم هست ، چند عنصر غير همنوع را تحت يك نام در حافظه ذخيره نمود .


ولي با مطالبي كه تاكنون فرموده شد انجام اين كار ممكن نيست .

بعنوان مثال ، اگر
بخواهيم اطلاعات مربوط به كارمندان موسسه اي را كه شامل نام كارمند ( از نوع
كاراكتري ) ، شماره كارمندي ( از نوع عدد صحيح ) ، حقوق ( از نوع عددي صحيح )
غيره هست ، تحت يك نام ذخيره كنيم .

در اين صورت متغير معمولي و آرايه جوابگايشان
نياز ما نيستند .

براي رفع اين مشكل در زبان C ، از نوعي داده به نام ساختمان
هستفاده مي شود .

بنابراين مي توان فرمود كه : " ساختمان " در زبان C نامي براي ه اي از متغيرها هست كه اين متغيرها مي توانند همنوع نباشند .


14:

تعريف نوع ساختمان

براي تعريف نوع ساختمان ، از دستور struct بصورت زير هستفاده مي شود : {
<نام ساختمان > struct
اجزاي ساختمان };

نام ساختمان ، از قانون نامگذاري براي متغيرها تبعيت مي كند.

اجزاي ساختمان
متغيرهايي هستند كه قسمتي از ساختمان مي باشند و همانند يك متغير معمولي و يا
آرايه بايد اسم و نوع هر كدام مشخص باشد.

به يك ساختمان نمونه كه براي نگهداري
اسم ، شماره كارمندي و حقوق كارمندان نوشته شده هست توجه نماييد : struct personel {
char name [31];
int person;
int salary;
};

در تعريف نوع ساختمان بايد موارد زير را در نظر داشت : 1
حرف { مي تواند در همان خطي كه دستور struct آمده هست نباشد .

2
دستور structبه ; ختم مي شود .


با مطالبي كه تاكنون فرموده شد، روش تعريف نوع ساختمان مشخص گرديد.

ولي تعريف
ساختمان براي هستفاده از اون كافي نيست .

بلكه پس از تعريف نوع ساختمان بايد
متغيرهايي از اين نوع را تعريف كرده وسپس اين متغيرها را در برنامه بكارگرفت .


براي روشن شدن موضوع ، يادآوري مي كنيم كه intو floatو دو نوع تعريف شده براي
كامپيوتر هستند كه بايد متغيرهايي از اين نوع ها تعريف و سپس از اونها هستفاده
گردد .

تعريف متغيرهايي از نوع ساختمان به دو روش امكان پذير هست :
روش اول ) پس از تعريف نوع ساختمان ، متغيرهاي از نوع ساختمان با دستور struct
تعريف مي شوند .


در اين روش از شكل كلي زير هستفاده مي شود : ;
نوع ساختمان <اسامي متغيرهاي ساختمان >struct "
نوع ساختمان " ، اسمي هست كه قبلا" در دستور struct ساختار اون مشخص شده
هست .

" اسامي متغيرهاي ساختمان " ، متغيرهايي را مشخص مي كند كه بايد از نوع
ساختماني كه اسم اون در نوع ساختمان مشخص شده هست باشد .

اگر تعداد اين متغيرها
بيش از يكي باشد با كاما از يكديگر جدا مي شوند .

بعنوان مثال ، دستور struct personel p1/p2;

دو متغير ساختمان به اسامي p1و p2و را تعريف مي كند كه از نوع ساختمان personel
هستند .


روش دوم ) در حين تعريف نوع ساختمان ( بلافاصله پس از تعريف نوع ) اسامي
متغيرهاي ساختمان مشخص مي گردند .


در اين روش از شكل كلي زير هستفاده مي شود .

{
اسم ساختمان struct
اجزاي ساختمان ;
اسامي متغيرهاي ساختمان }
در اين روش ، ذكر اسم ساختمان اجباري نيست .

در دستور زير دقت كنيد : struct {
char name [31];
int persno;
int salary;
} p1/p2;

دستور فوق دو متغير ساختمان به اسامي p1و p2و را تعريف مي كند كه ساختار خص شده هست .


15:

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

همانطوركه مشاهده شد هر ساختمان داراي چند جزئ هست كه براي دسترسي به هر يك
از اجزاي اون از روش كلي زير هستفاده مي شود :
<اسم متغير از نوع ساختمان >.<نام جزئ>
بعنوان مثال ، با فرض اين كه p1و p2و دو متغير از نوع ساختمان بوده و داراي 3
جزئ به اسامي name، person،و salaryو باشند ، دستورات زير موجب دسترسي به هر
يك از اجزاي متغير p1 مي شوند كه در مورد p2 نيز ميتوان به همين طريق عمل كرد: p1.name
p1.persno
p1.salary

اگر اجزاي ساختمان ، از نوع آرايه باشند ، ذكر انديس آرايه جهت دسترسي به
عناصر اون الزامي هست .

بعنوان مثال ، دستور زير را در نظر مي گيريم : struct student {
char name [31];
int cours [10];
int unit [10];
int grade [10];
int persno;
} st1.st2;

در دستور فوق بعضي از اجزاي ساختمان student بصورت آرايه اي تعريف شده اند .


دستورات زير موجب دسترسي به اجزاي متغير ساختمان st1 مي شوند : st1.cours [1]
st1.cours [i]
st1.name

همانطوركه مشاهده شد اگر اجزاي ساختمان رشته اي باشند ميتوان به تك تك عناصر
اون نيز دسترسي پيدا كرد (st1.name[i])
در مورد مقدار دادن به اجزاي ساختمان مي توان همانند يك متغير معمولي عمل
كرد .

لذا با فرض اين كه st1 متغير ساختماني باشد كه قبلا" تعريف شده هست
دستورات زير معتبر مي باشند : st1.persno=1243;( 1)
printf("\n %d"/st1.persno);( 2)
gets(st1.name);( 3)
for( i=0;i<10;i++( )4)
scanf("%d"/&st1.unit[i]);


مثال : برنامه اي كه دو عدد موهومي را از ورودي خوانده و مجموع اونها را
محاسبه مي كند و به خروجي مي برد .

main)(
{
struct complex
{
int real ;
int unreal ;
} comp1 / comp2 /result ;
printf("\n enter the real part");
printf(" for number %d:"/1);
scanf("%d"/&comp1.real );
printf("\n enter the unreal part");
printf(" for number %d:"/1 );
scanf("%d"/&comp1.unreal );
printf("\n enter the real part ");
printf(" for number %d:"/2 );
scanf("%d"/&comp2.real );
printf("\n enter the unreal part");
printf(" for number %d:"/2 );
scanf("%d"/&comp2.unreal );
result.real=comp1.real+comp2.real;
result.unreal=
comp1.unreal+comp2.unreal;
printf("\nthe result of sum is:");
printf("\nreal part=" );
printf("%d"/result.real);
printf("\n unreal part" );
printf("=%d"/result.unreal);
}

نمونه اي از خروجي برنامه مثال بالا : enter the real part for number 1:12
enter the unreal part for number 1:25
enter the real part for number 2:5
enter the unreal part for number 2:19

the result of sum is:

real part=17

un

16:

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

همانطوركه مشاهده شد هر ساختمان داراي چند جزئ هست كه براي دسترسي به هر يك
از اجزاي اون از روش كلي زير هستفاده مي شود :
<اسم متغير از نوع ساختمان >.<نام جزئ>
بعنوان مثال ، با فرض اين كه p1و p2و دو متغير از نوع ساختمان بوده و داراي 3
جزئ به اسامي name، person،و salaryو باشند ، دستورات زير موجب دسترسي به هر
يك از اجزاي متغير p1 مي شوند كه در مورد p2 نيز ميتوان به همين طريق عمل كرد: p1.name
p1.persno
p1.salary

اگر اجزاي ساختمان ، از نوع آرايه باشند ، ذكر انديس آرايه جهت دسترسي به
عناصر اون الزامي هست .

بعنوان مثال ، دستور زير را در نظر مي گيريم : struct student {
char name [31];
int cours [10];
int unit [10];
int grade [10];
int persno;
} st1.st2;

در دستور فوق بعضي از اجزاي ساختمان student بصورت آرايه اي تعريف شده اند .


دستورات زير موجب دسترسي به اجزاي متغير ساختمان st1 مي شوند : st1.cours [1]
st1.cours [i]
st1.name

همانطوركه مشاهده شد اگر اجزاي ساختمان رشته اي باشند ميتوان به تك تك عناصر
اون نيز دسترسي پيدا كرد (st1.name[i])
در مورد مقدار دادن به اجزاي ساختمان مي توان همانند يك متغير معمولي عمل
كرد .

لذا با فرض اين كه st1 متغير ساختماني باشد كه قبلا" تعريف شده هست
دستورات زير معتبر مي باشند : st1.persno=1243;( 1)
printf("\n %d"/st1.persno);( 2)
gets(st1.name);( 3)
for( i=0;i<10;i++( )4)
scanf("%d"/&st1.unit[i]);


مثال : برنامه اي كه دو عدد موهومي را از ورودي خوانده و مجموع اونها را
محاسبه مي كند و به خروجي مي برد .

main)(
{
struct complex
{
int real ;
int unreal ;
} comp1 / comp2 /result ;
printf("\n enter the real part");
printf(" for number %d:"/1);
scanf("%d"/&comp1.real );
printf("\n enter the unreal part");
printf(" for number %d:"/1 );
scanf("%d"/&comp1.unreal );
printf("\n enter the real part ");
printf(" for number %d:"/2 );
scanf("%d"/&comp2.real );
printf("\n enter the unreal part");
printf(" for number %d:"/2 );
scanf("%d"/&comp2.unreal );
result.real=comp1.real+comp2.real;
result.unreal=
comp1.unreal+comp2.unreal;
printf("\nthe result of sum is:");
printf("\nreal part=" );
printf("%d"/result.real);
printf("\n unreal part" );
printf("=%d"/result.unreal);
}

نمونه اي از خروجي برنامه مثال بالا : enter the real part for number 1:12
enter the unreal part for number 1:25
enter the real part for number 2:5
enter the unreal part for number 2:19

the result of sum is:

real part=17

un

17:

ارزش دهي اوليه به ساختمان

مي توان به متغيرهاي از نوع ساختمان كه داراي كلاس حافظه هستاتيك و خارجي
باشند ، همانند آرايه ها مقدار اوليه داد .

براي اين منظور مقادير اوليه در بين {
و} برنامه گرفته و با كاما از يكديگر جدا ميشوند.

مقاديري كه به متغير ساختمان
برنامه مي گيرند : اولين مقدار به اولين جزئ، دومين مقدار به دومين جزئ و n امين
مقدار به n امين جزئ نسبت داده مي شود .

اگر تعداد مقادير ، از تعداد اجزاي
متغير ساختمان كمتر باشند ، مقدار بقيه اجزاي عددي برابر با صفر و مقدار بقيه
اجزاي رشته اي برابر با NULL ( كاراكتر تهي ) خواهد شد .



مثال : ساختمان student را كه در زير آمده هست در نظر بگيريد : struct student {
char name[21] ;
char address[30] ;
int grade[10] ;
int stno ;
} s1/ s2 ;

اكنون مجموعه دستورات زير را ملاحظه نماييد : struct student st1={( 1)
"ali"/"mohammad"/
"{0}/15} ;

struct student st2={0} ;( 2)

struct student st3={( 3)
"ahmad"/
'\0'/{15/20}/0} ;

struct student st4={"reza"} ;( 4)

دستور (1) ، مقدار "ali"در nameر، "mohammad"،در addressر ، صفر در كليه
عناصر آرايه grade و 15در stnoر از متغير st1 برنامه مي گيرد .

در دستور (2)
كليه اجزاي عددي متغير st2 ، مقدار صفر و اجزاي كاراكتري ، مقدار تهي را
مي پذيرند ، در دستور (3) ، مقدار "ahmad"در nameر ، رشته تهي در address ، 15
و 20 بترتيب در محل هاي اول و دوم آرايه grade و صفر در stno متغير st3 برنامه
مي گيرد .

در دستور (4) ، مقدار "reza" در جزئ name از متغير st4 برنامه گرفته و ن متغير مقدار صفر و اجزاي غيرعددي مقدار تهي را مي پذيرند.


18:

نتساب ساختمانها به يكديگر

در گونه هاي اوليه زبان C ، انتساب يك ساختمان به ساختمان ديگر امكان پذير
نبود ولي در گونه هاي جديد C و همينطور در توربو C انتساب متغيرهاي ساختمان كه
از يك نوع باشند امكان پذير هست .



مثال : برنامه اي كه مشخصات چند دانشجو را بهمراه معدل اونها از ورودي خوانده
و سپس دانشجايشاني را كه دومين معدل را از نظر بزرگي دارد پيدا مي كند .

struct student {
char name[30] ;
float grade ;
} ;
main)(
{
int i / n ;
float y ;
struct student st1={0} ;
struct student st1={0}/ st ;
printf("\n enter the number " );
printf(" of student :" );
scanf("%d"/&n );
for( i=1 ; i <= n ; i++)
{
printf("\nenter name of student");
printf(" %d: "/i );
scanf("%s"/st.name );
printf("\nenter grade of student");
printf(" %d: "/i );
scanf("%f"/&y );
st.grade=y ;
if( st.grade > st1.grade)
{
st2=st1 ;
st1=st ;
}
else if( st.grade > st2.grade)
st2=st ;
}
printf("\nthe name of second ");
printf("student is: %s"/st2.name );
printf("\n\nthe grade of second" );
printf(" student is:" );
printf("%.2f"/st2.grade );
}

نمونه اي از خروجي برنامه مثال بالا : enter the number of student:5
enter name of student 1:ali
enter grade of student 1:12.6
enter name of student 1:sadegh
enter grade of student 2:18.2
enter name of student 3:reza
enter grade of student 3:14.5
enter name of student 4:mohammad
enter grade of student 4:12
enter name of student 5:ahmad
enter grade of student 5:15
the name of second student is:ahmad
the grade of second student is:15.00

19:

آرايه اي از ساختمانها

يكي از بيشترين موارد كاربرد ساختمانها ، تعريف شدن بصورت آرايه مي باشد .


براي تعريف آرايه اي از ساختمان ، ابتدا بايد نوع ساختمان را تعريف كرده وهمانند
تعريف متغيرهاي معمولي ، آرايه اي از اون نوع را تعريف نمود .

بعنوان مثال دستور struct personel st[100];

آرايه 100 عنصري st را كه هر عنصر اون از نوع ساختمان هستند تعريف مي كند .


اگر فرض شود كه persno يكي از اجزاي ساختمان personal باشد به طريق زير ميتوان
به اين جزئ دسترسي پيدا كرد و مقداري را به اون نسبت داد : st [i] .persno= 100;

دستور فوق موجب مي شود تا مقدار جزئ persno از عنصر i ام آرايه st برابر با 100
گردد .



مثال : برنامه اي كه مشخصات تعدادي از افراد را كه شامل نام و آدرس ( شامل :
خيابان ، شهر و ...

) هست ، از ورودي خوانده و در آرايه اي از ساختمان ها برنامه
مي دهد .

اين برنامه قادر هست : فردي را از آرايه حذف كند ، فرد جديدي را به
آرايه اضافه نمايد و محتايشانات كل آرايه را چاپ كند .

قبل از نوشتن اين برنامه
جهت درك صحيح اون ، ساختار سلسله مراتبي و وظايف هر يك از توابع شكل ( الف ) را
بيان مي كنيم :
ؤؤؤؤؤؤؤؤؤؤؤؤ | main )(|

ؤؤؤؤؤؤؤؤؤؤؤؤ |

ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤ
ؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ |menu_seletc)(| | enter )(| | delete )(| | list )(| |init_list )(|

ؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ |

ؤؤؤؤؤؤؤؤؤؤؤؤؤؤ |find_free )(|

ؤؤؤؤؤؤؤؤؤؤؤؤؤؤ
شكل ( الف ) .

نمودار سلسله مراتبي برنامه مثال

وظيفه تابع ()main : تعريف ساختمان ها ، توابع و فراخواني توابع مطابق شكل
( الف ) .


وظيفه تابع ()menu-slselect : ظاهر نمودن منايشاني در صفحه نمايش جهت انتخاب
نوع عمل برنامه .


وظيفه تابع ()enter : فراخواني تابع ()find-fefree جهت پيدا كردن جاي خالي
در آرايه ، مطالعهاطلاعات از صفحه كليد و وارد كردن اونها در جاي پيدا شده در
آرايه .


وظيفه تابع ()delete : حذف افراد از آرايه ( براي اين منظور اولين محل از
جزئ name را برابر با '\0' برنامه مي دهد ) .


وظيفه تابع ()list : نمايش محتايشانات كامل آرايه .


وظيفه تابع ()init-lslist : ارزش دهي به عناصر آرايه ( اولين محل از جزئname
را برابر با '\0' برنامه مي دهد ) .


وظيفه تابع ()find-fefree : پيدا كردن جاي خالي در آرايه جهت برنامه دادن
اطلاعات جديد در اون محل .

/* program example 8 - 4 */

#include "stdio.h"
#include "stdlib.h"
#define MAX 100
struct addr{
char name[10] ;
char street[15] ;
char city[10] ;
char state[3] ;
unsigned long int zip;
} addr_info[MAX] ;
void init_list(void)/enter(void );
void delete(void)/list(void );
int menu_select(void)/find_free(void);
main(void)
{
char choice / ch ;
init_list )(;
for(;{
choice=menu_select )(;
switch(choice)
{
case 1;
enter{} ;
break ;
case 2;
delete )(;
break ;
case 3;
list )(;
break ;
case 4;
exit(0 );
}
}
}
void init_list(void)
{
register int t ;
for(t=0 ; t addr_info[t].name[0]='\0' ;
}
menu_select(void)
{
char s[10] ;
int c ;
clrscr )(;
gotoxy(29.6 );
printf("1 )<< enter a name >>");
gotoxy(29.8 );
printf("2 )<< delete a name >>");
gotoxy(29.10 );
printf("3 )<< list the file >>");
gotoxy(29.12 );
printf("4 )<< Quit >>");
do {
gotoxy(24/15 );
printf(" Please enter your" );
printf(" choice(1-4");
gets(s );
c=atoi(s );
} while(c < 0 || c > 4 );
return( c );
}
void enter(void)
{
int slot ;
char s[80] ;
slot=find_free )(;
if(slot==-1)
{
printf("\n list full");
return ;
}
gotoxy(5/17 );
printf("enter name:" );
gets(addr_info[slot].name);

gotoxy(40/17 );
printf("enter street:" );
gets(addr_info[slot].street);

gotoxy(5/19 );
printf("enter city:" );
gets(addr_info[slot].city);

gotoxy(40/19 );
printf("enter state:" );
gets(addr_info[slot].state);

gotoxy(22/21 );
printf("enter zip:" );
gets(s );

addr_info[slot].zip=
strtoul(s/'\0'/10 );
}
find_free(void)
{
register int t ;
for(t=0 ; addr_info[t].name[0]
&& t < MAX ; ++t );
if(t==MAX )return- 1 ;
return t ;
}
void delete(void)
{
int slot ;
gotoxy(28/19 );
printf("enter record #(0-99");
scanf("%d"/&slot );
if(slot>=0 && slot addr info[slot].name[0]='\0';
}
void list(void)
{
register int t ;
int r=0 ;
char ch ;
clrscr )(;
gotoxy(25/2 );
printf(" << all information in");
printf(" list are:>>" );
gotoxy(13/3 );
printf("**********************");
printf("*******************" );
printf("********************" );
gotoxy(10/4 );
printf(" name street");
printf(" city " );
printf(" state zip");
printf(" " );
gotoxy(10/5);
;
("ؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤ ")printf ;
(" ؤؤؤؤؤؤ ")printf ;
("ؤؤؤؤ ؤؤؤؤؤؤؤ ")printf printf(" " );
for(t=0;t {
if(addr_info[t].name[0])
{
gotoxy(14/6+r );
printf("%s "/addr_info[t].name);
gotoxy(26/6+r );
printf("%s "/addr_info[t].street);
gotoxy(40/6+r );
printf("%s "/addr_info[t].city);
gotoxy(54/6+r );
printf("%s "/addr_info[t].state);
gotoxy(70/6+r );
printf("%1u "/addr_info[t].zip);
r++ ;
}
}
gotoxy(13/6+r );
printf("********************");
printf("*********************" );
printf("********************" );
gotoxy(27/7+r );
printf("press any key to continue");
ch=getch )(;
}

نكته اي كه در مورد برنامه مثال بالا بايد در نظر داشت اين هست كه در اين
برنامه از توابع كتابخانه اي ()gotoxy ، ()atoi و ()strtoul هستفاده شده هست .


نمونه اي از خروجي برنامه مثال بالا : 1 )<< enter a name >>
2 )<< delete a name >>
3 )<< list the file >>
4 )<< Quit >>

Please enter your choice(1-41

enter name:mohammad
enter street:daneshgah
enter city:mashhad
enter state:23
enter zip:123


1 )<< enter a name >>
2 )<< delete a name >>
3 )<< list the file >>
4 )<< Quit >>

Please enter your choice(1-42

enter name:naser
enter street:asrar
enter city:mashhad
enter state:34
enter zip:432


1 )<< enter a name >>
2 )<< delete a name >>
3 )<< list the file >>
4 )<< Quit >>

Please enter your choice(1-43

***************************************
name street city state zip
--- ------ ------ ------- --------
mohammad daneshgah mashhad 23 123
naser asrar mashhad 34 432
***************************************
press

20:

اجزاي يك ساختمان ميتوانند يك متغير معمولي ، آرايه و يا يك ساختمان باشند.


دو مورد اول را قبلا" مشاهده كرديم .

در اين قسمت به بررسي مورد سوم مي پردازيم .


وقتي كه اجزاي يك ساختمان از نوع ساختمان باشند براي دسترسي به اجزاي اون بايد
اسامي متغيرهاي ساختمان را از بالاترين ساختمان به داخلي ترين ساختمان ذكر كرد.



مثال : برنامه اي كه مشخصات چند كارمند را به همراه تاريخ هستخدام اونها از
ورودي خوانده و با اخذ تاريخ جاري ، سابقه خدمت كارمندان را محاسبه مي كند و
مشخصات كارمندي كه بيشترين سابقه خدمت را دارد به همراه توسط سن كارمندان به
خروجي منتقل مي كند .




#define MAX 100
main)(
{
int i / n /sumage=0 / maxold=0 ;
struct data {
int day ;
int month ;
int year ;
} today ;
struct employee {
char name [30];
int persno ;
struct data workdate ;
int age ;
int old ;
} emp[MAX] ;
struct employee maxemp={0} ;
printf("\n enter the number of");
printf(" employee: " );
scanf("%d"/&n );
printf("\n enter date" );
printf("(day month year" );
scanf("%d"/&today.day );
scanf("%d"/&today.month );
scanf("%d"/&today.year );
for( i=0 ; i < n ; i++)
{
printf("\n enter name:" );
scanf("%s"/emp[i].name );
printf("\n enter personel " );
printf("number: " );
scanf("%d"/&emp[i].persno );
printf("\n enter today date" );
pintf("(day month year" );
scanf("%d"/&emp[i].workdate.day );
scanf("%d"/&emp[i].workdate.month );
scanf("%d"/&emp[i].workdate.year );
printf("\n enter age: ");
scanf("%d"/&emp[i].age );
if( today.month <
emp[i].worldate.month ||
( today.month ==
emp[i].workdate.month &&
today.day >=
emp[i].workdate.day))
emp[i].old=today.year-
emp[i].workdate.year ;
else
emp[i].old=today.year-
emp[i].workdate.year - 1 ;
if( emp[i].old > maxold)
{
maxold=emp[i].old ;
maxemp=emp[i] ;
}
sumage+=emp[i].age ;
}
printf("\n the average of age");
printf(" is: %d"/sumage/n );
printf("\n the specification ");
printf("of a older person:" );
printf("\n the name is : ");
printf("%s"/maxemp.name );
printf("\n the persno is:");
printf("%d"/maxemp.persno );
printf("\n the age is :");
printf(": %d"/maxemp.age );
printf("\n the old is:");
printf("%d"/maxemp.old );
}

نمونه اي از خروجي برنامه مثال بالا : enter the number of employee:2
enter today date(day month year25 12 70
enter name:ahmad
enter personel number:1231
enter date(day month year12 2 60
enter age: 30
enter name:mohammad
enter personel number:4323
enter date(day month year2 12 55
enter age: 40

the average of age is:35
the specification of a older person:
the name is : mohammad
the persno is:4323
the age is :40
the old is: :o

21:

ساختمانها و يا آرايه اي ازساختمان كه تاكنون در برنامه ها بكار گرفته شده اند
يا بصورت عمومي تعريف شدند و يا درتابعي كه مورداستفاده برنامه مي گرفتند، تعريف
شدند .

ساختمانها و يا اجزاي اونها مي توانند به عنوان آرگومان ، به تابع منتقل
شده و يا اطلاعاتي را به تابع فراخواننده برگردانند .


براي انتقال اجزاي ساختمان به تابع ، همانند يك متغير معمولي عمل مي شود .


با اين تفاوت كه نام متغير ساختمان را بايد به همراه جزئ مورد نظر، در آرگومان
تابع ذكر كرد و بايد توجه داشت كه پارامتر تابع نيز بايد همنوع با آرگومان
متناظر با اون تعريف گردد .

بعنوان مثال ، ساختمان زير را در نظر بگيريد : struct student {
char x;
int ston;
char name[31];
} st1;

هر يك از دستورات زير موجب انتقال مقادير اجزاي متغير ساختمان st1 به تابعي
بنام ()func مي شوند .

func( st1.x);
func( st1.ston);
func( st1.name[5]);

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

براي توضيح بيشتر به مجموعه زير توجه نماييد : func( &st1.x);
func( &st1.ston);
func( &st1.name[5]);
func( st1.name);

همانطور كه در مجموعه دستورات فوق مشاهده مي گردد عملگر & بايد قبل از نام
متغير ساختمان ظاهر گردد ولي در آخرين دستور ، چون name يك آرايه هست ، براي
انتقال اون نيازي به عملگر & نيست .



مثال 1:

#include "stdio.h"
main)(
{
struct ss{
char name[20] ;
int x ;
} s ;
scanf("%s"/s.name );
scanf("%d"/&s.x );
test(s.name );
}
test(char *s)
{
while(*s)
{
printf("%c"/*s );
s++ ;
}
}


براي انتقال كامل متغيرهاي ساختمان به توابع بايد توجه داشت كه اين انتقال
از طريق فراخواني با ارزش ، صورت مي گيرد .


به هنگام انتقال كامل متغيرهاي ساختمان ، همنوع بودن آرگومان و پارامتر مهم
هست و برنامه نايشانس بايد اين مطلب را در نظر داشته باشد ( مثال 2 ) .



مثال 2: برنامه اي كه چگونگي تعريف پارامتر و آرگومان هاي ساختمان را نشان
مي دهد .




main)(
{
struct {
int a/b ;
char ch ;
} arg ;
arg.a=1000 ;
func(arg );
}
func(parm)
struct {
int x/y ;
char ch ;
} parm ;
{
printf("%d"/parm.x );
}


خروجي حاصل از اجراي برنامه مثال 2 عدد 1000 هست .

اگر چه تعريف پارامترها
و آرگومان هاي توابع جهت انتقال ساختمان ها بصورتي هست كه در مثال 2 آمده هست
صحيح مي باشند .

اين روش موجب طولاني شدن دستورات برنامه شده ، وقت بيشتري را
نيز مي طلبد .

براي انتقال ساختمان ها به توابع بهتر هست كه ساختمان ها بصورت
عمومي تعريف شوند و سپس بااستفاده از اين تعريف ، پارامترها ومتغيرهاي ساختمان
تعريف گردند .

با توجه به مطالبي كه فرموده شد ، مثال 2 را مي توان بصورتي كه در
مثال 3 آمده هست نوشت .





مثال 3: struct struct_type {
int a/b ;
char ch ;
} ;
main)(
{
struct struct_type arg ;
arg.a=1000 ;
func(arg );
}
func(parm)
struct struct_type parm ;
{
printf("\n %d"/parm.a );
}


پارامتر parm را در تابع ()func علاوه بر اونچه كه در مثال 3 آمده هست ، به
طريق زير نيز مي توان تعريف كرد : func( struct struct_type parm)


مثال 4: برنامه اي كه چگونگي انتقال كامل يك ساختمان را به تابع و انتقال
اطلاعات از طريق ساختمان به تابع فراخواننده را نشان مي دهد .


struct personel
{
char name[30] ;
int agnumb ;
} ;
main)(
{
struct personel agent1 / agent2 ;
struct personel newname )(;
agent1=newname )(;
agent2=newname )(;
list(agent1 );
list(agent2 );
}
struct personel newname)(
{
char numstr[80] ;
struct personel agent ;
printf("\n\t << New agent >> \n");
printf("Enter name: " );
gets(agent.name );
printf("\n agent number(3 digit)");
gets(numstr );
agent.agnumb=atoi(numstr );
return(agent );
}
list(age)
struct personel age ;
{
printf("\n\t<< agent: >>\n" );
printf("\n Name : %s \n"/age.name);
printf("\n agent number: ");
printf(" %3d\n"/age.agnumb );
}


نمونه اي از خروجي برنامه مثال 4 :


<< New agent >>
Enter name:reza

agent number(3 digit )213

<< New agent >>
Enter name:mohammad

agent number(3 digit )123

<< agent : >>

Name:reza

agent number: 213

<< agent : >>

Name:mohammad

a

22:

در زبان C تعريف اشاره گر از نوع ساختمان ، همانند تعريف ساير انواع اشاره گرها
امكان پذير هست .

اشاره گر ساختمان به دو منظور هستفاده مي شود : 1
امكان فراخواني به روش ارجاع در توابعي كه داراي آرگومان از نوع ساختمان
هستند را فراهم مي كند .

2
براي ايجاد ليست هاي پيوندي و ساير ساختمان داده هايي كه با تخصيص حافظه
پايشانا سر و كار دارند بكار مي رود .


وقتي كه ساختمان ها از طريق فراخواني به روش ارجاع به توابع منتقل مي شوند
سرعت انجام عمليات بر رايشان اونها بيشتر مي گردد.

لذا در حين فراخواني توابع بهتر
هست بجاي ساختمان ، آدرس اون را منتقل نمود.

عملگر& براي مشخص كردن آدرس ساختمان
( همانند ساير متغيرها ) مورد هستفاده برنامه مي گيرد .


تعريف اشاره گرهاي ساختمان همانند تعريف متغيرهاي ساختمان هست .

بااين تفاوت
كه در جلايشان اسم متغير ، علامت * برنامه مي گيرد.

بعنوان مثال ، ساختمان زير را در
نظر بگيريد : struct bal {
float balance ;
char name[80] ;
} person ;
struct bal *p;

در مجموعه دستورات فوق ، person يك متغير ساختمان وp يك اشاره گر به ساختمان
تعريف شده هست .

لذا دستور p= &person;

آدرس متغير ساختمان person را در اشاره گر p برنامه مي دهد .

براي دسترسي به
محتايشانات اجزاي ساختمان از طريق اشاره گر، بايد اشاره گر را در داخل پرانتز محصور
نمود .

بعنوان مثال دستور ( *p.)balance

موجب دسترسي به عنصر balance از ساختمان person ميشود.

علت برنامه دادن متغير
اشاره گر ساختمان در پرانتز ، اين هست كه تقدم عملگر نقطه (.) از عملگر * بالاتر
هست .


بطور كلي براي دسترسي به اجزاي ساختماني كه يك اشاره گر به اون اشاره مي كند
به دو روش مي توان عمل كرد : 1
ذكر نام اشاره گر در داخل پرانتز و سپس نام عنصر مورد نظر كه با نقطه از
هم جدا مي شوند ( مثل دسترسي به عنصر balance از ساختمان person توسط اشاره گر ( .

p
2
ؤؤ كه روش مناسب تري هست .

اگر بخواهيم با هستفاده از > هستفاده از عملگر
ؤؤ به عنصر >عملگر balance از ساختمان person دسترسي داشته باشيم بايد به طريق
زير عمل كنيم : balance
ؤؤ > p

مثال 1: برنامه اي كه با هستفاده از اشاره گرهاي ساختمان ، يك timer را شبيه
سازي مي كند .



struct tm
{
int hours ;
int minutes ;
int second ;
} ;
main)(
{
struct tm time ={0} ;
for( ;
{
update( &time );
display( &time );
}
}
update( struct tm *t)
{
( *t.)second ++ ;
if(( *t.)second == 60)
{
( *t.)second=0 ;
( *t.)minutes ++ ;
}
if(( *t.)minutes == 60)
{
( *t.)minutes=0 ;
( *t.)hours ++ ;
}
if(( *t.)hours==24)
( *t.)hours=0 ;
delay )( ;
}
display(struct tm *t)
{
gotoxy(70/2 );
printf("\n%2d:"/(*t.)hours );
printf("%2d:"/(*t.)minutes );
printf("%2d"/(*t.)second );
}
delay)(
{
long int t ;
for( t=1 ; t < 128000 ; ++t );
}


همانطور كه در مثال 1 مشاهده مي شود براي دسترسي به اجزاي ساختمان از عملگر *
ؤ ، تابع ()> هستفاده شده هست كه جهت آشنايي با عملگر update را با اين عملگر
بازنايشانسي مي كنيم :

update( struct tm *t)
{
second ++
;
ؤ> t
(َsecond == 60ؤ> t) if {
;
َsecond=0ؤ> t minutes ++
;
ؤ> t }

(َminutes == 60ؤ> t) if {
;
َminutes=0ؤ> t ;
hours ++ؤ> t }

(َhours==24ؤ> t) if ;
َhours=0ؤ> t delay )( ;
}



مثال 2: برنامه اي كه مشخصات مربوط به تعدادي از دانشجايشانان را خوانده و در
آرايه اي از ساختمان ها برنامه مي دهد .

مشخصات دانشجو عبارتند از: 1 نام دانشجو 2
شماره دانشجايشاني 3 تعداد درس ترم جاري 4 نمره هر درس .

اين برنامه پس از
مطالعهاطلاعات دانشجو معدل اونها را نيز محاسبه مي كند و در آرايه برنامه مي دهد.


امكان حذف دانشجايشاني از آرايه ، مشاهده اطلاعات يك يا چند دانشجو ، پيدا كردن
دانشجايشانان مشروط ( معدل كمتر از 12 ) و دانشجايشانان ممتاز ( معدل بالاتر از 17 )
از جمله وظايف اين برنامه هست .


قبل از مشاهده ليست كامل برنامه ، نمودار سلسله مراتبي اون را رسم كرده ( شكل
الف ) و وظايف هر يك از توابع را تشريح مي كنيم :


ؤؤؤؤؤؤؤؤؤؤؤؤؤؤ | main )(|

ؤؤؤؤؤؤؤؤؤؤؤؤؤؤ
ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤ
ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ |init_list)(||delete)(|| list)(||list1)(||list2)(||enter)(||menu_select)(|

ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ | | | |

ؤؤؤؤؤؤؤؤؤؤؤؤؤ| | ؤؤؤؤؤؤؤؤؤؤؤ |
()||find_free |ؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤ
ؤؤؤؤؤؤؤؤؤؤؤؤؤ| ||()| |print()|title |
|ؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤ | |
|
ؤؤؤؤؤؤؤؤؤؤؤ |
ؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤ |title)(| |print)(||
|
ؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤ |

ؤؤؤؤؤؤؤؤؤؤؤ
ؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤ |title)(| |print)(|

ؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤ

شكل الف .

نمودار سلسله مراتبي برنامه مثال 2

وظيفه تابع ()main : تعريف بعضي از متغيرها و فراخواني توابع ديگر مطابق
نمودار سلسله مراتبي شكل الف .


وظيفه تابع init-list : در ابتداي تابع main فراخواني شده و با NULL كردن
اولين محل جزئ name ، آرايه را ارزش دهي مي كند .


وظيفه تابع ()enter : ورود اطلاعات به آرايه .


وظيفه تابع ()delete : اين تابع براي حذف ركوردهايي از آرايه مورد هستفاده
برنامه ميگيرد.

براي اين منظور اولين محل جزئ name را برابر با NULL برنامه ميدهد.


وظيفه تابع ()list : بررسي آرايه ، جهت انتقال كامل اطلاعات اون به خروجي با
هستفاده از دو تابع ()title و ()print .


وظيفه تابع ()list1 : بررسي آرايه ، جهت پيدا كردن دانشجايشانان مشروط و انتقال
اطلاعات اين دانشجايشانان به خروجي ، توسط دو تابع ()title و ()print .


وظيفه تابع ()list2 : بررسي آرايه ، ئهت پيدا كردن دانشجايشانان ممتاز و انتقال
اطلاعات اونها به خروجي ، توسط دو تابع ()title و ()print .


وظيفه تابع ()menu-select : ظاهر نمودن منايشاني در صفحه نمايش جهت درخواست
انجام كار از برنامه .


وظيفه تابع ()find-free : پيدا كردن اولين محل خالي آرايه جهت برنامه دادن
اطلاعات جديد در اون توسط تابع ()enter .


وظيفه تابع ()title : چاپ عنوان براي خروجي .


وظيفه تابع ()print : چاپ اطلاعات موجود در آرايه در صفحه نمايش .



#include "stdio.h"
#include "stdlib.h"
#define MAX 100
struct student {
char name[10] ;
float mead ;
int unit ;
int number ;
int stno;
} st_info[MAX] ;
float x ;
int r=0 ;
void init_list(void)/enter(void );
void delete(void)/list(void)/list1)(/list2)(;
int menu_select(void)/find_free(void );
float sumgrade ;
int sumunit ;
int unit1/t ;
main(void)
{
char choice ;
init_list )(;
for(;{
choice=menu_select )(;
switch(choice)
{
case 1:
enter )(;
break ;
case 2:
delete )(;
break ;
case 3:
list )(;
break ;
case 4:
list1 )(;
break ;
case 5:
list2 )(;
break ;
case 6:
exit(0 );
}
}
}
void init_list(void)
{
register int n ;
for(t=0 ; t st_info[t].name[0]='\0' ;
}
menu_select(void)
{
char s[10] ;
int c ;
clrscr )(;
gotoxy(29/3 );
printf("1 )<< enter a name >>");
gotoxy(29/5 );
printf("2 )<< delete a name >>");
gotoxy(29/7 );
printf("3 )<< list the file >>");
gotoxy(29/9 );
printf("4 )<< list for probation >>");
gotoxy(29/11 );
printf("5 )<< list for exelent >>");
gotoxy(29/13 );
printf("6 )<< Quit >>");
do {
gotoxy(27/15 );
printf(" Please enter your " );
printf("choice(1-6 " );
gets(s );
c=atoi(s );
} while(c < 0 || c > 6 );
return( c );
}
void enter(void)
{
float grade ;
int slot /j ;
char s[80] ;
sumgrade=0 ;
sumunit=0 ;
slot=find_free )(;
if(slot==-1){
printf("\n list full" );
return ;
}
gotoxy(5/17 );
printf("enter name:" );
gets(st_info[slot].name );

gotoxy(5/18 );
printf("enter stno:" );
scanf("%d"/&st_info[slot].stno );

gotoxy(5/19 );
printf("enter number:" );
scanf("%d"/&st_info[slot].number );
for(j=1;j<=st_info[slot].number;j++)
{
gotoxy(40/17 );
printf(" ");
gotoxy(40/17 );
printf("enter grade number %d:"/j);
scanf("%f"/&grade );
gotoxy(40/19 );
printf(" ");
gotoxy(40/19 );
printf("enter unit of grade %d:"/j);
scanf("%d"/&unit1 );
sumgrade+=grade*unit1 ;
sumunit+=unit1 ;
}
st_info[slot].mead=sumgrade/sumunit ;
st_info[slot].unit=sumunit ;
}
find free(void)
{
register int t ;
for(t=0;st_info[t].name[0] &&
t < MAX ; ++t);
if(t==MAX )return- 1 ;
return t ;
}
void delete(void)
{
int slot ;
gotoxy(28/19 );
printf("enter record #(0 - 99" );
scanf("%d"/&slot );
if(slot <= 0 && slot < MAX)
st_info[slot].name[0]='\0' ;
}
void list(void)
{
char ch ;
clrscr )(;
r=0 ;
title ;
for(t=0;t if(st_info[t].name[0])
print )(;
}
gotoxy(13/6+r );
printf("******************************");
printf("*******************************" );
gotoxy(27/7+r );
printf("press any key to continue " );
getch)(;
}
void list1(void)
{
char ch ;
r=0 ;
clrscr )(;
title )(;
for(t=0;t if(st_info[t].name[0] && st_info[t].mead<12)
print)(
}
gotoxy(13/6+r );
printf("******************************");
printf("*******************************" );
gotoxy(27/7+r );
printf("press any key to continue " );
getch)(;
}
void list2(void)
char ch ;
r=0 ;
clrscr )(;
title )(;
for(t=0;t if(st_info[t].name[0] && st_info[t].mead<17)
print)(
}
gotoxy(13/6+r );
printf("******************************");
printf("*******************************" );
gotoxy(27/7+r );
printf("press any key to continue " );
getch)(;
}
title)(
{
gotoxy(25/2 );
printf(" << information in list");
printf("are :>>");
gotoxy(13/3 );
printf("*************************");
printf("****************");
printf("********************");
gotoxy(10/4 );
printf(" name mead ");
printf(" unit " );
printf(" number ");
printf(" stno " );
gotoxy(10/5);
;
(" ؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤ ")printf ;
(" ؤؤؤؤؤ ")printf ;
(" ؤؤؤؤ ؤؤؤؤؤ ")printf }
print)(
{
gotoxy(14/6+r );
printf("%s "/st_info[t].name );
gotoxy(26/6+r );
printf("%.2f "/st_info[t].mead );
gotoxy(40/6+r );
printf("%d "/st_info[t].unit );
gotoxy(54/6+r );
printf("%d "/st_info[t].number );
gotoxy(70/6+r );
printf("%u "/st_info[t].stno );
r++ ;
}


نمونه اي از خروجي برنامه مثال 2 : 1 )

<< enter a name >>
2 )<< delete a name >>
3 )<< list the file >>
4 )<< list for probation >>
5 )<< list for exelent >>
6 )<< Quit >>

Please enter your choice(1-61

enter name:ali enter grade number 1:19
enter stno:123 enter unit of grade 1:2
enter number:2 enter grade number 2:18
enter unit of grade 2:3

1 )<< enter a name >>
2 )<< delete a name >>
3 )<< list the file >>
4 )<< list for probation >>
5 )<< list for exelent >>
6 )<< Quit >>

Please enter your choice(1-62

enter name:reza enter grade number 1:12
enter stno:321 enter unit of grade 1:3
enter number:3 enter grade number 2:11
enter unit of grade 2:2
enter grade number 3:10
enter unit of grade 3:4

1 )<< enter a name >>
2 )<< delete a name >>
3 )<< list the file >>
4 )<< list for probation >>
5 )<< list for exelent >>
6 )<< Quit >>

Please enter your choice(1-63

<< information in list are :>>
***************************************
name mead unit number stno
----- ------ ---- ---- ------
ali 18:00 5 2 123
reza 10:00 9 3 321
***************************************
press any key to continue

1 )<< enter a name >>
2 )<< delete a name >>
3 )<< list the file >>
4 )<< list for probation >>
5 )<< list for exelent >>
6 )<< Quit >>

Please enter your choice(1-65

<< information in list are :>>
***************************************
name mead unit number stno
----- ------ ---- ---- ------
ali 18:00 5 2 123
***************************************
press any key to continue

1 )<< enter a name >>
2 )<< delete a name >>
3 )<< list the file >>
4 )<< list for probation >>
5 )<< list for exelent >>
6 )<< Quit >>

Please enter your choice(1-64

<< information in list are :>>
***************************************
reza 10:00 9 3 321
***************************************
press any key to continue

1 )<< enter a name >>
2 )<< delete a name >>
3 )<< list the file >>
4 )<< list for probation >>
5 )<< list for exelent >>
6 )<< Quit >>

23:

در زبان C برخلاف ساير زبانهاي برنامه سازي ، به يك بيت خاص از يك بايت حافظه
مي توان دسترسي پيدا كرد .

اين امر در زبان C به دلايل زير مفيد هست : 1
اگر محدوديتي در ميزان حافظه وجود داشته باشد، ميتوان از يك بايت بعنوان
چند متغير منطقي هستفاده نمود .

براي اين منظور مي توان هر بيت را بعنوان يك
متغير منطقي در نظر گرفت كه مقدار صفر به معني ارزش " درستي " و مقدار يك به
معني ارزش " نادرستي " و يا برعكس باشند .

2
در حين ارتباط كامپيوتر با دستگاه هاي خارجي ، بعضي از رابط ها مي توانند
اطلاعات موجود در يك بايت را ( كه هر بيت اون ممكن هست تفسير خاصي داشته باشد )
انتقال دهند .

3
بسياري از زيربرنامه هاي سيستم ( كه معمولا" از ديد ما پنهان هستند ) نياز
به دسترسي به بيت ها دارند .


اگر چه همه اعمال فوق توسط عملگرهاي بيتي قابل انجامند ، ولي ساختمان هاي
بيتي ، روش مناسب تر و بهتري براي برآوردن اين اهداف هستند .

بطور كلي مي توان
فرمود كه ساختمان بيتي ، مكانيزم ساختماني جهت دسترسي به بيت هاي يك بايت از
حافظه هست .


روش كلي تعريف ساختمان بيتي به صورت زير هست : {
نام ساختمان بيتي struct ;
طول فيلد >1نام فيلد >: <1نوع فيلد > <1 <;
طول فيلد >2نام فيلد >: <2نوع فيلد > <2 <.


.


.


;
طول فيلد >nنام فيلد >: اسامي متغيرهاي بيتي }
نام ساختمان بيتي از قانون نامگذاري براي متغيرها تبعيت مي كند .

هر يك از
فيلدها در ساختمان بيتي مي توانند از نوع int، unsigned، و يا signed باشد .


فيلدي كه طول اون 1 باشد يايد از نوع unsigned انتخاب گردد .

زيرا بيت با طول 1
نميتواند شامل علامت هم باشد.

طول فيلدها در ساختمان بيتي به بيت سنجيده ميشود.


يعني طول فيلد مشخص مي كند كه فيلد مورد نظر چند بيتي هست .


بعنوان مثال ساختمان بيتي زير را در نظر بگيريد :

struct device {
unsigned active :1 ;
unsigned ready :1 ;
unsigned xmt_error :1 ;
} dev_code ;


ساختمان 3 device فيلد كه طول هر كدام يك پيت هست را تعريف مي كند و متغير dev-code
از نوع ساختمان بيتي device تعريف شده هست .

متغير dev-code بصورت اون
چه كه در شكل (1) مشاهده مي شود در حافظه برنامه مي گيرد .


يك بايت
ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤ | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7
|
شماره بايت
ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤ
< بالا هستفاده ؤؤؤ<ؤؤؤ| | | | | |
dev-code/xxmt-error
ؤؤؤؤؤ | | dev-code/rready
ؤؤؤؤؤؤؤؤؤ | dev-code aactive
ؤؤؤؤؤؤؤؤؤؤؤؤؤ
شكل (1) .

وضعيت متغير dev-code

همانطور كه در شكل (1) مشاهده مي گردد براي دسترسي به اجراي متغير ساختمان
بيتي از عملگر نقطه (.) هستفاده مي گردد .

اگر اشاره گري به ساختمان بيتي اشاره
ؤؤ به اجزاي اين >نمايد ، همانند ساختمان معمولي مي توان با هستفاده از عملگر
ساختمان دسترسي پيدا كرد .


يكي از موارد كاربرد ساختمان هاي بيتي ، درتجزيه و تحليل اطلاعات اخذ شده از
يك دستگاه سخت افزاري هست .

بعنوان مثال ، پورت وضعيت يك تطبيق دهنده ارتباط
سري ، يك بايت وضعيت ، با ساختار زير را برمي گرداند :
شماره بيت مفهوم بيت ( وقتي كه 1 باشد )


change clear_to_send line 0
change in data_set_ready 1
trailing edge detected 2
change in recive line 3
clear_to_send 4
data_set_ready 5
telephone ringing 6
received signal 7


بايت وضعيت مربوط به تطبيق دهنده ارتباط سري را مي توان با هستفاده از
ساختمان بيتي تعريف كرد :

struct stalus_type {
unsigned delta_cts :1 ;
unsigned delta_dsr :1 ;
unsigned tr_edge :1 ;
unsigned delta_rec :1 ;
unsigned cts :1 ;
unsigned dsr :1 ;
unsigned ring :1 ;
unsigned rec_line :1 ;
} status;


براي هستفاده از ساختار بيتي status كافي هست كه زير برنامه اي نوشته شود تا
اطلاعات فرستاده شده را بخواند و سپس اون را تجزيه و تحليل و بررسي نمايد : status=get_port_status)(;

در دستور فوق ()get_port_status تابعي هست كه پورت وضعيت را خوانده و در
متغير ساختمان بيتي status برنامه مي دهد .


بعضي از نكاتي كه در مورد متغيرهاي از نوع ساختمان بيتي بايد در نظر داشت
عبارتند از : 1
نمي توان به آدرس اونها مراجعه كرد 2
نمي توانند بصورت آرايه تعريف شوند 3
به حد زيادي ، وابسته به ماشين هستند، بعنوان مثال ممكن هست در يك ماشين
بيت ها از چپ به راست قابل دسترسي باشند و در ماشين ديگر از راست به چپ .

4
تركيبي از ساختمان بيتي و ساختمان معمولي ، ممكن هست :

struct emp {
struct addr address1 ;
float pay ;
unsigned lay-off :1 ;
unsigned hourly :1 ;
unsigned shifted :1 ;
} ;


در ساختمان emp ، فيلد address1 از نوع ساختمان address تعريف شده هست كه
اين ساختمان مي تواند بصورت زير تعريف شود :

struct address {
char zip ;
char street [31] ;
char city [31] ;
} ;


نكته اي كه در مورد ساختمان emp بايد توجه داشت اين هست كه از يك بايت براي
نگهداري 3 قلم اطلاعات ( اجزاي lay-off، hourly،و shiftedو ) هستفاده شده هست .


اگر از ساختمان بيتي هستفاده نميشد حداقل به 3 بايت نياز بود ( اگر اين بايت ها
بصورت كاراكتري تعريف مي شدند ) .



مثال : برنامه اي كه چگونگي هستفاده از ساختمان هاي بيتي را نشان مي دهد .



struct date
{
unsigned int day: 5 ;
unsigned int month: 4 ;
unsigned int year: 7 ;
} ;
main)(
{
struct date dateofbirth / today ;
int age ;
char p1[40] / p2[40] ;
clrscr )(;
strcpy(p1/
"enter birth date( day month year");
strcpy(p2/
"enter today date(day month year: )");
askfordate(p1 / &dateofbirth );
askfordate(p1 / &today );
if( today.month > dateofbirth.month ||
( today.month == dateofbirth.month &&
today.day > dateofbirth.day))
age=today.year - dateofbirth.year ;
else
age=today.year - dateofbirth.year- 1;
printf("\n the age is %d year."/age);
}
askfordate(char *prompt /
struct date *point)
{
unsigned int d/m /y ;
printf("%s"/prompt );
scanf("%d%d%d"/&d/&m/&y );
day ==d
;
ؤ>point month=m
;
ؤ>point year =y
;
ؤ>point }


نمونه اي از خروجي برنامه مثال بالا :

enter birth date(day month year12 12 50
enter t

24:

، محلي از حافظه هست كه توسط دو يا چند متغير بطور اشتراكي
مورد هستفاده برنامه مي گيرد .

اين متغيرها بطور هموقت نمي توانند از اين محل
هستفاده كنند بلكه هر متغير مي تواند در وقت هاي متفاوتي اين محل را مورد
هستفاده برنامه دهد .


نحوه تعريف union همانند ساختمان هست و شكل كلي اون بصورت زير هست : {
اسم > union اجزاي union ;
اسامي متغيرها }
اسم union از قانون نامگذاري براي متغيرها تبعيت ميكند.

اجزاي union همانند
اجزاي ساختمان تعريف مي شوند و چگونگي تعريف متغيرهاي union نيز مثل تعريف
متغيرهاي ساختمان هست .

طول يك union به اندازه مجموع طول اجزاي اون نيست بلكه
به اندازه طول عنصري هست كه بيشترين طول را دارد، زيرا در واقع union ساختماني
هست كه آدرس شروع كليه اجزاي اون از يك نقطه هست .

union زير را در نظر بگيريد:


union u_type {
int i ;
char ch ;
float y ;
} ;


در تعريف u-type، 3، عنصر به اسامي i، ch،و yو تعريف شده اند .

در اين union
چون طول y از طول ساير اجزائ بيشتر هست ( طول int برابر با 2 بايت ، طول char
برابر با 1 بايت و طول float برابر با 4 بايت هست ) طول u-type برابر با طول y
يعني 4 در نظر گرفته مي شود ( مثال ) شكل (1) نحوه هستفاده اجزاي i، chو yو را
از يك محل حافظه به طول 4 بايت نشان مي دهد .


ؤؤؤؤ >y < ؤؤؤؤ
ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ | 0 | 1 | 2 | 3
|
شماره بايت
ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ch
< ؤ
ؤؤ >i < ؤؤ
شكل (1) .

نحوه هستفاده اجزاي union از حافظه

مثال :

main)(
{
union test {
int i ;
char ch ;
float y ;
} un ;
float x ;
printf("\n enter an integer number:");
scanf("%d"/&un.i );
printf(" the value of i is: %d/un.i);
printf("\n enter a character: " );
un.ch=getche )(;
printf("\n value of ch is:%c"/un.ch);
printf("\n enter a float number: ");
scanf("%f"/&x );
un.y=x ;
printf("the value of y is:%.2f"/un.y);
printf("\n\n the size of union is:");
printf("%d"/sizeof(union test ));
}


نمونه اي از خروجي برنامه مثال بالا :

enter an integer number:43
the value of i is:43
enter a character:f
the value of ch is:f
enter a float number:23.65
the value of y is:23.65
the size of u

25:

قبلا" مشاهده شد كه اجزاي يك ساختمان مي توانند ، از نوع ساختمان باشند .

به
طور كلي بكارگيري يك ساختمان در ساختمان ديگر ، union در يك ساختمان و برعكس و union
در unionر ديگر امكان پذير هست .



مثال :

main)(
{
struct twoint {
int num1:
int num2:
} ;
union intflo {
struct twoint test ;
float flonum ;
} unex ;
printf("\n size of union is: " );
printf("%d"/sizeof(union intflo));
unex.test.num1=564 ;
unex.test.num2=-231 ;
printf("\n unex.test.num1=");
printf("%d"/unex.test.num1 );
printf("\n unex.test.num2=");
printf("%d"/unex.test.num2 );
unex.flonum=45.76 ;
printf("\n unex.flonum=");
printf("%.2f"/unex.flonum );
}


نمونه اي از خروجي برنامه مثال بالا :

size of union is: 4
unex.test.num1=564
unex.test.num2=-231
unex.flonum=45.76

26:

دستور typedef براي تعايشانض نام نوع موجود هستفاده مي شود .

بدين معني كه با
هستفاده از اين دستور مي توان براي نوع هاي ابتدايي مثل intو charو و ...

و
همينطور نوع هاي تعريف شده در برنامه ، اسم ديگري انتخاب نمود .

اين دستور به
دو دليل اهميت دارد : 1
موجب ميشود تا مساله قابل حمل بودن زبان C قوت بيشتري پيدا كند.يعني اگر
برنامه اي را در يك ماشين نوشته و بخواهيم اون را در ماشين ديگري اجرا كنيم
چنانچه اين دو ماشين با يكديگر مطابقت نداشته باشند كافي هست دستور typedef
طوري عوض شود كه اين مشكل را حل نمايد .

2
موجب مي شود تا براي نوع هاي داده طولاني ، اسم ساده تري انتخاب گردد .


دستور typedef بصورت زير بكار مي رود :
<نوع موجود> <اسم جديد>typedef
نوع موجود ، يكي از انواع معتبر در زبان C هست .

اسم جديد، نامي هست كه نوع
موجود ، در برنامه باشد به اين نام خوانده شود .

دستور زير را در نظر بگيريد : unsigned int var1/ var2;

اين دستور موجب ميشود تا متغيرهاي var1و var2و از نوع " صحيح مثبت " انتخاب
شوند .

با هستفاده از دستور typedef براي unsigned int به طريق زير اسم جديدي
انتخاب مي كنيم : typedef unsigned int SUBINT ;

دستور فوق موجب مي شود تا بتوان بجاي عبارت unsigned intازSUBINTز هستفاده
كرد .

دستور زير را ملاحظه نماييد : SUBINT var1/var2 ;

با دستور فوق ، متغيرهاي var1و var2و از نوع SUBINT انتخاب مي شوند ، كه
همان unsigned int هست .


دستور typedef در مورد آرايه ها كاربرد جالبي دارد .

مجموعه دستورات زير را
در نظر بگيريد : typedef char STRING[50] ;
STRING s1/s2 ;

مجموعه دستورات فوق موجب مي شوند تا متغيرهاي s1و s2و از نوع كاراكتري و به
طول 50 بايت تعريف گردند.

بعبارت ديگر، اين مجموعه دستورات با دستور زير معادل
هست : char s1[50] /s2[50];

براي آشنايي بيشتر با چگونگي معرفي آرايه ها توسط دستور typedef به مثال 1
توجه نماييد :

مثال 1:

main)(
{
typedef unsigned int INT ;
typedef int ARR[5] ;
ARR list1 / list2 ;
INT i /sum= 0 ;
for( i=0 ;i < 5;i++)
scanf("%d"/&list1[i] );
for( i=0 ;i < 5;i++)
scanf("%d"/&list2[i] );
for( i=0 ;i < 5;i++)
sum+=list1[i]+list2[i] ;
printf("\n sum of two array is:");
printf("%d"/sum );
}


دستورtypedef در مورد ساختمانها بكار رفته و موجب ميگردد تا تعريف متغيرهاي
ساختمان و همينطور دسترسي به اجزاي اون به سهولت انجام شود .

براي آشنايي با
چگونگي عمل دستور typedef در مورد ساختمان ها به مثال 2 مراجعه نماييد .



مثال 2:

#include "stdio.h"
struct date {
int day ;
int month ;
int year ;
} ;
typedef struct date DATE ;
typedef DATE *PTRDATE ;

main)(
{
DATE today ;
PTRDATE ptr ;
ptr=&today ;
;
َday =2= 27ؤ > ptr ;
َmonth = 9ؤ > ptr ;
َyear == 1991ؤ > ptr ;
(dayؤ>"\n date is:%d"/ptr)printf ;
(monthؤ > "%d"/ptr)printf ;
(yearؤ > "%d"/ptr)printf }

جي برنامه مثال 2 :

27:


28:

نوع داده شمارشي ، اين امكان را فراهم مي كند كه بتوان عناصر يك مجموعه
متناهي را نامگذاري يا شماره گذاري كرده وسپس متغيرهايي را تعريف نمود تا مقادير
اون مجموعه را بپذيرند .

اين مجموعه با شناسه هايي معرفي مي شود كه به ثابت هاي
شمارشي معروفند .

نوع هاي شمارشي بصورت زير تعريف مي شوند : {
نام نوع شمارشي enum /
عنصر اول /
عنصر دوم /
عنصر سوم .


.


.



عنصر n ام } ;

نام نوع شمارشي همانند يك عنصر معمولي نامگذاري مي شود .

عناصر نوع شمارشي
شناسه هايي هستند كه اجزاي اون را مشخص كرده و با كاما از يكديگر جدا مي شوند .


تعريف متغيرهاي از نوع شمارشي همانند تعريف متغيرهاي نوع ساختمان انجام
مي شوند .

مجموعه دستورات زير را در نظر بگيريد :

enum color {( 1)
red/
yellow/
brown/
} color1/ color2/

enum color {( 2)
red/
yellow/
brown
} ;
enum color color1 / color2 ;


مجموعه دستورات (1) و (2) معادل يكديگرند.

در مجموعه دستورات (1) ضمن تعريف
نوع شمارشي color دو متغير color1و color2و از اين نوع متغير مي شوند و در
مجموعه دستورات (2) پس از تعريف نوع شمارشي color ، با هستفاده از دستور enum
دو متغير color1و color2و از اين نوع تعيين مي شوند.

متغيرهاي color1و color2و
فقط مي توانند مقادير red، yellow،و brownو را بپذيرند .

مجموعه دستورات زير
در مورد نوع هاي شمارشي فوق معتبرند :

color1=red ;
color2=yellow ;
if(color1==color2)
{
.


.


.


}


نكته اي كه در مورد نوع هاي شمارشي بايد توجه داشت اين هست كه به هر يك از
عناصر نوع شمارشي يك مقدار عددي صحيح ، نسبت داده مي شود :
به اولين عنصر ، مقدار صفر ، دومين عنصر مقدار 1 و به n امين عنصر ، مقدار n
1
نسبت داده مي شود .

مگر اين كه برنامه نايشانس اين مقادير را تغيير دهد .

به
عنوان مثال ، دستور زير را در نظر بگيريد : enum sample {a/b=5/c/d} ;

در دستور فوق مقدار صفر به a ، مقدار 5به b ، مقدار 6به c و مقدار 7به d
نسبت داده مي شود .



مثال : برنامه اي كه با هستفاده از نوع هاي شمارشي دستمزد هفته اي كارمندان
موسسه اي را محاسبه مي كند .



#include "stdio.h"
#define SATJUST 1.5
#define SUNJUST 2.0
enum weekday {
SUN /
MON /
TUE /
WED /
THU /
FRI /
SAT } ;
typedef enum weekday WEEKDAY ;
main)(
{
int hours ;
float baserate / rate /wages ;
WEELDAY day ;
WEELDAY tomorro )(;
printf("\n enter the basic");
printf(" hourly rate : " );
scanf("%f"/&baserate );
wages=0.0 ;
printf("\nenter the hours worked\n");
printf("for monday through sunday:");
printf("\n" );
day=SUN ;
do {
day=tomorrow(day );
scanf("%d"/&hours );
switch(day)
{
case MON:
case TUE:
case WED:
case THU:
case FRI:
rate=baserate ;
break ;
case SAT:
rate=SATJUST * baserate;
break ;
case SUN:
rate=SUNJUST * baserate;
break ;
}
wages+=rate * hours ;
} while( day != SUN );
printf("\ntotal wages for the");
printf(" week is: %.2f"/wages );
}
tomorrow(WEEKDAY d)
{
WEEKDAY nextd ;
switch( d)
{
case SUN : nextd=MON ; break ;
case MON : nextd=TUE ; break ;
case TUE : nextd=WED ; break ;
case WED : nextd=THU ; break ;
case THU : nextd=FRI ; break ;
case FRI : nextd=SAT ; break ;
case SAT : nextd=SUN ; break ;
}
return(nextd );
}

نمونه اي از خروجي برنامه مثال بالا : enter the basic hourly rate : 1
enter the hours worked
for monday through sunday:

12 43 56 78 98 64 23

total wages fo

29:

داده هاي مورد نياز برنامه هايي كه تاكنون نوشته شده اند در متغيرهاي معمولي
آرايه ها و ساختمان ها ذخيره و مورد پردازش برنامه گرفته اند .

متغيرهاي معمولي
آرايه ها و ساختمان ها ، همگي در حافظه RAM برنامه دارند .

لذا پس از قطع جريان
برق ( و يا خاموش شدن كامپيوتر ) و يا خروج از برنامه ، داده هايي كه در اونها
ذخيره شده اند از بين مي روند و براي هستفاده مجدد از اونها ، بايد مجددا" وارد
گردند كه قطعا"اين كار مقرون به صرفه نيست .زيرا نه تنها مستلزم صرف وقت زيادي
هست بلكه حوصله انجام كار را نيز از برنامه نايشانس سلب مي نمايد .

براي رفع اين
مشكل نوعي ساختمان داده ديگر به نام فايل مورد هستفاده برنامه مي گيرد .

اين نوع
ساختمان داده بر رايشان حافظه جانبي مثل ديسك ، نوار و غيره تشكيل مي گردند .

چون
اطلاعات موجود در رايشان حافظه جانبي با قطع جريان برق ، قطع اجراي برنامه و يا
دلايلي از اين قبيل از بين نميروند، به دفعات زيادي مورد هستفاده برنامه ميگيرند.


هر فايل شامل مجموعه اي از داده هاي مرتبط به هم هست .

مانند داده هاي مربوط
به كليه دانشجايشانان يك دانشگاه ، داده هاي مربوط به هر يك از اجزاي فايل ، يك
ركورد نام دارد .

به عنوان مثال ، در يك دانشگاه داده هاي مربوط به هر دانشجو
تشكيل يك ركورد را مي دهند .

لذا مي توان فرمود كه هر فايل ، مجموعه اي از چند
ركورد هست .

اگر باز هم دقيق تر به فايل دانشجايشانان دانشگاه پرداخته شود، مشاهده
مي گردد كه هر دانشجو تشكيل يك ركورد را مي دهند .

لذا مي توان فرمود كه هر فايل
مجموعه اي از چند ركورد هست .

اگر باز هم دقيق تر به فايل دانشجايشانان دانشگاه
پرداخته شود ، مشاهده مي گردد كه هر دانشجو ممكن هست چند قلم داده داشته باشد.


مثل نام دانشجو ، تعداد واحدهايي كه گذرانده ، نمره هر درس و ...

.

به هر يك از
اجزاي يك ركورد ، فيلد فرموده مي شود ، لذا مي توان فرمود كه هر ركورد مجموعه اي از
چند فيلد هست .


در زبان C فايل داده ، مي تواند هر دستگاهي مثل : صفحه نمايش ، صفحه كليد
چاپگر ، ترمينال ديسك ، نوار و غيره باشد .


داده ها ممكن هست به 4 روش در فايل ذخيره شده و سپس مورد بازيابي برنامه گيرند: 1
داده ها، كاراكتر به كاراكتر در فايل نوشته شده و سپس كاراكتر به كاراكتر
از فايل خوانده شوند .

2
داده ها بصورت رشته اي از كاراكترها، در فايل نوشته شده وسپس بصورت رشته اي
از كاراكترها مورد دسترسي برنامه گيرند .

3
داده ها درحين نوشتن بر رايشان فايل ، با فرمت خاصي نوشته شده و سپس با همان
فرمت خوانده شوند ( مثل توابع ()printf و ()scanf در ورودي خروجي معمولي ) .

4
داده ها به شكل ساختمان ( ركورد ) در رايشان فايل نوشته شده و سپس به صورت
ساختمان از فايل خوانده شوند .

صي در زبان C منظور شده اند .


30:

داده ها ممكن هست در فايل به دو صورت ذخيره شوند كه عبارتند از : 1) اسكي يا
متن 2 text باينري (binary) .

اين دو روش ذخيره شدن داده ها ، در موارد زير با
يكديگر تفاوت دارند : 1
تعيين انتهاي خط .

2
تعيين انتهاي فايل .

3
نحوه ذخيره شدن اعدد بر رايشان ديسك .


در فايل text اعداد بصورت رشته اي از كاراكترها ذخيره مي شوند ولي در فايل
باينري اعداد به همان صورتي كه در حافظه برنامه مي گيرند بر رايشان ديسك ذخيره
مي گردند .

بعنوان مثال ، در فايل text عدد 526 سه بايت را اشغال مي كند.

زيرا
هر رقم اون ، بصورت يك كاراكتر در نظر گرفته مي شود .

ولي در فايل باينري اين
عدد در 2 بايت ذخيره مي گردد ( چون عدد 526 يك عدد صحيح هست و اعداد صحيح در
دو بايت ذخيره مي شوند ) ( شكل 1 ) .


در فايل text ، كاراكتري كه پايان خط را مشخص مي كند ، در حين ذخيره شدن بر
رايشان ديسك بايد به كاراكترهاي CR/LF، line feed،و carriage returnو تبديل شود و
در حين خوانده شدن عكس اين عمل بايد صورت گيرد .

يعني كاراكترهاي CR/LF بايد
به كاراكتر تعيين كننده پايان خط تبديل شوند .

بديهي هست كه اين تبديلات مستلزم
صرف وقت هست ، لذا دسترسي به اطلاعات موجود در فايل هاي text كندتر از فايل هاي
باينري هست .


ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤؤ | 999 | | '9' | '9' | '9' |

ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤ | 132.844 || '1' | '3' | '2' | '.' | '8' | '4' | '4' اعداد در فايل text اعداد در حافظه

شكل (1) .

مقايسه ذخيره شدن اطلاعات در فايل text و حافظه

اختلاف ديگر فايل هاي text و باينري در تشخيص انتهاي فايل هست .

درهر دو روش
ذخيره فايل ها ، طول فايل توسط سيستم نگهداري مي شود و انتهاي فايل با توجه به
اين طول مشخص مي گردد .

در حالت text كاراكتر 1A ( در مبناي 16 ) و يا 26 ( در
مبناي 10 ) مشخص كننده انتهاي فايل هست .

( اين كاراكتر با فشار دادن كليد CTL
به همراه كليد Z توليد ميشود ).

در حين مطالعهداده ها از رايشان فايل text ، وقتي
كنترل به اين كاراكتر رسيد بيانگر اين هست كه داده هاي موجود درفايل تمام شده اند.


در فايل باينري ممكن هست عدد 1A ( در مبناي 16 ) و يا 26 ( در مبناي 10 ) جزئي
از اطلاعات بوده ، بيانگر انتهاي فايل نباشد .

لذا نحوه تشخيص انتهاي فايل در text متفاوت هست .


31:

منظور از ساوقت فايل اين هست كه اطلاعات در فايل چگونه ذخيره شده و سپس به
چه روش هايي مورد بازيابي برنامه مي گيرند .

يا بعبارت ديگر قانون حاكم بر نحوه
ذخيره و بازيابي داده ها و فايل را ساوقت فايل گايشانند .

حال به دو ساوقت فايل
پرداخته مي شود : 1
ساوقت فايل ترتيبي (sequential) .

2
ساوقت فايل تصادفي (random) .


در ساوقت فايل ترتيبي ، ركوردها به همان ترتيبي كه از ورودي خوانده ميشوند
در فايل برنامه مي گيرند و در هنگام بازيابي ، به همان ترتيبي كه در فايل ذخيره
شده اند مورد دسترسي برنامه مي گيرند .

بعنوان مثال اگر صدمين ركورد فايل بخواهد
مورد دسترسي برنامه گيرد، بايد 99 ركورد قبل از اون از فايل خوانده شوند.

فايلهاي
ترتيبي معمولا" داراي يك فيلد كليد هستند .

( فيلد كليد ، فيلدي هست كه بعنوان
شاخص ركورد مورد هستفاده برنامه ميگيرد ) و بر پايه اون ، مرتب ميباشند ( شكل 1 ).


بعنوان مثال در مورد دانشجايشانان ، شماره دانشجايشاني و در مورد كارمندان شماره
كارمندي ، فيلد خوبي براي شاخص فرد مي باشند .


شماره شناسايي نام موضوع درس نمره 12
Ahmad پاسكال 20 23
Ali پاسكال 15 34
Reza پاسكال 18 20 C Jafar 56

شكل (1) .

نمونه اي از يك فايل ترتيبي

در ساوقت فايل تصادفي ، به هر ركورد يك شماره اختصاص مي يابد .

لذا اگر
فايل داراي n ركورد باشد ، ركوردها از 1تا nا شماره گذاري خواهند شد .

وقتي كه
ركوردي در يك فايل با ساوقت تصادفي برنامه گرفت ، محل اون توسط يك الگوريتم پيدا
كننده آدرس ، كه با فيلد كليد ارتباط دارد مشخص مي شود .

در اين صورت دو ركورد
با فيلد كليد مساايشان ، نمي توانند در فايل تصادفي وجود داشته باشند .

در ساوقت
فايل تصادفي مستقيما" مي توان به هر ركورد دلخواه دسترسي پيدا كرد ( بدون اين
كه ركوردهاي قبل از اون خوانده شوند ) .

شكل (2) نمونه اي از يك فايل تصادفي را
نمايش مي دهد .


شماره ركورد شماره شناسايي نام موضوع درس نمره 13
12 Ahmad پاسكال 20 20 C Jafar 56 20
24
23 Ali پاسكال 15 31
34 Reza پاسكال 18
ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤ اي از فايل تصادفي

32:

منظور از ساوقت فايل اين هست كه اطلاعات در فايل چگونه ذخيره شده و سپس به
چه روش هايي مورد بازيابي برنامه مي گيرند .

يا بعبارت ديگر قانون حاكم بر نحوه
ذخيره و بازيابي داده ها و فايل را ساوقت فايل گايشانند .

حال به دو ساوقت فايل
پرداخته مي شود : 1
ساوقت فايل ترتيبي (sequential) .

2
ساوقت فايل تصادفي (random) .


در ساوقت فايل ترتيبي ، ركوردها به همان ترتيبي كه از ورودي خوانده ميشوند
در فايل برنامه مي گيرند و در هنگام بازيابي ، به همان ترتيبي كه در فايل ذخيره
شده اند مورد دسترسي برنامه مي گيرند .

بعنوان مثال اگر صدمين ركورد فايل بخواهد
مورد دسترسي برنامه گيرد، بايد 99 ركورد قبل از اون از فايل خوانده شوند.

فايلهاي
ترتيبي معمولا" داراي يك فيلد كليد هستند .

( فيلد كليد ، فيلدي هست كه بعنوان
شاخص ركورد مورد هستفاده برنامه ميگيرد ) و بر پايه اون ، مرتب ميباشند ( شكل 1 ).


بعنوان مثال در مورد دانشجايشانان ، شماره دانشجايشاني و در مورد كارمندان شماره
كارمندي ، فيلد خوبي براي شاخص فرد مي باشند .


شماره شناسايي نام موضوع درس نمره 12
Ahmad پاسكال 20 23
Ali پاسكال 15 34
Reza پاسكال 18 20 C Jafar 56

شكل (1) .

نمونه اي از يك فايل ترتيبي

در ساوقت فايل تصادفي ، به هر ركورد يك شماره اختصاص مي يابد .

لذا اگر
فايل داراي n ركورد باشد ، ركوردها از 1تا nا شماره گذاري خواهند شد .

وقتي كه
ركوردي در يك فايل با ساوقت تصادفي برنامه گرفت ، محل اون توسط يك الگوريتم پيدا
كننده آدرس ، كه با فيلد كليد ارتباط دارد مشخص مي شود .

در اين صورت دو ركورد
با فيلد كليد مساايشان ، نمي توانند در فايل تصادفي وجود داشته باشند .

در ساوقت
فايل تصادفي مستقيما" مي توان به هر ركورد دلخواه دسترسي پيدا كرد ( بدون اين
كه ركوردهاي قبل از اون خوانده شوند ) .

شكل (2) نمونه اي از يك فايل تصادفي را
نمايش مي دهد .


شماره ركورد شماره شناسايي نام موضوع درس نمره 13
12 Ahmad پاسكال 20 20 C Jafar 56 20
24
23 Ali پاسكال 15 31
34 Reza پاسكال 18
ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤ اي از فايل تصادفي

33:

هر فايل قبل از اين كه بتواند مورد هستفاده برنامه گيرد ، بايد باز گردد .


مواردي كه در حين باز كردن فايل مشخص مي شوند عبارتند از : 1
نام فايل 2
نوع فايل از نظر ذخيره اطلاعات (textيا binaryا) 3
نوع فايل از نظر ورودي خروجي ( آيا فايل فقط به عنوان ورودي هست ، آيا
فقط بعنوان خروجي هست يا هم بعنوان ورودي هست و هم بعنوان خروجي ) .


يك فايل ممكن هست طوري باز شود كه فقط عمل نوشتن اطلاعات بر رايشان اون مجاز
باشد .

به چنين فايلي ، فايل خروجي فرموده مي شود .

اگر فايل طوري باز گردد كه
فقط عمل مطالعهاطلاعات از اون امكان پذير باشد به چنين فايلي ، فايل ورودي فرموده
مي شود .

اگر فايل طوري باز شود كه هم عمل نوشتن اطلاعات بر رايشان اون مجاز باشد و
هم عمل مطالعهاطلاعات از اون ، به چنين فايلي ، فايل ورودي و خروجي فرموده ميشود.


اگر فايلي قبلا" وجود نداشته باشد ، در حين باز شدن بايد بعنوان فايل خروجي باز
شود .

اگر فايلي قبلا" وجود داشته باشد و بعنوان خروجي باز گردد ، اطلاعات قبلي مي رود ، براي باز كردن فايل از تابع ()fopen هستفاده مي گردد .


34:

تابع ()fopen براي باز كردن فايل مورداستفاده برنامه گرفته و داراي الگايشان زير
هست : FILE *fopen(char *filename / *mode)

در الگايشان فوق ، filename به رشته اي اشاره مي كند كه حاايشان نام فايل و محل
تشكيل يا وجود اون هست .

نام فايل داده از قانون نامگذاري فايل برنامه تبعيت
مي كند و شامل دو قسمت : نام و انشعاب هست كه بهتر هست انشعاب فايل داده ، dat
انتخاب گردد .

محل تشكيل يا وجود فايل مي تواند شامل نام درايو و يا هر مسير
موجود رايشان ديسك باشد .

mode مشخص مي كند كه فايل چگونه بايد باز شود ( ورودي
خروجي و يا ...

) .

مقاديري كه ميتوانند بجاي mode در تابع ()fopen برنامه گيرند
همراه با مفاهيم اونها در جدول زير آمده اند .

mode
مفهوم
(rt)r فايلي از نوع text را به عنوان ورودي باز مي كند
(wt)w فايلي از نوع text را به عنوان خروجي باز مي كند
(at)a فايل را طوري بازميكند كه بتوان اطلاعاتي را به انتهاي اون اضافه
نمود rb
فايلي از نوع باينري را به عنوان ورودي باز مي كند wb
فايلي از نوع باينري را به عنوان خروجي باز مي كند ab
فايل موجود از نوع باينري را طوري باز مي كند كه بتوان اطلاعاتي
را به انتهاي اون اضافه نمود
(r+t)r+ فايل موجود از نوع text را به عنوان ورودي و خروجي باز مي كند
(w+t)w+ فايلي از نوع text را به عنوان ورودي و خروجي باز مي كند
(a+t)a+ فايل موجود از نوع text را به عنوان ورودي و خروجي باز مي كند r+b
فايل موجود از نوع باينري را به عنوان ورودي و خروجي باز ميكند w+b
فايل از نوع باينري را به عنوان ورودي و خروجي باز مي كند a+b
فايل از نوع باينري را به عنوان ورودي و خروجي باز ميكند ( اين
فايل مي تواند قبلا" وجود داشته باشد ) .


جدول مقادير معتبر mode در تابع ()fopen

براي باز كردن فايل بايد يك اشاره گر از نوع فايل تعريف گردد تا به فايلي كه
توسط تابع fopen باز مي شود اشاره نمايد .

اگر فايل به دلايلي باز نشود اين
اشاره گر برابر با NULL خواهد بود.

بعنوان مثال ، دستورات زير را درنظر بگيريد: FILE *fp;( 1)
fp=fopen("A:test"/"w");( 2)

دستور (1)، متغير fp رااز نوع اشاره گر فايل تعريف مي كند و دستور (2) فايلي
بنام test را بر رايشان درايو A ايجاد مي نمايد ( چون حالت "w" ، فايل را به صورت
خروجي باز مي كند ) .


براي تشخيص اين كه آيا فايل با موفقيت باز شده هست يا خير مي توان اشاره گر
فايل را با NULL مقايسه كرد.

( NULL ماكرايشاني هست كه در فايل stdio.h تعريف شده
هست و با حروف بزرگ بكار مي رود ) .

اگر اشاره گر فايل برابر با NULL باشد بدين
معني هست كه فايل باز نشده هست :

if((fp=fopen("A:test"/"w"))==NULL)
{
printf("cannot open file \ n");
exit( 0

35:

پس از اين كه برنامه نايشانس كارش را با فايل تمام كرد ، بايد اون را ببندد .


بستن فايل توسط تابع ()fclose انجام مي شود كه داراي الگايشان زير هست : int fclose(FILE *fp)

در الگايشان فوق ، fp به فايلي اشاره مي كند كه بايد توسط تابع ()fclose بسته
شود .

بعنوان مثال ، دستور ;(p)fclose موجب بستن فايلي ميشود كه p به اون اشاره
مي كند .


36:

براي نوشتن يك كاراكتر در فايل ، از توابع ()putc و ()fputc هستفاده ميشود.


طريقه هستفاده از اين دو تابع يكسان هست .

تابع ()putc در گونه هاي جديد C و
()fputc در گونه هاي قديمي C وجود داشته هست .

چون تابع ()putc به صورت ماكرو
تعريف شده هست سرعت عمل اون بالا هست .

لذا سعي ما در اين هست كه از تابع ()putc
هستفاده شود .

الگايشان تابع ()putc بصورت زير هست : int putc( int ch/FILE *fp)

در الگايشان فوق ، ch كاراكتري هست كه بايد در فايل نوشته شود و fp اشاره گري
از نوع فايل هست كه مشخص مي كند، كاراكتر موردنظر بايد در چه فايلي نوشته شود.


براي مطالعهكاراكترها از فايل ، ميتوان از دو تابع ()getcو()fgetc) هستفاده
نمود .

نحوه بكارگيري اين دو تابع يكسان هست .

تابع ()fgetc در گونه هاي قديمي C
و ()getc در گونه هاي جديد C وجود دارد .

چون تابع ()getc بصورت ماكرو پياده
سازي شده هست از سرعت بيشتري برخوردار هست .

لذا ما سعي در هستفاده از تابع
()getc داريم .

الگايشان اين تابع بصورت زير هست : int getc( FILE *fp)

در الگايشان فوق ، fp اشاره گري هست كه مشخص مي كند كاراكتر مورد نظر از كدام
فايل بايد خوانده شود .


در مورد مطالعهو نوشتن داده ها بر رايشان فايل بايد به نكاتي توجه داشت : 1
وقتي كاراكترهايي بر رايشان فايل نوشته مي شوند بايد مكان بعدي كه ، كاراكتر
آتي در اونجا برنامه مي گيرد مشخص باشد .

همينطور وقتي كه كاراكترهايي از فايل
خوانده ميشوند بايد مشخص باشد كه تاكنون تا كجا فايل خوانده شده هست و كاراكتر
بعدي از كجا بايد خوانده شود .

براي برآوردن اين هدف ، سيستم از يك متغير بنام "
موقعيت سنج فايل " هستفاده مي كند كه با هر دستور مطالعهو يا نوشتن بر رايشان
فايل ، مقدار اين متغير بطور اتوماتيك تغيير مي كند تا موقعيت فعلي فايل را
مشخص نمايد .

لذا عمل نوشتن بر رايشان فايل و عمل مطالعهاز رايشان اون از جايي شروع
مي شود كه اين متغير نشان مي دهد .

2
در هنگام مطالعهداده ها از فايل بايد بتوان انتهاي فايل را تست نمود .


يعني در برنامه بايد بتوان اين تست را انجام داد كه ، اگر در حين مطالعهداده ها
از فايل ، " موقعيت سنج فايل " به انتهاي فايل رسيد دستور مطالعهبعدي صادر
نگردد .

چرا كه در غير اينصورت ، سيستم پيام خطايي را مبني بر نبودن اطلاعات در
فايل صادر مي كند .


در حين مطالعهداده ها از فايل text پس از رسيدن به انتهاي فايل تابع ()getc
يا ()fgetc علامت EOF را برمي گرداند.

لذا در هنگام مطالعهداده ها از فايل text
مي توان به عمل مطالعههمچنين گفت .

تا اين كه كاراكتر خوانده شده برابر با EOF
گردد.

درفايل باينري براي تست كردن انتهاي فايل ازتابع ()feof هستفاده ميگردد.


الگايشان اين تابع بصورت زير هست : int feof( FILE *fp)

در الگايشان فوق ، fp اشاره گري هست كه مشخص مي كند اين تابع بايد بر رايشان چه
فايلي عمل كند .

تابع ()fopen علاوه بر تشخيص انتهاي فايلهاي باينري براي تشخيص
انتهاي فايل هاي text نيز هستفاده مي شود .

اكنون به بررسي مثال هايي در مورد
فايل هاي text و باينري و چگونگي تست انتهاي اين دو نوع فايل مي پردازيم .



مثال 1: برنامه اي كه كاراكترهايي را از ورودي خوانده و در يك فايل text برنامه
مي دهد ( آخرين كاراكتر ورودي $ هست ) و سپس داده هاي موجود در اين فايل را
خوانده و به فايل ديگري منتقل مي كند .



#include "stdio.h"
#include "stdlib.h"

void main(void)
{
FILE *in/*out ;
char ch;
in=fopen("test.dat"/"w");
if( in==NULL)
{
printf("cannot open file\n");
exit(1);
}
do {
ch=getchar)(;
putc(ch/in);
}while(ch!='$');
fclose(in);
out=fopen("output.dat"/"w");
if(out==NULL)
{
printf("cannot open out file");
exit(1);
}
in=fopen("test.dat"/"r");
if(in==NULL)
{
printf("cannot open input file");
exit(1);
}
ch=getc(in);
while(ch!=EOF)
{
putc(ch/out);
ch=getc(in);
}
fclose(in);
fclose(out);
}


نمونه اي از اجراي برنامه مثال 1 :

this is a sample file.


this is a text file.


text file is slow.


end of file.


$



مثال 2: برنامه اي كه كاراكترهايي رااز صفحه كليد گرفته و در يك فايل باينري
برنامه ميدهد و سپس كاراكترهاي موجود در اين فايل را خوانده و به يك فايل باينري
ديگر منتقل مي كند .

اسامي فايل هاي ورودي و خروجي بعنوان آرگومان تابع اصلي
به برنامه وارد مي شوند .



#include "stdio.h"
#include "stdlib.h"

void main(int argc/char *argv[])
{
FILE *in/*out ;
char ch;
clrscr )(;
if(argc!=3)
{
printf("you forget enter");
printf(" file name\n");
exit(1);
}
in=fopen(argv[1]/"wb");
if( in==NULL)
{
printf("cannt open(first)");
printf(" output file \n");
exit(1);
}
do {
ch=getchar)(;
putc(ch/in);
} while(ch!='$');
fclose(in);
in=fopen(argv[1]/"rb");
if(in==NULL)
{
printf("cannot open input");
printf(" file");
exit(1);
}
out=fopen(argv[2]/"wb);
if(out==NULL)
{
printf("cannot open output");
printf(" file");
exit(1);
}
ch=getc(in);
while(!feof(in))
{
putc(ch/out);
ch=getc(in);
}
fclose(in);
fclose(out);
}



مثال 3: برنامه اي كه برنامه ديگري را بعنوان فايل ورودي ، پذيرفته و تعداد
پرانتزهاي باز و بسته و همينطور تعداد آكولادهاي باز و بسته را شمارش مي كند .


نام فايل ورودي بعنوان آرگومان تابع اصلي ، به برنامه وارد مي شود .



#include "stdio.h"
#include "stdlib.h"

void main(int argc/char *argv[])
{
FILE *in ;
char ch;
int openbraket=0 / closebraket=0;
int openbraket=0 / closparant=0;
if(argc!=2)
{
printf("\n the number of");
printf(" argument is incorrect.");
exit(0);
}
in=fopen(argv[1]/"r");

if( in==NULL)
{
printf("\n file cannot open!.");
exit(0);
}
ch=getchar)(;
while( ch != EOF)
{
if( ch=='{')
openbraket ++ ;
else if( ch=='}')
closebraket ++;
else if( ch=='(')
openparant ++;
else if( ch==')')
closparant ++;
ch=getc(in );
}
printf("\n the number of open ");
printf("braket is:%d"/openbraket);
printf("\n the number of close ");
printf("braket is:%d"/closebraket);
printf("\n the number of open ");
printf("parantheses is:");
printf("%d"/openparant);
printf("\n the number of close");
printf(" parantheses is:");
printf("%d"/closparant);
fclose(in);
}


نمونه اي از خروجي برنامه مثال 3 :

E:\TC>9-3 11.7.c

the number of open braket is:37
the number of close braket is:37
the number of open parantheses is:177

37:

براي نوشتن رشته ها در فايل ، از تابع ()fputs و براي مطالعهرشته ها از قايل
از تابع ()fgets هستفاده مي گردد .

الگوهاي اين دو تابع بصورت زير مي باشند : int fputs( const char *str/ FILE *fp)
char *fgets( char *str/ int length/ FILE *fp)

در الگايشان فوق ، fp اشاره گري هست كه مشخص مي كند اين توابع بايد بر رايشان چه
فايل هايي عمل كنند .

در تابع ()fgets اشاره گر str به رشته اي اشاره مي كند كه
بايد در فايل نوشته شود .

اين اشاره گر در تابع ()fputs به رشته اي اشاره مي كند
كه اطلاعات خوانده شده از فايل در اون برنامه مي گيرند .

length طول رشته اي را كه
بايد از فايل خوانده شود مشخص مي كند .

نحوه عمل تابع ()fgets به اين صورت هست
كه :
از ابتداي فايل شروع به مطالعهمي كند تا به انتهاي يك خط برسد و يا رشته اي
به طول length كاراكتر را از فايل بخواند.

برخلاف تابع ()gets، در تابع ()fgets
كاراكتري كه انتهاي خط را مشخص مي كند جزئ رشته اي خواهد بود كه اين تابع از
فايل مي خواند .



مثال : برنامه اي كه رشته هايي رااز ورودي ( صفحه كليد ) خوانده و در يك فايل
برنامه مي دهد .

از اونجايي كه تابع ()gets كاراكتري كه پايان خط را مشخص مي كند
به رشته اضافه نمي كند ، در حين نوشتن بر رايشان فايل اين كاراكتر به رشته خوانده
شده اضافه مي شود .

براي خاتمه برنامه كافي هست به جاي رشته ، فقط كليد enter
وارد شود .



#include "stdio.h"
#include "stdlib.h"

void main(void)
{
FILE *fp ;
char str[80];
if((fp=fopen("test"/"w"))==NULL)
{
printf("cannot open file\n" );
exit(1);
}
printf("enter a string");
printf("(ENTER to quit\n");
while( 1)
{
gets(str);
if(!str[0])
break ;
strcat(str/"\n");
fputs(str/fp);
}
fclose(fp );
}


نمونه اي از اجراي برنامه مثال بالا :

enter a string(ENTER to quit
in the name of god.
this is a sample file
for string i/o.
bottom of

38:

در مثالهايي كه تاكنون مطرح گرديد، فايل يا فقط بعنوان وسيله ورودي هستفاده
گرديد و يا فقط بعنوان وسيله خروجي ، در اين قسمت مشاهده خواهد شد كه چگونه
ميتوان يك فايل را هم بعنوان وسيله ورودي و هم بعنوان وسيله خروجي مورداستفاده
برنامه داد.

براي اين منظور كافي هست در تابع ()fopen بجاي mode از يكي از عبارات r+
يا r+tا ( باز كردن فايل text موجود بعنوان ورودي و خروجي ) ، w+يا w+tا
( ايجاد يك فايل text بعنوان ورودي و خروجي ) ، a+يا a+tا ( ايجاد فايل text و
يا باز كردن فايل text موجود ، بعنوان ورودي و خروجي ) ، r+b ( باز كردن فايل
باينري موجود ، بعنوان ورودي و خروجي ) ، w+b ( ايجاد يك فايل باينري بعنوان
ورودي و خروجي ) و ياa+b ( ايجاد و يا بازكردن فايل موجود باينري بعنوان ورودي
و خروجي ) هستفاده نمود .

بعنوان مثال ، دستورات زير را در نظر بگيريد :

fp1= fopen( "test.dat"/ "w+b");( 1)
fp2= fopen( "sample.dat"/ "r+b");( 2)
fp3= fopen( "test2.dat"/"a+t");( 3)


دستور (1) ، فايلي بنام test.dat را از نوع باينري و بصورت ورودي و خروجي
باز مي كند كه اشاره گر fp1 به اون اشاره مي كند .

اگر فايل test.dat قبلا" وجود
داشته باشد محتايشانات قبلي اون از بين خواهند رفت .دستور(2)، فايلي بنام sample.dat
را كه اكنون بر رايشان درايو جاري وجود دارد از نوع باينري و بصورت ورودي و خروجي
باز مي كند .

اگر فايل sample.dat بر رايشان درايو جاري وجود نداشته باشد ، پيام
خطايي صادر خواهد شد .

دستور (3) ، فايلي بنام test2.dat را از نوع text و به
صورت ورودي و خروجي باز مي كند .

اگر فايل test2.dat قبلا" وجود نداشته باشد
ايجاد خواهد شد و اگر وجود داشته باشد اطلاعات قبلي اون محفوظ بوده و اطلاعات جديد
به انتهاي اون اضافه خواهد شد .


در حين كار با فايل ها ( نوشتن اطلاعات بر رايشان اونها و يا مطالعهاطلاعات از
اونها ) براي برگشت به ابتداي فايل ( تغيير " موقعيت سنج فايل " طوري كه ابتداي
فايل اشاره كند ) بايد فايل را بسته و مجددا" اون را باز نمود ( البته با توجه
به مطالبي كه تاكنون در مورد فايل ها فرموده شد ) .

اين مطلب در مثال هايي كه
تاكنون مطرح شد به چشم مي خورد .

اصولا" شايد در فايل هايي كه فقط بعنوان خروجي
و يا فقط بعنوان ورودي باز مي شوند، نياز به برگشت به ابتداي فايل ( بدون بستن
و باز كردن مجدد اون ) احساس نشود، ولي اين امر در مورد فايل هاي ورودي و خروجي
به عنوان يك نياز مطرح هست .

براي اين منظور از تابعي بنام ()rewind هستفاده
مي گردد .

الگايشان تابع ()rewind در فايل stdio.h برنامه داشته و بصورت زير هست : void rewind( FILE *fp)

در الگايشان فوق ، fp به فايلي اشاره مي كند كه " موقعيت سنج " اون بايد به
ابتداي فايل اشاره نمايد .



مثال : برنامه اي كه رشته هايي را از ورودي خوانده و در يك فايل text برنامه
مي دهد و سپس محتايشانات اين فايل را خوانده و به صفحه نمايش منتقل مي كند .



#include "stdio.h"
#include "stdlib.h"

void main(void)
{
FILE *fp ;
char str(80);
if((fp=fopen("test"/"w+"))==NULL)
{
printf("cannot open file\n" );
exit(1);
}
printf("enter a string");
printf("(Enter to quit\n");
while( 1)
{
gets(str);
if(!str[0])
break ;
strcat(str/"\n");
fputs(str/fp);
}
printf("\n the content of");
printf(" file is:\n\n");
rewind(fp);
fgets(str / 79 / fp);
while( !feof(fp))
{
printf("%s"/str);
fgets(str / 79 /fp );
}
fclose(fp );
}


نمونه اي از خروجي برنامه بالا :


( متن وارد شدهه از طريق صفحه كليد به فايل text ) enter a string(Enter to quit
<< top of file >>
this is an example for
read/write file.


<>

( متن موجود در فايل text كه به خروجي منتقل شده هست ) the aontent of file is:

<< top of file >>
this is an example for
read/wri

39:

در حين انجام كار با فايل ها ممكن هست خطايي رخ دهد .

بعنوان مثال ، عدم
وجود فضاي كافي براي ايجاد فايل ، آماده نبودن دستگاهي كه فايل بايد در اونجا
تشكيل گردد و يا مواردي از اين قبيل منجر به بروز خطا مي شوند .

با هستفاده از
تابع ()ferror مي توان از بروز چنين خطايي مطلع گرديد .

الگايشان تابع ()ferror
در فايل stdio.h برنامه داشته و بصورت زير هست : int ferror( FILE *fp)

در الگايشان فوق ، fp اشاره گري هست كه مشخص مي كند اين تابع بايد بر رايشان چه
فايلي عمل كند.

اين تابع يك تابع منطقي هست .

بدين معني كه اگر خطايي در رابطه
با فايل ها رخ داده باشد اين تابع ارزش " درستي " وگرنه ارزش " نادرستي " را
برمي گرداند .

براي تشخيص خطا در كار با فايل ها ، بلافاصله پس از هر فعلي كه
رايشان فايل انجام مي شود بايد از اين تابع هستفاده نمود .



مثال : برنامه اي كه كاراكترهاي tab را از فايل حذف كرده و بجاي اون به تعداد
كافي فضاي خالي (blank) برنامه مي دهد .

اسامي فايل هاي ورودي و خروجي از طريق
آرگومان به برنامه وارد مي شود .



#include "stdio.h"
#include "stdlib.h"

#define TAB_SIZE 8
#define OUT 1
#define IN 1
void err(int );
void main(int argc / char *argv[])
{
FILE *in / *out;
int tab / i ;
char ch ;
if(argc!=3)
{
printf("\n incorrect number of");
printf(" parameters" );
printf("\n\t press a key...

" );
getch )(;
exit(1 );
}
in=fopen(argv[2] / "wb" );
if( in==NULL)
{
printf("\n cannot open");
printf(" output file." );
printf("\n\t press a key...

" );
getch )(;
exit(1 );
}
tab=0;
do {
ch=getc(in );
if( ferror(in))
err(IN );
if(ch=='\t')
{
for( i=tab ; i < 8 ; i++)
{
putc(' ' / out );
if( ferror(out))
err(OUT );
}
tab=0 ;
}
else
{
putc(ch / out );
if( ferror(out))
err(OUT );
tab ++ ;
if( tab==TAB_SIZE ||
ch=='\n' || ch=='\r')
tab=0;
}
}while( !feof(in ));
fclose(in );
fclose(out );
}
void err(int eror)
{
if( eror==IN)
printf("\n error on input file.");
else
printf("\n press a key...

");
getch )(;
exit

40:

براي حذف فايل هاي غيرضروري مي توان از تابع ()remove هستفاده كرد .

الگايشان
اين تابع در فايل stdio.h برنامه داشته و بصورت زير هست : int remove( char *filename)

در الگايشان فوق filename بنام فايلي كه بايد حذف شود ، اشاره مي كند.

اگر عمل
تابع ناموفقيت انجام شود مقدار صفر وگرنه مقداري غير از صفر برگردانده خواهد
شد .



مثال : برنامه اي كه نام فايلي را بعنوان آرگومان پذيرفته و اونرا حذف ميكند.



#include "stdio.h"
#include "stdlib.h"

main(int argc / char *argv[])
{
char str[80] ;
if(argc!=2)
{
printf("\n you must type a file name!\n" );
exit(1 );
}
printf("erase %s( y/n"/argv[1]);
gets(str );
if(toupper(*str)=='y')
if(remove(argv[1]))
{
printf("cannot erase file\n");
exit(1);
}
}


نمونه اي از اجراي برنامه مثال بالا :

E:\TC>9-6 test.x
erase test.x(y/ny

41:

بافر ، حافظه اي هست كه به فايل ها اختصاص مي يابد تا اعمال ورودي خروجي
بر رايشان اونها با سرعت بيشتري انجام گيرد.

در حين خروج از برنامه خوب هست كه جهت
اطمينان بيشتر ، به ماشين دستور داد تا كليه داده هاي موجود در بافرها را به
فايل مربوطه منتقل مي نمايد.

براي اين منظور مي توان از تابع ()fflush هستفاده
نمود .

اگر كار اين تابع با موفقيت انجام شود ، مقداري كه توسط اون برگردانده
مي شود برابر با صفر وگرنه برابر با EOF خواهد بود ( EOF ماكرايشاني هست كه در
فايل stdio.h تعريف شده هست ) .

الگايشان تابع ()fflush در فايل stdio.h برنامه
داشته و بصورت زير هست : int fflush( FILE *fp)

در الگايشان فوق ، fp فايلي را مشخص ميكند كه تابع ()fflush بايد بر رايشان اون عمل
نمايد .

اگر fp ذكر نشود تابع ()fflush بر رايشان كليه فايل هايي كه بعنوان خروجي
باز شده اند عمل مي كند .

بعنوان مثال ، دستور (f)fflush موجب مي شود تا كليه به فايل با اشاره گر f ، در اين فايل نوشته شوند

42:

اگر لازم باشد كه داده ها با فرمت خاصي در فايل نوشته و يا از اون خوانده شوند
مي توان از دو تابع ()fprintf و ()fscanf هستفاده نمود .

اين دو تابع دقيقا"
كار توابع ()printf و ()scanf را در ورودي خروجي معمولي ( غير از فايل )
انجام مي دهند .

الگايشان اين توابع در فايل stdio.h برنامه داشته و به صورت زير
مي باشند :

int fprintf( FILE *fp/ "*control_string/..."/ char arg/)...


int fscanf( FILE *fp/ "*control_string/..."/ char arg/)...




در الگايشان فوق ، fp اشاره گري هست كه مشخص ميكند اعمال اين توابع بايد بر رايشان
چه فايلي انجام شود .

control-srstring مشخص مي كند كه داده ها (args) بايد با
چه فرمتي نوشته و يا خوانده شوند .



مثال : برنامه اي كه يك رشته و يك عدد صحيح را از ورودي خوانده و اونرا در يك
فايل مي نايشانسد و سپس از اين فايل خوانده و در صفحه نمايش چاپ مي كند .



#include "stdio.h"
#include "stdlib.h"
#include "io.h"

void main(void)
{
FILE *fp;
char s[80] / number[10];
int t;
if((fp=fopen("test"/"w"))==NULL)
{
printf("cannot open file \n" );
exit(1 );
}
printf("\n enter a string: ");
gets(s);
strcat(s/"\n");
printf("\n enter anumber:");
gets(number);
t=atoi(number);
fprintf(fp/"%s%d"/s/t );
fclose(fp );
if((fp=fopen("test"/"r"))==NULL)
{
printf("cannot open file\n");
exit(1);
}
fscanf(fp/"%s%d"/&s/&t);
printf("\nstring=%s/digit=%d"/s/t);
}


نمونه اي از خروجي برنامه مثال بالا :

enter a string:hello!
enter a number:123
string=hello! / digit=123


در مورد تابع ()fprintf و ()fscanf بايد توجه داشت كه عليرغم اينكه ورودي
خروجي بااين دو تابع آسان هست اما اطلاعات به همان صورتي كه در صفحه نمايش ظاهر
مي شوند در فايل ذخيره مي گردند .

بعنوان مثال ، عدد 267 كه در صفحه نمايش ، 3
بايت را اشغال مي كند اگر توسط تابع ()fprintf بر رايشان فايل نوشته شود نيز 3
بايت را اشغال خواهد كرد ( توجه داريم كه عدد 267 يك عدد صحيح هست و مي تواند
در دو بايت ذخيره شود ) .

اين بدين معني هست كه هر رقم بصورت كاراكتر تلقي
مي گردد .

اگر اين عدد توسط تابع ()fscanf از رايشان فايل خوانده شود ، بايد عمل
تبديل كاراكتر به عدد صورت گيرد كه مستلزم صرف وقت هست .

براي جلوگيري از اين كه از دو تابع ()fread و ()fwrite هستفاده گردد .


43:

همانطوركه تاكنون مشاهده گرديد توابع زيادي براي انجام اعمال ورودي خروجي
فايل وجود دارند .

دو تابع ()fprintf و ()fscanf براي نوشتن و مطالعهانواع
مختلفي از داده ها و با فرمت هاي متفاوت بر رايشان فايل بكار مي روند .

البته اين
دو تابع از سرعت كمي برخوردارند كه توصيه مي شود از اونها هستفاده نگردد .

براي
ورودي خروجي ركورد و همينطور ساير ورودي خروجيها ميتوان از دو تابع ()fread
و ()fwrite هستفاده نمود كه از سرعت بالايي برخوردارند .

الگايشان اين توابع در
فايل stdio.h برنامه داشته و بصورتهاي زير مي باشند :

int fread( void *buffer/ int num_byte/ int count/ FILE *fp)
int fwrite( void *buffer/ int num_byte/ int count/ FILE *fp)


در الگوهاي فوق ، پارامتر buffer در مورد تابع fread به ساختمان داده يا
متغيري اشاره مي كند كه داده هاي خوانده شده از فايل بايد در اون برنامه گيرند و
اين پارامتر تابع ()fwrite به محلي از حافظه اشاره مي كند كه داده هاي موجود در
اون محل بايد در فايل نوشته شوند .

پارامتر num_byte در هر دو تابع طول داده اي
كه بايد خوانده يا نوشته شود را مشخص مي كند .

پارامتر count تعداد عناصري هست
كه طول اون توسط num_byte مشخص مي گرديد و بايد در فايل نوشته و يا از فايل
خوانده شوند .

اشاره گر fp به فايلي اشاره مي كند كه توابع freadو fwriteو بايد
بر رايشان اونها عمل كنند .

بعنوان مثال مجموعه دستورات زير را در نظر بگيريد :

char table [20];( 1)
char arr [10];( 2)
fwrite( table/ sizeof( char)/ 20/ fp);( 3)
fread( arr/ sizeof( char)/ 10/ fp);( 4)


دستورات (1) و (2) رشته هايي به طول هاي 20 و 10 را تعريف مي كنند .

دستور
(َ3) ، 20 بايت از اطلاعات موجود در آرايه table را در فايلي كه fp به اون اشاره
مي كند مي نايشانسد .

دستور (4) تعداد 10 بايت از اطلاعات را از فايلي كه fp به اون
اشاره مي كند خوانده و در متغير arr برنامه مي دهد .

توابع ()fread و ()fwrite
بيشتر در ورودي خروجي ركورد مورد هستفاده برنامه مي گيرند .



مثال 1: برنامه اي كه نام ، تعداد ساعت كار و حق الزحمه ساعتي كارمندان
موسسه اي را دريافت كرده و در يك فايل برنامه ميدهد و سپس بااستفاده ازاين اطلاعات
حقوق اونها را محاسبه كرده و به خروجي منتقل مي كند .



#include "stdio.h"
#include "stdlib.h"
main)(
{
FILE *p;
char numstr[10];
int i / salary ;
struct em
{
char name [10] ;
int hp;
int h;
} emp ;
clrscr )(;
p=fopen("employ.dat"/"wb+" );
if( p==NULL)
{
printf("cannot open output file");
printf("\n press a key...

" );
getch )(;
exit(1 );
}
gotoxy(14/2 );
puts("<< data entry >>");
gotoxy(3/3 );
printf(" name hour pay");
printf(" hour " );
gotoxy(3/4 );
printf("--------- ----------");
printf("------ ");
i=5 ;
while( 1)
{
gotoxy(3/i );
gets(emp.name);
if(!emp.name[0])
break ;
gotoxy(21/i );
gets(numstr );
emp.hp=atoi(numstr );
gotoxy(34/i );
gets(numstr );
emp.h=atoi(numstr );
i++ ;
fwrite(&emp/sizeof(struct em)/1/p);
}
rewind(p );
clrscr)(;
gotoxy(7/2 );
puts(" << OUTPUT >> " ) ;
gotoxy(3/3 );
puts(" name salary ");
gotoxy(3/4 );
puts("-------- -----------");
i=5 ;
fread(&emp / sizeof(struct em)/1/p);
while(!feof(p))
{
gotoxy(3/i );
puts(emp.namp);
gotoxy(21/i );
printf("%d"/ emp.hp*emp.h );
i++ ;
fread(&emp/sizeof(struct em)/1/p);
}
gotoxy(6/++i );
puts("press a key...

");
getch )(;
}


نمونه اي از خروجي برنامه مثال 1 :

<< data entry >>
name hour pay hour
------ ---------- --------
ali 120 100
reza 500 50
ahmad 200 10

<< OUTPUT >>
name salary
-------- ----------
ali 12000
reza 25000
ahmad 2000

press a key...





مثال 2: برنامه اي كه يك بانك اطلاعاتي از دانشجايشانان تشكيل مي دهد .

اطلاعاتي
در بانك برنامه مي گيرند عبارتند از : نام دانشجو ، شماره دانشجايشاني ، نمره و
جنسيت دانشجو .


قبل از مشاهده ليست برنامه بهتر هست نگاهي به نمودار سلسله مراتبي برنامه و
وظايف توابع داشته باشيم :
ؤؤؤؤؤؤؤؤؤؤؤؤؤؤ | main )(|

ؤؤؤؤؤؤؤؤؤؤؤؤؤؤ |

ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤ
ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ||init_list)(||| menu )(|| enter )(||display )(|| save )(|| load )(|

ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ |
|

ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ||init_list)(||

ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ شكل ( الف )
نمودار سلسله مراتبي برنامه مثال 2

وظيفه تابع ()main : فراخواني توابع مطابق شكل ( الف ) .


وظيفه تابع init-lslist : مقداردهي اوليه به ليست ( باNULL كردن اولين كاراكتر ( .

name

وظيفه تابع ()menu : ظاهر نمودن منايشاني در صفحه نمايش .


وظيفه تابع ()enter : اخذ اطلاعات از صفحه كليد و برنامه دادن اون در ليست .


وظيفه تابع ()display : چاپ محتايشانات ليست در صفحه نمايش .


وظيفه تابع ()save : انتقال محتايشانات ليست به فايل .


وظيفه تابع ()load : انتقال اطلاعات از فايل به ليست .



ليست برنامه مثال 2 :

#include "stdio.h"
#include "stdlib.h"
#define SIZE 100
struct student
{
char name [10] ;
int stno / --- ;
float grade ;
} list[SIZE] ;
int menu(void );
void init_list(void )/ enter(void );
void display(void )/ save(void );
void load(void );
main)(
{
char chois ;
init_list)(;
for(;
{
switch(menu))(
{
case 'e':
enter)(;
break;
case 'd':
display)(;
break;
case 's':
save )(;
break;
case 'i':
load )(;
break ;
case 'q':
exit(0 );
}
}
}
void init_list(void)
{
register int t ;
for( t=0 ; t < SIZE ; t++)
*list[t].name='\0' ;
}
void enter(void)
{
register int i ;
int row ;
char numstr[10];
for( i=0 ; i < SIZE ; i++)
if( !list[i].name)
break ;
if(i==SIZE)
{
printf("\n list is full " );
printf("press a key...

" );
getch )(;
}
clrscr )(;
gotoxy(10/2 );
puts("<< INPUT DATA >>");
gotoxy(1/3 );
printf(" name stno ");
printf(" gread ---(1/2)" ) ;
gotoxy(1/4 );
puse( "-- ----- ------- ");
printf("------- -----" );
row=5 ;
for(;
{
gotoxy(1/row);
gets(list[i].name);
if(!list[i].name[0]);
break ;
gotoxy(12/row);
gets(numstr );
list[i].stno=atoi(numstr );
gotoxy(20/row);
gets(numstr );
list[i].grade=atoi(numstr );
gotoxy(30/row);
gets(numstr );
list[i].---=atoi(numstr );
row ++ ;
i ++ ;
}
}
void display(void)
{
register int t ;
int row ;
clrscr )(;
gotoxy(10/2 );
puts("<< OUTPUT DATA >> " );
gotoxy(1/3 );
printf(" name stno gread ");
printf(" ---(1/2)" );
gotoxy(1/4 );
puse( " ----- ---- ------- ");
printf("--------" );
row=5 ;
for( t=0 ; t < SIZE ; t++)
{
if(*list[t].name)
{
gotoxy(1/row);
printf("%s"/list[t].name);
gotoxy(12/row);
printf("%d"/list[t].stno);
gotoxy(20/row);
printf("%.2f"/list[t].grade );
gotoxy(30/row);
printf("%d"/list[t].--- );
row ++ ;
}
}
gotoxy(5/row+2);
printf(" press a key...

");
getch )(;
}
void save(void)
{
FILE *fp ;
register int i ;
fp=fopen("st"/wb");
if(fp==NULL)
{
printf("\n cannot open file");
printf("\n press a key...

");
getch )(;
return ;
}
for(i=0 ; i < SIZE ; i++)
if(*list[i].name)
fwrite(&list[i]/
sizeof(struct student)/1/fp );
clrscr )(;
gotoxy(20/10 );
printf("data saved.press a key.");
getch )(;
}
void load(void)
{
FILE *fp ;
register int i ;
fp=fopen("st"/rb");
if(fp==NULL)
{
printf("\n cannot open file");
printf("\n press a key...

");
getch )(;
return ;
}
init_list )(;
for(i=0 ; i < SIZE ; i++)
{
fread(&list[i]/
sizeof(struct student)/1/fp);
if(feof(fp))
{
clrscr )(;
gotoxy(20/10 );
printf("data loaded.press a key.");
getch )(;
return ;
}
}
}
menu(void)
{
char s[80] ;
clrscr )(;
do {
gotoxy(20/4);
printf("E )enter data ");
gotoxy(20/6);
printf("D )display on screan");
gotoxy(20/8);
printf("L )load file");
gotoxy(20/10);
printf("S )save in file");
gotoxy(20/12);
printf("Q )quit");
gotoxy(20/14);
printf("enter your select:");
gets(s );
}while(!strchr("edlsq"/tolower(*s)));
return tolower(*s );
}


در برنامه مثال 2 از تابع ()tolower هستفاده شده هست .


براي آشنايي با نحوه عملكرد برنامه ، نتيجه دوبار اجراي اون را در زير مشاهده
مي كنيد :
نتيجه حاصل از اجراي اول :

E )enter data
D )display on screan
L )load file
S )save in file
Q )quit
enter your select:e
<< INPUT DATA >>
name stno grade ---(1/2)
-------- ----- ---- ------
reza 123 12.4 1
mohammad 321 16.6 1
mina 543 11.5 2

E )enter data
D )display on screan
L )load file
S )save in file
Q )quit
enter your select:d
<< OUTPUT DATA >>
name stno grade ---(1/2)
-------- ----- ---- ------
reza 123 12.4 1
mohammad 321 16.6 1
mina 543 11.5 2
press a key...



E )enter data
D )display on screan
L )load file
S )save in file
Q )quit
enter your select:s
data saved.press a key.

E )enter data
D )display on screan
L )load file
S )save in file
Q )quit
enter your select:q


نتيجه حاصل از اجراي دوم :
E )enter data
D )display on screan
L )load file
S )save in file
Q )quit
enter your select:l
data loaded.press a key.

E )enter data
D )display on screan
L )load file
S )save in file
Q )quit
enter your select:d
<< OUTPUT DATA >>
name stno grade ---(1/2)
-------- ----- ---- ------
reza 123 12.4 1
mohammad 321 16.6 1
mina 543 11.5 2
press a key...



E )enter data
D )display on screan
L )load file
S )save in file

44:

حل يك مساله از طريق فايلهاي ترتيبي

تاكنون با نحوه تشكيل فايل هاي ترتيبي و چگونگي دسترسي به اطلاعات موجود در
اون آشنا شده ايم .

اكنون مساله پيچيده تري را در نظر مي گيريم : يك فايل داده به
نام old حاايشان اطلاعات مربوط به دانشجايشانان هست كه بايد بازسازي گردد .

منظور از
بازسازي فايل ، حذف ركورد ، تغيير ركورد و يا اضافه نمودن ركورد جديدي به فايل
هست .

فرمت ركوردهاي فايل old بصورت زير مي باشد :
نمره | درس | نام دانشجو | شماره دانشجايشاني |
ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ 4 20 10 2


نمونه اي از اطلاعات موجود در فايل old بصورت زير هست :

نمره نام درس نام دانشجو فيلد كليد ( شماره دانشجايشاني )
ؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤ 1234 Ali pascal 15
2345 Ahmad pascal 19
3456 Reaz C 18
5678 Jafar C 14
6789 Jalal pascal 13
9999 zzzz zzzz 9


براي بازسازي فايل old ركوردهاي تراكنش در فايلي بنام trans برنامه دارند .


فرمت ركوردهاي اين فايل بصورت زير مي باشد :
|
نمره | درس | نام دانشجو | تراكنش | شماره دانشجايشاني |
ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ 4 1 20 10 2

در فرمت فوق ، تراكنش مشخص مي كند كه ركورد بايد حذف ، اضافه و يا تغيير
نمايد .

اگر تراكنش برابر با I ركورد بايد اضافه گردد ، اگر برابر با D باشد
ركورد بايد حذف گردد و اگر برابر با C باشد ركورد بايد تغيير نمايد .



نمونه اي از محتايشانات فايل trans بصورت زير هست .



نمره نام درس نام دانشجو نوع تغييرات فيلد كليد ( شماره دانشجايشاني )
ؤؤؤؤ ؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤ 20
pascal Ahmad تغيير محتايشانات ركورد 2345 20
C Ritchie اضافه 4567 13
pascal Jalal حذف 6789 9999 zzz zzz zzz 9


نتيجه حاصل از تركيب دو فايل oldو transو فايل جديدي بنام new هست كه حاايشان
جديدترين اطلاعات مي باشد و محتايشانات اون بصورت زير هست :

نمره نام درس نام دانشجو فيلد كليد ( شماره دانشجايشاني )
ؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤ 1234 Ali pascal 15
2345 Ahmad pascal 20
3456 Reaz C 19
4567 Ritchie C 20
5678 Jafar C 14
9999 zzz zzz 18


چگونگي تركيب فايل هاي oldو transو و تشكيل فايل new در شكل ( الف ) مشاهده
مي گردد .


ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ |
نقل خطا | | فايل old | o
ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤ ؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ
ؤ >ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ<ؤ|
برنامه بازسازي |
ؤ >ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ<ؤ
ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤ ؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ |
فايل new | n | فايل | tatrans
ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ
شكل ( الف ) .

بازسازي فايل ترتيبي

همانطور كه در شكل ( الف ) مشاهده مي گردد ، اگر در حين بازسازي خطايي رخ
دهد ، مثلا" ركوردي كه در فايل old وجود نداشته باشد ولي سعي در حذف اون داشته
باشيم ، پيام خطاي مناسبي در صفحه نمايش چاپ مي شود .

شكل ( ب ) نمودار سلسله
مراتبي برنامه بازسازي فايل ترتيبي را نشان مي دهد .


ؤؤؤؤؤؤؤؤؤؤؤؤ | main )(|

ؤؤؤؤؤؤؤؤؤؤؤؤ |

ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤ | | | | |

ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ|ؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ |syserr)(|||get_master_record||||get_transaction_r ecord||do_nintial_status|

ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ|ؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ
ؤؤؤؤؤؤؤؤؤؤ | |
ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤ | | |
|
ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ |apply_transaction||do_final_status||copy_correspo nding||put_master_record||
|
ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ
ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ |
ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ | ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ | | | | |

ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ| ؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ||copy_corresponding|| |error| |||copy_corresponding|| |get_master_record|

ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ| ؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ |
|

ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ || put_master_record ||

ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ
شكل ( ب ) .

نمودار سلسله مراتبي بازسازي فايل ترتيبي



ليست برنامه بازسازي فايل ترتيبي .

# include
# define READONLY "r"
# define WRITEONLY "w"
# define FALSE 0
# define TRUE 1
typedef int boolean;

# define NAMESIZE 21
# define SUBJECTSIZE 11
# define TRAILER 9999

# define INSERT 'I'
# define DELETE 'D'
# define CHANGE 'C'

char *prog;
FILE *fopen)(
int fclose)(/fscanf)(/fprinter
boolean get_transaction_record)(
boolean get_master_record)(
boolean put_master_record)(

void do_inital_status)(
void do_final_status)(
void apply_transation)(
void copy_corresponding)(
void syserr)(/error)(

main(argc/argv)
int argc
char *argv[]
{
cgar b[21]/c[11]
int a/d
FILE *fpold/*fptrans/*fpnew
int current_key
boolean allocated
char tran_transaction
int old_identification
tran_identification
new_identification
char old_name[NAMESIZE]
tran_name[NAMESIZE]
new_name[NAMESIZE]
char old_subject[SUBJECTSIZE]
tran_subject [SUBJECTSIZE]
new_subject[SUBJECTSIZE]
int old_grede/tran_grade
new_grade

prog=argv[0]
if(argc !=4 )syserr(1/
"usage:&s file1 file2 file3\n"/prog)

else if((fpold=fopen(argv[1]/
READONLY))==NULL)
syserr(2/
"cannot open &s\n"/argv[1])
else if(( fptrans=fopen( argv[2]/
READONL))==NULL
syserr(2/"cannot open &s\n"/argv[2])
else if (( fopew=fopen( argv[3]/
WRITEONLY))==NULL
syserr(2/"cannot open &s\n"/argv[3]);
else
{
get_master_record(fpold/
&old_identification/
old_name/old_subject/&old_grade);
get_transction_record(fptrans/
&tran_identification/
&tran_transaction/
&tran_name/tran_subject/
&tran_grade
current_key=tran_identification <
old_identification ?
tran_identification:
old_identification ;
while(current_key != TRAILER)
{
do_initial_status(current_key/
&allocated/
fpold/&old_identifcation/
old_name/old_subject/&old_grade);
*new_identification'
new_name/new_sudject/&new_grade);
while(current_key==
tran_identification
{
apply_transaction( &allocated'
tran_identification/
tran_transaction/
tran_subject/tran_grade/
&new_identification/new_name/
new_subject/&new_grade);
get_transction_record(fptrans/
&tran_identification/
&tran_transaction/tran_name
tran_subject/&tran_grade/
}
do_final_status( fpnew/allocated/
new_identification/new_name/
new_subject/new_grade);
current_key=tran_identification<
old_identification ?
tran_identification:
old_identification ;
}
copy_corresponding(
&new_identification/new_name/
new_subject/&new_grade/9999/
"zzzzzzzzzzzzzzzzzzzz"/
"zzzzzzzzzz"/9);
put_master_record(fpnew/
new_identification/
new_name/new_subject/new_grade );
fclose(fpold);
fclose(fptrans);
fclose(fpnew);
}
}

boolean get_transaction_record(fp/
identification/
transaction/ name/suhject/grade)
FILE *fp;
int *identification;
char *transaction;
char *name;
char *subject;
int *grade;
{
if( fscanf( fp/ "%4d%c%20s%10%2d"/
identification/
transaction/name/subject/grade)==5)
return(TRUE);
else
return(FALSE);

}

boolean get_master_record(fp/
identification/name/subject/grede)
FILE *fp;
int *identification;
char *name;
char *subject;
int *grade;
{
if( fscanf( fp/"%4d%20s%10s%2d"/
identification/
name/sunject/grade)==4)
return(TRUE);
else
return(FALSE);

}

boolean put_master_record(fp/
identification/name/subject/grade)
FILE *fp;
int *identification;
char *name;
char *subject;
int *grade;
{
if(fprintf(fp/
"%6d %-20s %-10s %2d\n"/
identification/name/
subject/grade)!=EOF)return(TRUE);
else
return(FALSE);
}


void apply_transaction(allocated/
tran_identification/
tran_transaction/tran_name/
tran_subject/tran_grade/
new_identification/new_name/
new_subject/new_grade)
boolean *allocated;
char tran_transaction;
int tran_identification/
*new_identification;
char *tran_name/ *new_name;
char *tran_subject/ *new_subject;
int tran_grade/ *new_grade;

{
switch(tran_transaction)
{
case INSERT:
if(*allocated==TRUE)
error(INDSERT/
"record already exists\n"/
tran_identification);
else
{
copy_corresponding(
new_identification/
new_name/new_subject/
tran_grade);
*allocated=TRUE;
}
break;
case DELETE:
if(*allocated==FALSE)
error(DELETE/
"tecord dose not exist\n"/
tran_identification);
else
*allocated=FALSE;
break;
case CHANGE:
if(*allocated==FALSE)
error(CHANFE/
"record dose not exist\n"/
tran_identification);
else
copy_corresponding(
new_identification/
new_name/new_subject/
new_grade/
tran_identification/
tran-name/tran_subject/
tran_grade);
break;
}
}

void do_initial_status(current_key/
allocated/fp/old_identification/
old_name/old_subject/old_grade/
new_identificatinl/new_name/
new_subject/new_grade)
int current_key;
boolean *allocated;
FILE *fp'
int *old_identification/
*new_identification/
char *old_name/ *new_name;
char *old_subject/ *new_subject;
int *old_grade/ *new_grade;
{
if(*old_identification==current_key)
{
copy_corresponding(
new_identification/new_name/
new_subject/new_grade/
*old_identification/
old_name/old_subject/*old_grade);
*allocated=TRUE;
get_master_record(fp/
old_identification/
old_name/old_subject/old_grade);
}
else
*allocated=FALSE;
}

void do_final_status(fp/allocated/
identification/name/subject/grade)

FILE *fp;
boolean allocated;
int identification;
char *name;
char grade;
int
{
if(allocated==TRUE)
put_master_record(fp/identification/
name/subject/grade);
}

void copy_corresponding(
dest_identification/dest_name/
dest_subject/dest_grade/
sou_identification/
sou_name/sou_subject/sou_grade)
int *dest_identification/
sou_identification;
char *dest_name/ *sou_name;
char *dest_subject/ *sou_subject;
int *dest_grade/ sou_grade;
{
*dest_identification=
sou_identification;
strcpy(dest_name/sou_name);
strcpy(dest_subject/sou_subject);
*dest_grade=sou_grade;
}

void syserr( errcode/message/argument)
int errcode;
char *message/argument ;
{
fprintf(stderr/"%s[%2d]:"/prog/
errcode);
fprintf(stderr/message/argument);
exit(errcode);
}

void error( code/message/id)
char code;
char *message;
int id;
{
printf("%c %30s %4d\n"/
code/message/id);
}


اجراي برنامه بازسازي فايل ترتيبي و محتايشانات فايل هاي داده :


فايل new 2345 ahmad pascal 20
3456 reza c 19
4567 richie c 20
5678 jafar c 14
9999 zzzzzzzzzzzzzzzzzzzz zzzzzzzzzz 9

فايل old 1234ali pascal 15
2345ahmad pascal 18
3456reza c 19
5678jafar c 14
6789jafar pascal 13
9999zzzzzzzzzzzzzzzzzzzzzzzzzzzzzz 9

فايل trans 2345cahmad pascal 20
4567Irichie c 20
6789Kjalal pascal 13
9999zzzzzzzzzzzzzzzzzzz

45:

دسترسي تصادفي به فايل ( ورودي خروجي تصادفي )

دربرنامه هايي كه تاكنون نوشته اند،ازساوقت فايل ترتيبي براي ذخيره وبازيابي
اطلاعات هستفاده شده هست .

در اين قسمت چگونگي تشكيل تصادفي مطرح شده و طريقه
دسترسي به اطلاعات موجود در اونها مورد بررسي برنامه مي گيرند.


براي دسترسي تصادفي به فايل هااز تابع ()fseek هستفاده مي شود.الگايشان اين تابع
در فايل stdio.h برنامه داشته و بصورت زير مي باشد :
int fseek( FILE *fp/ long num_byte/ int origin)


پايه كار تابع ()fseek به اين صورت هست كه : با شروع از يك محل در فايل كه
توسط پارامتر origin مشخص مي شود ، " موقعيت سنج فايل " را به طول num-btbyte
بايت تغيير مكان مي دهد.

يعني تغييرمكان " موقعيت سنج فايل " بطور نسبي بوده و
نسبت به محلي كه توسط origin محل 100 فايل را بعنوان مبدا حركت مشخص كند و طول num-byte
برابر با 200 باشد ، " موقعيت سنج فايل " به محل 300 منتقل خواهدشد.


مقاديري كه origin مي تواند بپذيرد در جدول ذيل آمده اند .



( مبداحركت ) origin نام ماكرايشاني كه بيانگراين مبدااست

ابتداي فايل SEEK_SET
موقعيت فعلي فايل SEEK_CUR
انتهاي فايل SEEK_END


مقادير معتبر پارامتر origin در تابع fseek O

جدول فوق گايشاناي اين هست كه اگرپارامتر origin برابربا SEEK_SET باشد،"موقعيت
سنج فايل " ازابتداي فايل به طول num_byte بايت به طرف انتهاي فايل حركت ميكند.


اگرپارامتر origin برابر باSEEK_CUR باشد،"موقعيت سنج فايل " نسبت به محل خودش
به اندازه num_byte بايت به طرف انتهاي فايل حركت مي كند .

اگر پارامتر origin
برابر با SEEK_END باشد، " موقعيت سنج فايل " به اندازه num_byte بايت ، طول
فايل را افزايش مي دهد و سپس به اين محل اشاره مي نمايد .


محلي كه براي هر ركورد در فايل تصادفي درنظر گرفته مي شود، "ناحيه ركورد" نام
دارد .

چون هر ركورد در ناحيه مربوط به خودش نوشته مي شود .

ممكن هست چندين
ناحيه ركورد بين ركوردهاي فايل خالي باقي بماند.

به عنوان مثال ،فرض مي كنيم در
يك فايل مربوط به كارمندان ، طول ركورد 100 بوده تعداد كارمندان 5 نفر بوده و
شماره كارمندي اونها 100 ، 500 ، 600 ، 800 ، 900 باشد .

پس از برنامه گرفتن
مشخصات اين كارمندان درفايل ،99 ناحيه ركورد (99x100 بايت ) قبل از ركورد اول
و 399 ناحيه ركورد قبل از ركورد دوم و ...

به هدر مي روند ، اين موارد را شايد
بتوان به عنوان يكي از معايب فايل تصادفي در نظر گرفت ولي معمولا" مكانيزمهايي ي بهبود اين حالت منظور مي شود .


46:

دستگاههاي ورودي خروجي هستاندارد

وقتي اجراي يك برنامه به زبان C آغازميشود، 5 فايل بطور اتوماتيك بازميشوند
كه اشاره گرهاي اونها در جدول زير مشاهده مي گردند .




اشاره گر دستگاه (فايل ) نام دسگاه (فايل )


stdin
دستگاه ورودي هستاندارد (صحفه كليد) stdout
دستگاه خروجي هستاندارد (صفحه نمايش ) stderr
دستگاه هستانداردجهت ثبت پيامهاي خطا(صفحه نمايش ) stdprn
دستگاه هستاندارد چاپ (چاپگر موازي ) stdaux
پورت سري (serial port)



بعنوان مثال ، مجموعه دستورات زير را در نظر بگيريد :


putc(ch/stout );( 1)
printf(stout/%d/%d"/a/b );( 2)
fscanf(stdin/"%d/%d"/&X/&Y );( 3)



دستور (1) موجب مي شود تا كاراكتر ch در صفحه نمايش نوشته شود : دستور (2)
موجب مي شود تا متغيرهاي Xو Yو از صفحه كليد خوانده شوند .


دستگاه هاي هستاندارد ورودي خروجي همانطور كه بطور اتوماتيك باز مي شوند،به
طور اتوماتيك نيز بسته خواهند شد و نياز به بستن اونها توسط برنامه نايشانس نيست .


47:

توابع كتابخانه اي ( قسمت اول )

توابع ، جهت انجام اعمال رياضي ، كاراكتري ، رشته اي ، مقايسه ، تبديل انواع
و غيره مورد هستفاده برنامه مي گيرند.

در اعمال رياضي مي توان توليد اعداد تصادفي
محاسبه قدرمطلق اعداد و لگاريتم را نام برد و در اعمال كاراكتري مي توان خواند
و نوشتن كاراكترها و در مورد اعمال رشته اي مي توان انتقال رشته اي به رشته ديگر
مقايسه رشته ها و ...

را نام برد .

بطور كلي مي توان فرمود كه توابع در زبان C از
تنوع بسيار زيادي برخوردارند .


در زبان C هر تابع داراي الگايشاني هست كه اين الگو نوع تابع و نوع پارامترهاي
اون را مشخص مي كند .

الگايشان هر تابع در يك فايل header برنامه دارد .

ضمن بررسي
توابع ، الگايشان اونهاذكر شده و فايل header كه اين الگو در اونجا برنامه دارد معرفي
مي گردد .

به دليل اين كه درك مفاهيم بعضي از توابع نياز به داشتن اطلاعاتي در
موضوعات مختلف هست .


48:

مقدمه
نمي دانم تا حالا به مشكل "زبانها" برخورد كرده ايد يا نه ...

بنظر من تمامي زبانها در 99 % موارد شبيه به هم هستند ...

اين مطلب پايه تحقيقي شد براي اينكه يكي از دوستان خوبمان بنام "اردلان شاهقلي " اين مطلب را تهيه و يكي از دوستان ديگرمان بنام سركار خانم "نادري " زحمت تايپ انرا بكشند ...


اميد وارم اين مطلب هر چند ناقص كمك خوبي براي يادگيري هر دو زبان باشد



وكيلي


زبان C زبان Pascal
;(عبارت 2& ",عبارت 1Scanf (" ;( ) read
; (عبارت 2 , " عبارت 1") Printf ; ( ) write
نكته : دستورات Scanf و Printf داراي دو عبارت اول و دوم ميباشند .


نكته : در دستور Scanf به جاي عبارت اول از كاراكترهاي كنترلي فرمت هستفاده ميشود.


نكته : در دستور Scanf به جاي عبارت دوم (سپس علامت & ) اسم متغيرهايي كه بايد خوانده شوند مي آيد .

البته با توجه به كاراكترهاي كنترلي فرمت عبارت اول .


نكته : در دستور Printf به جاي عبارت 1 از كاراكترهاي كنترلي هستفاده ميشود .

( البته در اين دستور ميتوان بسيار عبارت اول يك متن را به .............

برنامه داد و ديگر احتياجي به عبارت دوم نيست ) در ضمن ميتوا ن از تركيب از حالت بالا هم هستفاده كرد .


نكته : عبارت دوم در دستور Printf .............

اسم متغير به همراه بعضي از كاراكترهاي كنترلي ميباشد .


; ) & , " ln (" Scanf ;( )ln read
; ) , " ln (" Printf ; ( )ln write

جدول كاراكترهاي كنترلي دستورPrintf ( ) و( ) Scanf
كاراكتر توضيحات
\f موجب انتقال كنترل به صفحه جديد مي شود
\n موجب انتقال كنترل به خط جديد ميشود
\t به اندازه ي 8 كاراكتر فاصله ايجاد ميشود
\" چاپ دبل كتيشن
\' چاپ كتيشن
\O NULL ( رشته ي .......

)
\\ Back slash
\V انتقال كنترل به 8 سطر بعد
جدول كاراكترهاي كنترلي فرمت
كاراكتر توضيحات
%c كاراكتر
%d اعداد صحيح دهدهي مثبت و منفي
%i اعداد صحيح دهدهي مثبت و منفي
%e نمايش علمي عدد همراه با حرف e
%E نمايش علمي عدد همراه با حرف E


جدول كاراكترهاي كنترلي فرمت
كاراكتر توضيحات
%f نمايش اعداد اعشاري
%g نمايش اعداد اعشاري
%G نمايش اعداد اعشاري
%S رشته اي از كاراكترها
%p اشاره گرها

در زبان C براي ورود اطلاعات انواع ديگري از توابع را داريم كه معادل اونها همان read در پاسكال ميباشد.

(readln) و .............دستور هم معادل Write موجود ميباشد.


C Pascal
getch ( );= نام متغير كاراكتري read( );
getche ( ); = نام متغير كاراكتري read( );
getchar ( ); = نام متغير كاراكتري read( );

Putch ( ) ; Write ( );
Putchar ( ) ; Write ( );

البته دستورات فوق فقط براي مطالعهيك char ميباشند.


دو دستور زير برا دريافت و نوشتن string در C ميباشند .
; (نام متغير رشته اي) gets
; (نام متغير رشته اي) Puts

انواع داده ها برابر هست با
C Pascal
int integer
Flout real
Char char
(آرايه اي از char ميباشد.

) string
Int boolean

معادل بعضي از دستورات Pascal در C در پائين آمده هست .


C Pascal
= = =
= = :
! < >
<= <=
>= >=
!= not
&& And
|| or
++Xيا ++X inc(x)
X-- يا --X dic(x)
{ begin
} End;
} End.


} End
break; break;

C Pascal
(شرط ) if then شرط if 1)

{ begin


} end
Else else
{ begin


} end;
(عمليات ; شرط خاتمه ; مقادير اوليه= متغبرهاFor ( Do مقدار نهائي to مقدار اوليه = : متغير حلقه 2) For
{ begin




} end;
البته در زبان C حلقه ي for ميتواند هر كدام و با ................

تمام مراحل را ( عمليات يا شرط خاتمه با دستوارات انتساب نداشته باشد .

)
در صورتي كه حلقه ي for به صورت زير نوشته شود مانند حلقه ي while در پاسكال عمل خواهد كرد .(بصورت بينهايت)
For (; ; )

C Pascal
) شرط ادامه ي حلقه While ( do شرط ادامه ي حلقه 1) while

{ Begin


} End;

do 2) repeat

; ( شرط ادامه ي حلقه While ( ;(شرط خروج از حلقه) until

(نام متغير) Switch of نام متغير 3) Case
{ begin :حالت اول
:{ حالت اول case
End ;
Break; begin: حالت دوم
}
:{ حالت دوم case end;
Break;
} : begin حالت n ام
:{ حالت case end;
Break; Else Begin
Defualt : End;
end;
}

}
همان طوري كه مي دانيد C تشكيل شده هست از يك سري تابع و حتي برنامه ي اصلي اون هم يك تابع هست كه بصورت زير اونرا مي نايشانسيم .


Void Main ( )
{

}
C مانند پاسكال داراي تابع مي باشد و اين توابع مي توانند كار رايشانه ها را هم اجرا کنند .


C Pascal
; ( نام متغير ها / نوع متغير ها ) نام تابع نوع تابع ; ( نوع تابع : ( نام متغير ها ) نام تابع Function
{ begin


} End;
برابر تعريف آرايه ها در C داريم .


زبان Pascal
نوع آرايه of ] مقدار انتسابي ..

مقدار ابتدائي [ Array : نام آرايه
زبان C
]طول هر خانه[ ] تعداد خانه هاي اون [ نام آرايه نوع آرايه

در زبان C اولين خانه ي آرايه ها داراي انديس صفر ميباشد .


در زبان C متغيري به نام string وجود ندارد و بجاي اون از آرايه اي از نوع char هستفاده ميشود .


C پاسكال
Char x[ ]; x:string;
در زبان C آخرين خانه ي يك آرايه از char ها با '/0' پر خواهد شد .

( '/0' انتهاي يك string ميباشد .

)
براي كپي كردن يك string در ديگري از تابع
C پاسكال
;( متغير دوم و نام متغير اول Strcpy( Pchar;: (متغير دوم ونام متغير اول strcopy (
در هر دو زبان مقدار متغير دوم و متغير اول كپي ميشود .

( البته دستور strcopy در unit، string زبان پاسكال برنامه دارد .)
;( متغير دوم و نام متغير اول ) strcut ; Pchar : ( متغير دوم و نام متغير اول ) strcut
در هر دو زبان مقدار متغير دوم به انتهاي مقدار متغير اول مي چسبد و در متغير اول برنامه مي گيرند .

( دستور فوق در unit string پاسكال برنامه دارد .

)

49:

اشاره گرها
C پاسكال
نام اشاره گر * نوع اشاره گر نوع اشاره گر ^ : نام اشاره گر
نكته : در زبان C هميشه بايد در هنگام ارسال آرايه ها به تابع آخرين عنصر اون معلوم باشد البته مي توان تمامي عناصر را هم معلوم كرد و يا آخرين عنصر را به تابع فرستاد .


در زبان C ميتوان اشاره گري از نوع آرايه تعريف كرد با هستفاده از دستور Malloc بصورت زير
Int*P
P= ( int *)Malloc ( n* size of ( int))
با دو دستور بالا ابتدا اشاره گر p از نوع int ساخته شده سپس يك آرايه ي n عنصري از نوع int به p نسبت داده ميشود .


ارزش دهي اوليه اشاره گرها درC
; "رشته " = نام رشته Char *
نكته : ساختمان ها در زبان C معادل ركوردها در زبان پاسكال ميباشند .


C پاسكال
نام ساختمان struct record = نام ركورد
{ ;نوع فيلد : نام فيلد اول
; نام فيلد نوع فيلد ;نوع فيلد : نام فيلد دوم
; نام فيلد نوع فيلد '
' '
'
; نام فيلد نوع فيلد ;نوع فيلد : نام فيلد n ام
}; end;

در زبان پاسكال در .............

var ميتوان به صورت زير متغير هائي از نوع record تعريف كرد و در زبان C داريم .
; اسامي متغير ها نام ساختمان Str var
; نام ركورد : نام متغير نكته : در زيان C ميتوان متغير هاي ساختمان را بصورت زير تعريف كرد
نام ساختمان Struct
{
; نام فيلد نوع فيلد
; نام فيلد نوع فيلد
'
'
; نام فيلد نوع فيلد
نام متغير ها }
براي دسترسي به عناصر داده ها و ركورد ها داريم
C پاسكال
نام فيلد .

نام ساختمان نام فيلد .

نام ركورد
براي تعريف آرايه اي از ركورد ها و يا ساختمان ها به صورت زير عمل ميكنيم .


C پاسكال
نام ساختمان struct type
{ record= نام ركورد
; نام فيلد نوع فيلد ; نوع فيلد : نام فيلد
; نام فيلد نوع فيلد '
' '
' ; نوع فيلد : نام فيلد
; نام فيلد نوع فيلد end;
} var
; [n ] نام آرايه نام ساختمان Strust ; نام ركورد of [1..n] array : نام آرايه

C پاسكال
( نام رشته ) a to i = ; ( عددي براي چك كردن و نام عدد و نام رشته ) vul
دو دستور بالا در C و در پاسكال يك مقدار رشته اي را ميگيرد و به يك مقدار int تبديل ميكند .


نكته : ميتوان يك اشاره گر از نوع ساختمان داشته باشيم به صورت زير

C پاسكال
نام ساختمان strust
{
; نام فيلد نوع فيلد
; نام فيلد نوع فيلد
'
'
; نام فيلد نوع فيلد
; نام اشاره گرها * و نام متغير }
و بصورت زير هم ميتوان عمل كرد
; نام اشاره گر * نام ساختمان struct
نكته : اگر اشاره گر از نوع ساختمان داشته باشيم ميتوان براي دسترسي به عناصر ساختمان بصورت زير عمل كرد .
نام فيلد .

( نام اشاره گر *)
نام فيلد نام اشاره گر
در زبان C اين امكان وجود دارد كه ساختماني را به گونه اي تعريف كنيم كه طول عناصر اونرا بر حسب bit مشخص كرد .


C پاسكال
نام ساختمان struct
{
; طول فيلد : نام فيلد نوع فيلد
; طول فيلد : نام فيلد نوع فيلد
'
'
'
; طول فيلد : نام فيلد نوع فيلد
; نام اشاره گر * و نام متغير ها }
نكته : اگر يك ساختمان از نوع بيتي داشته باشيم : (1 نمي توان به آدرس اونها مراجعه كرد
(2 نمي توان بصورت آرايه تعريف شود
(3 تركيبي از ساختمان بيتي و معمولي ممكن هست
يونيون ها : محلي از حافظه هست كه توسط دو يا چند متغير به طور اشتراكي مورد هستفاده برنامه مي گيرد.

عناصر يونيون ها تمامي از يك مدل حافظه شروع ميشوند .


در يونيون ها فضاي اشغال شده برابر هست با فضاي مورد نياز براي بزرگترين فيلد .


C
نام يونيون union
{
; نام فيلد و نوع فيلد
'
'
; نام فيلد و نوع فيلد
; نام اشاره گرها * و نام متغير ها }
نكته : ميتوان هر يك از فيلد هاي يك union خود يك struct يا union ديگر نيز باشند .



C پاسكال
اسم جديد نوع موجود typedet type
انواع داده شمارشي :

C
نام نوع شمارشي enum
{
عنصر اول
عنصر دوم
'
'
عنصر n ام
; نام اشاره گرها * و نام متغير ها }
; نام متغير ها نام نوع شمارشي enum

نكته : مقدار عددي عنصر اول صفر و عنصر n ام مقدار عددي n را ميگيرد .


فايل ها : برابر تعريف يك متغير از نوع فايل داريم
C پاسكال
نام اشاره گر فايل * FILE var
نام ركورد مورد نظر of file : نام متغير فايل
و براي كار با فايل ها دستورات زير را داريم يا
; text :
C پاسكال
; ( "فرمت باز شدن" و " آدرس فايل" ) fopen = نام اشاره گر فايل
; ( نام اشاره گر فايل ) f close
; ( نام اشاره گر فايل ) rewind
تابع rewind باعث ميشود كه اشاره گر به ابتداي فايل اشاره كند .


; ( نام اشاره گر فايل و نام متغير كاراكتري ) putc
; ( " و " ) fputc
;( نام اشاره گر فايل ) getc= نام متغير كاراكتري
;( نام اشاره گر فايل ) fgetc= نام متغير كاراكتري
;( نام اشاره گر فايل و نام متغير رشته اي ) fputs
; ( نام اشاره گر فايل و طول اون و نام متغير رشته اي ) fgets
دستور زير چك ميكند كه آيا اشاره گر به انتهاي فايل رسيده هست يا خير
اگر اشاره گر به انتها رسيده باشد مقدار 1 و در غير اينصورت صفر را بر ميگرداند.


; ( نام اشاره گر فايل ) fremove ( اگر انجام شود مقدار صفر و در غير اينصورت مقدار ديگر ارجاع ميشود .

)
در زبان C تابعي وجود دارد كه اگر در هنگام كار با فايل اشكالي پيش آيد ارزش 1 و در غير اينصورت ارزش صفر را بر ميگرداند كه بصورت زير هست .


; ( نام اشاره گر فايل ) ferror

C پاسكال
دستور زير باعث مي شود يك كاراكتر حرف كوچك به كاراكتر حرف بزرگ تبديل شود .


; ( نام متغير كاراكتري ) foupper= نام متغير كاراكتري
در زبان C ميتوان يك struct را درون فايل برنامه داد و يا از اون خواند .


C
;( نام اشاره گر فايل و تعداد مطالعهو (نام ساختمان Struct ) Sizeof و نام متغير ساختمان Fread (&
;( و " و " و " &amp fwrite
پاسكال
; ( نام متغير فايل و نام متغير ركورد read(
;( نام متغير فايل و نام متغير ركوردWrite (
; ( نام متغير كاراكتري follower = نام متغير كاراكتري
دستور حذف يك كاراكتر را به حرف كوچك تبديل ميكند .



Linklist

C پاسكال
{ نام ساختمان struct ; نام ركورد ^ = نام اشاره گر
; نام فيلد نوع فيلد record = نام ركورد
" " نوع فيلد : اسم فيلد
" " " "
; نام فيلد نوع فيلد " "
; نام فيلد آدرس * نام ساختمان struct ; نوع فيلد : نام فيلد
}; ; نام اشاره گر : اسم فيلد آدرس
End;
نكته : در زبان C براي تعريف اشاره گر هاي خارجي داريم :
C پاسكال
; نام اشاره گر * نام ساختمان struct
براي ايجاد گره داريم
C پاسكال
((نام ساختمان struct)sizeof)Malloc ( *نام ساختمان struct)= نام اشاره گر ساختمان var ; نام ركورد : نام متغير

50:

خيلي ممنون از لطفتون
دوستار شما Magic

51:

عالی بود ...جامع و کامل ..........مرسی از لطفتون

52:

very cool man!thanks a lot

53:

دست درد نكنه ولي اگه يه نسخه pdf اش رو هم ميزاشتي ديگه محشر ميشد.


54:

میشه یه مسئله حل کنید


63 out of 100 based on 28 user ratings 653 reviews