PDA

نسخه کامل مشاهده نسخه کامل : آموزش پيشرفته C



Nesta
27-04-2005, 00:48
اشاره گرها و رشته ها

چون رشته ها در زبان 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

Nesta
27-04-2005, 00:49
ارزش دهي اوليه رشته ها به عنوان اشاره گر

در اين قسمت مي خواهيم مشخص كنيم كه چگونه ميتوان رشته ها را بعنوان اشاره گر
مقدار اوليه داد . براي روشن شدن موضوع ، به مثال 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 را بصورت اشاره گر تعريف كرده
است ، قابليت انعطاف بيشتري به اين متغير داده است . اين امر باعث شده است كه
با دستور ساده ;(text++)puts رشته text كاراكتر به كاراكتر به خروجي منتقل گردد
كه نتيجه زير حاصل خواهد شد : your name is:

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


مثال 2: برنامه اي كه براي ذخيره كردن نام هاي تعدادي از افراد ، از آرايه اي
از اشاره گرها استفاده مي كند. اين برنامه با خواندن نام 5 نفر از ورودي ، آنها
را در آرايه اي قرار داده ، سپس نامي را از ورودي دريافت مي كند و تشخيص مي دهد
كه آيا اين نام در ليست وجود دارد يا خير . 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 عنصر در نظر گرفت كه هر عنصر آن نيز يك آرايه يك بعدي به

Nesta
27-04-2005, 00:50
اشاره گر به اشاره گر

