|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
קורס:"שפת C"
מתוך הספר: C - מדריך מקצועי
קלט / פלט של תו בודדכפי שראינו בפרק 2, "הכרת שפת C", קריאת וכתיבת תו בודד מבוצעת ע"י הפונקציות getchar() ו- putchar(). שתי אלה מוגדרות בספרייה התקנית של C כפונקציות מקרו (באמצעות הקדם מעבד) בקובץ stdio.h. getchar()זוהי פקודת הקלט הפשוטה ביותר אשר בעזרתה ניתן לקרוא תו אחד מהקלט הסטנדרטי (בדרך כלל המקלדת). פונקציה זו מחזירה את תו הקלט הבא בכל פעם שהיא נקראת. לדוגמא, בכדי לקרוא תו מהקלט נבצע: int ch; ch = getchar();
שאלה: מדוע התו מוגדר כ- int ולא כ- char? תשובה: סוף הקלט מצוין ע"י הקבוע EOF המוגדר בספרייה stdio.h כך:
#define EOF (-1)
בהגעה לסוף הקלט, הפונקציה getchar() מחזירה את EOF. משום כך על הערך המוחזר של הפונקציה להיות מטיפוס שלם, הכולל גם את תחום הערכים השליליים. לדוגמא, הלולאה הבאה מונה את כלל התווים שנקראו מהקלט: while (getchar()!=EOF) ++chars_no; שאלה: כיצד מסמנים סוף קובץ קלט ע"י המקלדת? תשובה: במערכת ההפעלה Windows ע"י Ctrl-Z, וב- Unix ע"י Ctrl-D. putchar()זוהי פקודת הפלט הפשוטה ביותר אשר כותבת לפלט הסטנדרטי ( בדרך כלל המסך ) את התו הנתון לה כפרמטר: putchar(ch);
לדוגמא, ההוראה putchar('A'); תדפיס: A 'A' הוא ערך ASCII של התו A, כלומר 65. לכן ניתן להדפיס את התו A גם ע"י ההוראה: putchar(65); בדומה ל- getchar(), גם putchar() מטפלת בטיפוס int ולא char בכדי לאפשר הדפסת תו סוף קובץ, EOF. תכנית הדוגמא הבאה קולטת תו מהמשתמש (באמצעות המקלדת) ומדפיסה אותו למסך: #include <stdio.h> void main ( ) { int ch; ch = getchar(); putchar(ch); } קריאת תווי קלט וניתוחםנכתוב מספר תכניות למניית תווים, שורות ומילים בקבצי טקסט. בתכניות אלו נעשה שימוש בפונקציות קלט פלט, ובמרכיבים בסיסיים בשפת C שהכרנו עד כה. תכנית למניית תוויםהתכנית הבאה מונה את מספר תווי הקלט שנקראו ומדפיסה מספר זה: /* file: count_chars.c */ #include <stdio.h> void main () { long chars_no=0; while (getchar()!=EOF) ++chars_no; printf("Read %ld chars\n", chars_no); } אם נריץ את התכנית ונקליד את הקלט הבא: This file is a stream of text chars. It can have all kinds of characters: a, z, 3, *, &, @, { }, ש, ת ; | / ? > _ = + יתקבל הפלט: Read 118 chars הסבר: התכנית קוראת תווים מהקלט - שהוא זרם תוים - עד להגעה לתו מסיים קובץ (EOF):
תרגולקרא/י סעיף זה בספר ובצע/י את תר' 1-2 שבעמ' 89.
מניית שורותהקלט הוא זרם תווים המסתיים בתו מסיים קובץ (EOF). בתוך זרם התווים, נמצא תו מיוחד ('\n') המציין מעבר שורה חדשה:
נכתוב תכנית למניית מספר השורות בקלט. לספור את השורות פירושו לספור תווי "שורה חדשה" בקלט, כלומר כמה פעמים הופיע התו מסיים השורה ('\n') בזרם הטקסט שבקלט. אלגוריתם התכנית:
קוד התכנית: /* file: count_lines.c */ #include <stdio.h> void main () { int c; int lines_no=0; while ((c=getchar())!=EOF) { if (c=='\n') ++lines_no; } printf("Read %d lines\n",lines_no); } אם נריץ את התכנית ונקליד את הקלט הבא: This is the first line. This is the second line. This is the third line. יתקבל הפלט: Read 3 lines תרגולקרא/י סעיף זה בספר ובצע/י את תר' 1-2 שבעמ' 91.
מניית מיליםכדי לספור מילים צריך להגדיר מילה. אנו נגדיר מילה בצורה פשוטה:
בפועל גם תווי פיסוק מפרידים בין מילים - אנו נתעלם מהם בשלב זה. למנות מילים פירושו למנות כמה פעמים הופסק זרם התוים ע"י תו לבן - כלומר תו רווח, טאב או תו שורה חדשה:
הרעיון: נגדיר משתנה מצב (state) שיציין במהלך קריאת התווים אם אנו בתוך מילה (INSIDE) או מחוץ לה (OUTSIDE). בכל מעבר ממצב OUTSIDE למצב INSIDE נקדם את מונה המילים. האלגוריתם:
קוד התכנית והסבר מובאים בעמ' 93. קרא/י סעיף זה בספר ובצע/י את תר' 1-3 שבעמ' 94. פלט לפי תבנית ע"י printfפונקצית הספריה printf משמשת להדפסת פלט מורכב: היא כוללת אפשרויות לשילוב טקסט עם ערכי משתנים, רווח, הצמדה ואפשרויות נוספות. הטכניקה שבה היא פועלת כוללת מחרוזת בקרה ופרמטרים להדפסה: int printf ("מחרוזת בקרה", <<פרמטר2>, <פרמטר1 ...); מחרוזת הבקרה מורה ל- printf כיצד והיכן להציב את הפרמטרים בשורת הפלט. היא כוללת את המלל שברצוננו להציג, ביחד עם מצייני הפורמט (format specifiers) המתארים את הטיפוס והמיקום של הפרמטרים. לדוגמא: printf("The %d exam grades are %f and %f", 2, 87.5, 93.4); הפלט: The 2 exam grades are 87.500000 and 93.400000
כל מציין פורמט מתחיל בתו האחוזים (%) ואחריו אות המסמנת את טיפוס הפרמטר:
הטבלה שבעמ' 95 מפרטת את מצייני הטיפוס עפ"י קטגוריות הטיפוסים. דוגמאות פשוטות:
דוגמאות מורכבות יותר:
קביעת תצורת הפלטריווחבפונקציה printf ניתן לשלוט בריווח השורה ובמספר התווים המוצגים לכל שדה. לדוגמא, הוראת ההדפסה printf("%f %d %s\n", 45.583f, 5, "hello"); תציג למסך: 45.583000 5 hello ניתן לקבוע את רוחב השדה בהדפסת פרמטר מסוים ע"י הצבת מספר בין הסימן % למציין הטיפוס. לדוגמא, את הנתונים מההדפסה הקודמת נדפיס בשדה ברוחב 8 תווים: printf("%8f%8d%8s\n", 45.583f, 5, "hello"); יודפס:
כפי שניתן לראות, רוחב השדה הכולל הוא מינימום - אם הנתון כולל מספר תווים גדול מרוחב השדה הוא יודפס במלואו, לכן הפרמטר הראשון מודפס על פני 9 מקומות ולא 8. הפרמטר השני, 5, מודפס על פני 8 מקומות ומוצמד לחלק הימני שלהם. גם הפרמטר השלישי, "hello" , מודפס על פני 8 מקומות ומוצמד ימינה.
דיוקניתן גם לקבוע את הדיוק שמשמעותו היא בהתאם לטיפוס:
הדיוק מצויין מימין לנקודה במחרוזת הבקרה: printf("%8.2f%8.4d%8.3s\n", 45.583f, 5, "hello"); יודפס:
הצמדהבברירת מחדל, המספרים המודפסים מוצמדים לימין בפלט. כדי לבצע הצמדה לשמאל של המספרים, מציבים סימן "-" לפני ערך רוחב השדה. לדוגמא: printf("%-8.2f%-8d%-8s\n", 45.583f, 5, "hello"); יודפס:
מצייני פורמט נוספיםמצייני הפורמט הבאים מוצבים בין הסימן % למציין הטיפוס, או לרוחב השדה - אם קיים. קביעת short (h) ו- long (l) לשלמים:התו h המופיע בין הסימן % למציין טיפוס שלם מציין שהפרמטר הוא מסוג short, והתו l מציין שהפרמטר מסוג long: short s1 = 1234; long l1 = 123456789L; printf("%ld %hd", l1, s1); קביעת long (L) לממשיים:התו L המופיע בין הסימן % למציין טיפוס ממשי מציין שהפרמטר הוא מסוג long double: long double ld = 34E+33; printf("%Lg", ld); הצגת אפסים מקדימים (0):התו 0 (אפס) בין הסימן % לרוחב השדה מציין מילוי באפסים: printf("%08.2f %d\n", 45.58f, 5); יודפס: 00045.58 5 כפי שראינו קודם, עבור שלמים מציין הדיוק גם הוא משמש למילוי אפסים לצורך הדפסת מספר ספרות מינימלי. קביעת הרווח ע"י פרמטרים (*)התו * המופיע בין הסימן % למציין הטיפוס מציין שרוחב השדה נמצא ברשימת הפרמטרים במקום המתאים. לדוגמא: printf("%*.*f %d\n", 8, 2, 45.583f, 5); יודפס: 45.58 5 קביעת תצורה ע"י #התו #המופיע בין הסימן % למציין הטיפוס מציין תצורה שונה להדפסות הבאות:
לדוגמא, פלט ההוראה הבאה printf("%g %x\n", 45.0f, 0xF5); הוא 45 f5 כעת, אם נוסיף את התו # במחרוזת הבקרה: printf("%#g %#x\n", 45.0f, 0xF5); יודפס: 45.0000 0xf5 הדפסת +התו + המופיע בין הסימן % למציין הטיפוס מציין הדפסת מספר חיובי עם הסימן +. (אם המספר הוא שלילי מודפס הסימן "-" ללא תלות במציין זה). דוגמא: printf("%+d %+7.2f %+d", 22, 23.44, -15); יודפס: +22 +23.44 -15 תרגולקרא/י סעיף זה בספר ובצע/י את תר' 1-2 שבעמ' 98-99.
קלט לפי תבנית ע"י scanfהפונקציה scanf מבצעת קריאת קלט עפ"י פורמט. השם scanf הוא קיצור של scanf היא פונקציה מקבילה ל- printf הקוראת מהקלט לתוך רשימת פרמטרים עפ"י פורמט נתון, אך עם הבדל אחד משמעותי: במקום הפרמטרים עצמם מועברות הכתובות שלהם. לדוגמא, בפעולת הקלט למשתנה ממשי float amount; scanf("%f", &amount); מועברת כתובת המשתנה, &amount, לפונקציה scanf:
הפונקציה scanf קוראת נתונים מהקלט לתוך כתובות שניתנות לה כפרמטרים. האופרטור & מציין "הכתובת של": הצבתו לפני שם המשתנה מציינת התייחסות לכתובתו - נעסוק במצביעים בהרחבה בפרק 8, "מצביעים". scanf מתעלמת מהתווים ה"לבנים" - רווח, טאב ותו שורה חדשה - אלא אם כן סוג הנתון הוא תווי. לדוגמא: int num; scanf("%d", &num); printf("The number is %d", num); אם בקלט יהיה כתוב "123abc", הפונקציה תקרא את המספר 123 ותתעלם מהאותיות abc, כיוון שאינן ספרות. שאלה: מה היה קורה לו במחרוזת הבקרה היה כתוב %x במקום %d? תשובה: abc ספרות חוקיות במספור הקסה-דצימלי ולכן הן היו נקראות. המספר הנקרא היה 0x123ABC. מצייני הטיפוסהטבלה שבעמ' 100 כוללת את מצייני הטיפוסים עבור scanf. scanf מנסה להתאים כל תו הנמצא במחרוזת הבקרה לקלט, כולל רווחים. לדוגמא, אם נרצה לקלוט 2 מספרים - שלם וממשי - מופרדים ע"י הסימן "^" נכתוב: int inum; float fnum; printf("Enter an integer and a float, separated by ^\n"); scanf("%d ^ %f", &inum, &fnum); printf("%d %f", inum, fnum); עבור הקלט Enter an integer and a float, separated by ^ 23 ^ 23.45 יודפס 23 23.450001 דוגמאותנניח שמוגדרים המשתנים int inum; float fnum; char ch; וכמו כן נניח שמוגדר טיפוס מחרוזת ומשתנה מחרוזת: typedef char String[256]; String str; הטבלה הבאה כוללת דוגמאות להוראות קלט ומבנה קלט מתאים:
בדיקת הצלחת פעולת הקלטכאשר מבצעים פעולת קלט, יש לוודא שהקלט נקרא באופן תקין. לדוגמא, אם המשתמש מתבקש להקליד מספר ובמקום זאת הוא מקליד אות, הקלט אינו תקין. שאלה: כיצד נדע אם הקלט הצליח ? תשובה: הפונקציה scanf מחזירה את מספר הפרמטרים שנקראו באופן תקין מהקלט. ניתן להשתמש בערך זה כדי להחליט אם הקלט היה תקין. לדוגמא: #include <stdio.h> void main() { int num1; float num2; int n; printf("Please enter 2 numbers - integer and real: "); n = scanf("%d %f", &num1, &num2); if(n!=2) printf("Incorrect input!"); else printf("The numbers are: %d %.2f", num1, num2); } בתכנית מבקשים מהמשתמש להקליד שני מספרים, שלם וממשי. המשתנה n משמש לקריאת הערך המוחזר מהפונקציה scanf n = scanf("%d %f", &num1, &num2); במידה וערך זה שונה מהערך הצפוי - 2 - מדפיסים הודעת שגיאה למשתמש. דוגמא להרצת התכנית עם קלט שגוי: Please enter 2 numbers - integer and real: 12 word Incorrect input! קלט / פלט של מחרוזותכפי שראינו, מחרוזת היא מערך תווים המסתיים בתו מסיים מחרוזת. הדפסת מחרוזת אפשרית ע"י הפונקציה printf בתוספת מזהה הטיפוס %s: typedef char String[256]; String str = "hello"; printf("%s",str); או בקיצור: printf(str); קריאת מחרוזות מתבצעת ע"י מזהה הטיפוס %s , לדוגמא: scanf("%s",str); מחרוזת היא מקרה מיוחד - אין צורך באופרטור הכתובת "&" מכיוון ששמה הוא כתובתה. בפרק 8, "מצביעים", נרחיב בנושא כתובות המשתנים והפרמטרים לפונקציות. קלט / פלט שורת טקסט ע"י gets ו- putsקיימות פונקציות קלט / פלט ייעודיות לקריאה וכתיבה של מחרוזת הפרושה על שורה שלמה:
שתי הפונקציות מוצהרות בקובץ הספרייה stdio.h ומקבלות כפרמטר מחרוזת:
עיין/י בתכנית הדוגמא שבעמ' 103. ניתוב קלט / פלט (I/O Redirection)הפעלת התכנית ממערכת ההפעלהלאחר הידור התכנית נוצר קובץ ביצוע הניתן להרצה ממערכת ההפעלה. אופן ההפעלה תלוי במערכת ההפעלה בה עובדים. לדוגמא, ב- Windows ניתן להפעיל את התכנית מתוך מנהל הקבצים ע"י הקשה כפולה על קובץ הביצוע של התכנית (exe) . כמו כן ניתן להפעילה מתוך חלון DOS ע"י הקלדת שמה והקשה על Enter. אם שם התכנית הוא prog.exe והיא נמצאת בספרייה c:\c_course נבצע: c:\c_course> prog קלט התכנית יינתן ע"י המקלדת ופלט התכנית יוצג למסך. קלט / פלט תקני (Standard I/O)כאשר התכנית מבצעת פעולות קלט / פלט ע"י printf או scanf למשל, היא אינה "יודעת" מהיכן מגיע הקלט ולאן מופנה הפלט. קלט/פלט תקני (Standard I/O) הוא התייחסות כללית למקור הקלט וליעד הפלט של התכנית. אלה תלויים באופן ההפעלה של התכנית ע"י המשתמש. בברירת מחדל, מקור קלט התכנית הוא המקלדת ויעד הפלט הוא המסך:
ניתוב הקלט והפלטהמשתמש יכול לקבוע את מקור הקלט ואת יעד הפלט בהפעלת התכנית. לדוגמא, ניתן להפנות את הפלט לקובץ במקום למסך: c:\c_course> prog > prog.out
התכנית prog.exe תופעל והפלט שלה המבוצע ע"י ההוראות putchar, printf, puts ינותב לקובץ prog.out. למסך לא יודפס דבר. כמו כן ניתן לקרוא מקובץ את קלט התכנית במקום מהמקלדת. לדוגמא, אם נרצה לקרוא קלט לתכנית prog.exe מהקובץ prog.in נבצע: c:\c_course> prog < prog.in כעת התכנית לא תמתין לקלט מהמקלדת ע"י המשתמש, אלא תקרא את הנתונים מהקובץ באופן רציף ותמשיך בביצוע:
ניתן לשלב את השניים - כלומר לקרוא מקובץ ולכתוב לקובץ: c:\c_course> prog < prog.in > prog.out
במערכות הפעלה רבות קבצים מתארים התקני מערכת, ולכן ניתן להשתמש בהפניית קלט/פלט לקבצים כדי לפשט פעולות מורכבות. לדוגמא, תחת מערכות ההפעלה Windows / DOS הקובץ prn מתאר את המדפסת - לכן ניתן להדפיס את פלט התכנית prog.exe ע"י: c:\c_course> prog > prn
סיכום
תרגילי סיכוםבצע/י את תרגילי הסיכום שבעמ' 106.
|