اگر متغيري آدرس متغير ديگر را در خود نگهداري كند ، متغير اول يك اشاره گر
است . اگر متغير دوم ، از نوع اشاره گر باشد در اينصورت متغير اول يك اشاره گر
به اشاره گر است ( شكل 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

Nesta
27-04-2005, 00:50
نكاتي در مورد اشاره گرها

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

مثال 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و
در محل هاي متوالي حافظه قرار نگيرند .
با اشكالاتي كه تاكنون درمورد اشاره گرها گفته شد برنامه نويس بايد در استفاده ا دقت كافي بخرج دهد تا با مشكل مواجه نگردد .

Nesta
27-04-2005, 00:54
آرگومانهاي تابع اصلي (()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 عدد آرگومان استفاده نمود كه معمولا" تعداد را اجازه مي دهد .

Nesta
27-04-2005, 00:54
دستورات پيش پردازنده

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

Nesta
27-04-2005, 00:55
تعريف ماكرو

ماكرو، نامي براي يك رشته است كه اين رشته مي تواند تركيبي از خروف ، ارقام
مقادير ثابت ، توابع و غيره باشد . دستور پيش پردازنده # 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 :

Nesta
27-04-2005, 00:55
ضميمه كردن فايل ها (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

Nesta
27-04-2005, 00:56
دستورات پيش پردازنده شرطي

در حالت معمولي ، دستور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 را تست مي كند كه چون اين كرو تعريف نشده است موجب خروجي زير مي شود :

Nesta
27-04-2005, 00:57
حذف ماكروهاي تعريف شده

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

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

Nesta
27-04-2005, 00:57
اسامي ماكروهاي از پيش تعريف شده

اسامي تعداد 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) باشد ، كامپايلر استاندارد و در غير د استاندارد نيست .

Nesta
27-04-2005, 00:58
دستور پيش پردازنده #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- است مشخص مي گردد .

Nesta
27-04-2005, 00:58
دستور پيش پردازنده # 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

Nesta
27-04-2005, 00:59
ساختمان ها

قبلا" مشاهده كرديم كه چگونه يك متغير ، يك قلم از داده را در خود نگهداري
مي كند و همچنين ديديم كه چگونه مي توان چند عنصر همنوع را در يك آرايه ذخيره
كرد . گاهي لازم است ، چند عنصر غير همنوع را تحت يك نام در حافظه ذخيره نمود .
ولي با مطالبي كه تاكنون گفته شد انجام اين كار ممكن نيست . بعنوان مثال ، اگر
بخواهيم اطلاعات مربوط به كارمندان موسسه اي را كه شامل نام كارمند ( از نوع
كاراكتري ) ، شماره كارمندي ( از نوع عدد صحيح ) ، حقوق ( از نوع عددي صحيح )
غيره است ، تحت يك نام ذخيره كنيم . در اين صورت متغير معمولي و آرايه جوابگوي
نياز ما نيستند . براي رفع اين مشكل در زبان C ، از نوعي داده به نام ساختمان
استفاده مي شود . بنابراين مي توان گفت كه : " ساختمان " در زبان C نامي براي ه اي از متغيرها است كه اين متغيرها مي توانند همنوع نباشند .

Nesta
27-04-2005, 00:59
تعريف نوع ساختمان

براي تعريف نوع ساختمان ، از دستور 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و را تعريف مي كند كه ساختار خص شده است .

Nesta
27-04-2005, 01:00
دسترسي به اجزاي ساختمان

همانطوركه مشاهده شد هر ساختمان داراي چند جزئ است كه براي دسترسي به هر يك
از اجزاي آن از روش كلي زير استفاده مي شود :
<اسم متغير از نوع ساختمان >.<نام جزئ>
بعنوان مثال ، با فرض اين كه 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

Nesta
27-04-2005, 01:01
دسترسي به اجزاي ساختمان

همانطوركه مشاهده شد هر ساختمان داراي چند جزئ است كه براي دسترسي به هر يك
از اجزاي آن از روش كلي زير استفاده مي شود :
<اسم متغير از نوع ساختمان >.<نام جزئ>
بعنوان مثال ، با فرض اين كه 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

Nesta
27-04-2005, 01:01
ارزش دهي اوليه به ساختمان

مي توان به متغيرهاي از نوع ساختمان كه داراي كلاس حافظه استاتيك و خارجي
باشند ، همانند آرايه ها مقدار اوليه داد . براي اين منظور مقادير اوليه در بين {
و} قرار گرفته و با كاما از يكديگر جدا ميشوند. مقاديري كه به متغير ساختمان
قرار مي گيرند : اولين مقدار به اولين جزئ، دومين مقدار به دومين جزئ و 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 قرار گرفته و ن متغير مقدار صفر و اجزاي غيرعددي مقدار تهي را مي پذيرند.

Nesta
27-04-2005, 01:02
نتساب ساختمانها به يكديگر

در گونه هاي اوليه زبان 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

Nesta
27-04-2005, 01:02
آرايه اي از ساختمانها

يكي از بيشترين موارد كاربرد ساختمانها ، تعريف شدن بصورت آرايه مي باشد .
براي تعريف آرايه اي از ساختمان ، ابتدا بايد نوع ساختمان را تعريف كرده وهمانند
تعريف متغيرهاي معمولي ، آرايه اي از آن نوع را تعريف نمود . بعنوان مثال دستور 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-4:)1

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-4:)2

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-4:)3

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

Nesta
27-04-2005, 01:03
اجزاي يك ساختمان ميتوانند يك متغير معمولي ، آرايه و يا يك ساختمان باشند.
دو مورد اول را قبلا" مشاهده كرديم . در اين قسمت به بررسي مورد سوم مي پردازيم .
وقتي كه اجزاي يك ساختمان از نوع ساختمان باشند براي دسترسي به اجزاي آن بايد
اسامي متغيرهاي ساختمان را از بالاترين ساختمان به داخلي ترين ساختمان ذكر كرد.

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


#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 year:)25 12 70
enter name:ahmad
enter personel number:1231
enter date(day month year:)12 2 60
enter age: 30
enter name:mohammad
enter personel number:4323
enter date(day month year:)2 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

Nesta
27-04-2005, 01:04
ساختمانها و يا آرايه اي ازساختمان كه تاكنون در برنامه ها بكار گرفته شده اند
يا بصورت عمومي تعريف شدند و يا درتابعي كه مورداستفاده قرار مي گرفتند، تعريف
شدند . ساختمانها و يا اجزاي آنها مي توانند به عنوان آرگومان ، به تابع منتقل
شده و يا اطلاعاتي را به تابع فراخواننده برگردانند .
براي انتقال اجزاي ساختمان به تابع ، همانند يك متغير معمولي عمل مي شود .
با اين تفاوت كه نام متغير ساختمان را بايد به همراه جزئ مورد نظر، در آرگومان
تابع ذكر كرد و بايد توجه داشت كه پارامتر تابع نيز بايد همنوع با آرگومان
متناظر با آن تعريف گردد . بعنوان مثال ، ساختمان زير را در نظر بگيريد : 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

Nesta
27-04-2005, 01:17
در زبان 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-6:)1

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-6:)2

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-6:)3

<< 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-6:)5

<< 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-6:)4

<< 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 >>

Nesta
27-04-2005, 01:18
در زبان 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 year:)12 12 50
enter t

Nesta
27-04-2005, 01:19
، محلي از حافظه است كه توسط دو يا چند متغير بطور اشتراكي
مورد استفاده قرار مي گيرد . اين متغيرها بطور همزمان نمي توانند از اين محل
استفاده كنند بلكه هر متغير مي تواند در زمان هاي متفاوتي اين محل را مورد
استفاده قرار دهد .
نحوه تعريف 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

Nesta
27-04-2005, 01:19
قبلا" مشاهده شد كه اجزاي يك ساختمان مي توانند ، از نوع ساختمان باشند . به
طور كلي بكارگيري يك ساختمان در ساختمان ديگر ، 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

Nesta
27-04-2005, 01:20
دستور 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 :

Nesta
27-04-2005, 01:20
نوع داده شمارشي ، اين امكان را فراهم مي كند كه بتوان عناصر يك مجموعه
متناهي را نامگذاري يا شماره گذاري كرده وسپس متغيرهايي را تعريف نمود تا مقادير
آن مجموعه را بپذيرند . اين مجموعه با شناسه هايي معرفي مي شود كه به ثابت هاي
شمارشي معروفند . نوع هاي شمارشي بصورت زير تعريف مي شوند : {
نام نوع شمارشي 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

Nesta
27-04-2005, 01:21
داده هاي مورد نياز برنامه هايي كه تاكنون نوشته شده اند در متغيرهاي معمولي
آرايه ها و ساختمان ها ذخيره و مورد پردازش قرار گرفته اند . متغيرهاي معمولي
آرايه ها و ساختمان ها ، همگي در حافظه RAM قرار دارند . لذا پس از قطع جريان
برق ( و يا خاموش شدن كامپيوتر ) و يا خروج از برنامه ، داده هايي كه در آنها
ذخيره شده اند از بين مي روند و براي استفاده مجدد از آنها ، بايد مجددا" وارد
گردند كه قطعا"اين كار مقرون به صرفه نيست .زيرا نه تنها مستلزم صرف وقت زيادي
است بلكه حوصله انجام كار را نيز از برنامه نويس سلب مي نمايد . براي رفع اين
مشكل نوعي ساختمان داده ديگر به نام فايل مورد استفاده قرار مي گيرد . اين نوع
ساختمان داده بر روي حافظه جانبي مثل ديسك ، نوار و غيره تشكيل مي گردند . چون
اطلاعات موجود در روي حافظه جانبي با قطع جريان برق ، قطع اجراي برنامه و يا
دلايلي از اين قبيل از بين نميروند، به دفعات زيادي مورد استفاده قرار ميگيرند.
هر فايل شامل مجموعه اي از داده هاي مرتبط به هم است . مانند داده هاي مربوط
به كليه دانشجويان يك دانشگاه ، داده هاي مربوط به هر يك از اجزاي فايل ، يك
ركورد نام دارد . به عنوان مثال ، در يك دانشگاه داده هاي مربوط به هر دانشجو
تشكيل يك ركورد را مي دهند . لذا مي توان گفت كه هر فايل ، مجموعه اي از چند
ركورد است . اگر باز هم دقيق تر به فايل دانشجويان دانشگاه پرداخته شود، مشاهده
مي گردد كه هر دانشجو تشكيل يك ركورد را مي دهند . لذا مي توان گفت كه هر فايل
مجموعه اي از چند ركورد است . اگر باز هم دقيق تر به فايل دانشجويان دانشگاه
پرداخته شود ، مشاهده مي گردد كه هر دانشجو ممكن است چند قلم داده داشته باشد.
مثل نام دانشجو ، تعداد واحدهايي كه گذرانده ، نمره هر درس و ... . به هر يك از
اجزاي يك ركورد ، فيلد گفته مي شود ، لذا مي توان گفت كه هر ركورد مجموعه اي از
چند فيلد است .
در زبان C فايل داده ، مي تواند هر دستگاهي مثل : صفحه نمايش ، صفحه كليد
چاپگر ، ترمينال ديسك ، نوار و غيره باشد .
داده ها ممكن است به 4 روش در فايل ذخيره شده و سپس مورد بازيابي قرار گيرند: 1
داده ها، كاراكتر به كاراكتر در فايل نوشته شده و سپس كاراكتر به كاراكتر
از فايل خوانده شوند . 2
داده ها بصورت رشته اي از كاراكترها، در فايل نوشته شده وسپس بصورت رشته اي
از كاراكترها مورد دسترسي قرار گيرند . 3
داده ها درحين نوشتن بر روي فايل ، با فرمت خاصي نوشته شده و سپس با همان
فرمت خوانده شوند ( مثل توابع ()printf و ()scanf در ورودي خروجي معمولي ) . 4
داده ها به شكل ساختمان ( ركورد ) در روي فايل نوشته شده و سپس به صورت
ساختمان از فايل خوانده شوند . صي در زبان C منظور شده اند .

Nesta
27-04-2005, 01:22
داده ها ممكن است در فايل به دو صورت ذخيره شوند كه عبارتند از : 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 متفاوت است .

Nesta
27-04-2005, 01:22
منظور از سازمان فايل اين است كه اطلاعات در فايل چگونه ذخيره شده و سپس به
چه روش هايي مورد بازيابي قرار مي گيرند . يا بعبارت ديگر قانون حاكم بر نحوه
ذخيره و بازيابي داده ها و فايل را سازمان فايل گويند . حال به دو سازمان فايل
پرداخته مي شود : 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
ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤ اي از فايل تصادفي

Nesta
27-04-2005, 01:23
منظور از سازمان فايل اين است كه اطلاعات در فايل چگونه ذخيره شده و سپس به
چه روش هايي مورد بازيابي قرار مي گيرند . يا بعبارت ديگر قانون حاكم بر نحوه
ذخيره و بازيابي داده ها و فايل را سازمان فايل گويند . حال به دو سازمان فايل
پرداخته مي شود : 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
ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤؤ ؤؤؤؤؤؤ اي از فايل تصادفي

Nesta
27-04-2005, 01:23
هر فايل قبل از اين كه بتواند مورد استفاده قرار گيرد ، بايد باز گردد .
مواردي كه در حين باز كردن فايل مشخص مي شوند عبارتند از : 1
نام فايل 2
نوع فايل از نظر ذخيره اطلاعات (textيا binaryا) 3
نوع فايل از نظر ورودي خروجي ( آيا فايل فقط به عنوان ورودي است ، آيا
فقط بعنوان خروجي است يا هم بعنوان ورودي است و هم بعنوان خروجي ) .
يك فايل ممكن است طوري باز شود كه فقط عمل نوشتن اطلاعات بر روي آن مجاز
باشد . به چنين فايلي ، فايل خروجي گفته مي شود . اگر فايل طوري باز گردد كه
فقط عمل خواندن اطلاعات از آن امكان پذير باشد به چنين فايلي ، فايل ورودي گفته
مي شود . اگر فايل طوري باز شود كه هم عمل نوشتن اطلاعات بر روي آن مجاز باشد و
هم عمل خواندن اطلاعات از آن ، به چنين فايلي ، فايل ورودي و خروجي گفته ميشود.
اگر فايلي قبلا" وجود نداشته باشد ، در حين باز شدن بايد بعنوان فايل خروجي باز
شود . اگر فايلي قبلا" وجود داشته باشد و بعنوان خروجي باز گردد ، اطلاعات قبلي مي رود ، براي باز كردن فايل از تابع ()fopen استفاده مي گردد .

Nesta
27-04-2005, 01:24
تابع ()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

Nesta
27-04-2005, 01:24
پس از اين كه برنامه نويس كارش را با فايل تمام كرد ، بايد آن را ببندد .
بستن فايل توسط تابع ()fclose انجام مي شود كه داراي الگوي زير است : int fclose(FILE *fp)

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

Nesta
27-04-2005, 01:25
براي نوشتن يك كاراكتر در فايل ، از توابع ()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

Nesta
27-04-2005, 01:26
براي نوشتن رشته ها در فايل ، از تابع ()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

Nesta
27-04-2005, 01:26
در مثالهايي كه تاكنون مطرح گرديد، فايل يا فقط بعنوان وسيله ورودي استفاده
گرديد و يا فقط بعنوان وسيله خروجي ، در اين قسمت مشاهده خواهد شد كه چگونه
ميتوان يك فايل را هم بعنوان وسيله ورودي و هم بعنوان وسيله خروجي مورداستفاده
قرار داد. براي اين منظور كافي است در تابع ()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

Nesta
27-04-2005, 01:27
در حين انجام كار با فايل ها ممكن است خطايي رخ دهد . بعنوان مثال ، عدم
وجود فضاي كافي براي ايجاد فايل ، آماده نبودن دستگاهي كه فايل بايد در آنجا
تشكيل گردد و يا مواردي از اين قبيل منجر به بروز خطا مي شوند . با استفاده از
تابع ()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

Nesta
27-04-2005, 01:27
براي حذف فايل هاي غيرضروري مي توان از تابع ()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/n:)y

Nesta
27-04-2005, 01:28
بافر ، حافظه اي است كه به فايل ها اختصاص مي يابد تا اعمال ورودي خروجي
بر روي آنها با سرعت بيشتري انجام گيرد. در حين خروج از برنامه خوب است كه جهت
اطمينان بيشتر ، به ماشين دستور داد تا كليه داده هاي موجود در بافرها را به
فايل مربوطه منتقل مي نمايد. براي اين منظور مي توان از تابع ()fflush استفاده
نمود . اگر كار اين تابع با موفقيت انجام شود ، مقداري كه توسط آن برگردانده
مي شود برابر با صفر وگرنه برابر با EOF خواهد بود ( EOF ماكرويي است كه در
فايل stdio.h تعريف شده است ) . الگوي تابع ()fflush در فايل stdio.h قرار
داشته و بصورت زير است : int fflush( FILE *fp)

در الگوي فوق ، fp فايلي را مشخص ميكند كه تابع ()fflush بايد بر روي آن عمل
نمايد . اگر fp ذكر نشود تابع ()fflush بر روي كليه فايل هايي كه بعنوان خروجي
باز شده اند عمل مي كند . بعنوان مثال ، دستور (f)fflush موجب مي شود تا كليه به فايل با اشاره گر f ، در اين فايل نوشته شوند

Nesta
27-04-2005, 02:07
اگر لازم باشد كه داده ها با فرمت خاصي در فايل نوشته و يا از آن خوانده شوند
مي توان از دو تابع ()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 استفاده گردد .

Nesta
27-04-2005, 02:08
همانطوركه تاكنون مشاهده گرديد توابع زيادي براي انجام اعمال ورودي خروجي
فايل وجود دارند . دو تابع ()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

Nesta
27-04-2005, 02:09
حل يك مساله از طريق فايلهاي ترتيبي

تاكنون با نحوه تشكيل فايل هاي ترتيبي و چگونگي دسترسي به اطلاعات موجود در
آن آشنا شده ايم . اكنون مساله پيچيده تري را در نظر مي گيريم : يك فايل داده به
نام 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

Nesta
27-04-2005, 02:10
دسترسي تصادفي به فايل ( ورودي خروجي تصادفي )

دربرنامه هايي كه تاكنون نوشته اند،ازسازمان فايل ترتيبي براي ذخيره وبازيابي
اطلاعات استفاده شده است . در اين قسمت چگونگي تشكيل تصادفي مطرح شده و طريقه
دسترسي به اطلاعات موجود در آنها مورد بررسي قرار مي گيرند.
براي دسترسي تصادفي به فايل هااز تابع ()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 ناحيه ركورد قبل از ركورد دوم و ... به هدر مي روند ، اين موارد را شايد
بتوان به عنوان يكي از معايب فايل تصادفي در نظر گرفت ولي معمولا" مكانيزمهايي ي بهبود اين حالت منظور مي شود .

Nesta
27-04-2005, 02:10
دستگاههاي ورودي خروجي استاندارد

وقتي اجراي يك برنامه به زبان 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و از صفحه كليد خوانده شوند .
دستگاه هاي استاندارد ورودي خروجي همانطور كه بطور اتوماتيك باز مي شوند،به
طور اتوماتيك نيز بسته خواهند شد و نياز به بستن آنها توسط برنامه نويس نيست .

Nesta
27-04-2005, 02:11
توابع كتابخانه اي ( قسمت اول )

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

Nesta
27-04-2005, 02:12
مقدمه
نمي دانم تا حالا به مشكل "زبانها" برخورد كرده ايد يا نه ... بنظر من تمامي زبانها در 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 پاسكال قرار دارد . )

Nesta
27-04-2005, 02:12
اشاره گرها
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 (&
;( و " و " و " &) fwrite
پاسكال
; ( نام متغير فايل و نام متغير ركورد read(
;( نام متغير فايل و نام متغير ركوردWrite (
; ( نام متغير كاراكتري follower = نام متغير كاراكتري
دستور حذف يك كاراكتر را به حرف كوچك تبديل ميكند .

Linklist

C پاسكال
{ نام ساختمان struct ; نام ركورد ^ = نام اشاره گر
; نام فيلد نوع فيلد record = نام ركورد
" " نوع فيلد : اسم فيلد
" " " "
; نام فيلد نوع فيلد " "
; نام فيلد آدرس * نام ساختمان struct ; نوع فيلد : نام فيلد
}; ; نام اشاره گر : اسم فيلد آدرس
End;
نكته : در زبان C براي تعريف اشاره گر هاي خارجي داريم :
C پاسكال
; نام اشاره گر * نام ساختمان struct
براي ايجاد گره داريم
C پاسكال
((نام ساختمان struct)sizeof)Malloc ( *نام ساختمان struct)= نام اشاره گر ساختمان var ; نام ركورد : نام متغير

magic
01-04-2006, 01:46
خيلي ممنون از لطفتون
دوستار شما Magic

farinaz
13-06-2006, 12:07
عالی بود ...جامع و کامل ..........مرسی از لطفتون

niyazmande javab
15-06-2006, 18:41
very cool man!thanks a lot

shahabamo
30-08-2006, 10:59
دست درد نكنه ولي اگه يه نسخه pdf اش رو هم ميزاشتي ديگه محشر ميشد.

RP2010
17-01-2011, 21:50
میشه یه مسئله حل کنید