מבוא לתכנות ולמדעי המחשב בשפת C/הדפסה, אריתמטיקה, משתנים, טיפוסים וקלט

מתוך ויקיספר, אוסף הספרים והמדריכים החופשי

תבנית:ניווט מבוא

הדפסת מספרים[עריכה]

השם של פקודת ההדפסה שראינו, printf, משמעו - print formatted כלומר, הדפסה בפורמט. הפקודה יודעת לשלב טקסט עם נתונים שונים ולהציג אותם יחד בפורמט קריא. הקוד הבא, לדוגמה, גורם להדפסת טקסט עם מספר שלם ומספר רציונאלי:

#include <stdio.h>
 
int main() {
	printf("An integer number: %d, a real number: %f \n",12,3.141); 
	return 0; 
}

אחרי שמירת הקובץ, הידור והרצה, נקבל את הפלט הבא:

An integer number: 12, a real number: 3.141000

בתוך מחרוזת ההדפסה שילבנו שני סימנים מיוחדים: d% ו- f%.

המשמעות של d% היא שאנו מתכוונים להדפיס במקומו מספר שלם בהצגה עשרונית (decimal, מכאן ה- d בסימון).

את המספר, 12, שאמור להחליף את d% המחרוזת, כתבנו כפרמטר נוסף אחרי המחרוזת.

המשמעות של f% הוא מספר ממשי (מיוצג בהצגה של נקודה צפה, floating point ומכאן ה-f שבסימון). המספר 3.141 יחליף את הסימון f% בהדפסה אך כפי שניתן לראות הוא מוצג עם שני ספרות אפס עוקבות, שלא משנות כמובן את ערכו. printf מאפשרת שליטה מעודנת יותר בצורת ההדפסה של מספר ממשי. הנה מספר דוגמאות.

אריטמטיקה בסיסית[עריכה]

הקוד הבא:

#include <stdio.h>
int main() {
	printf("12 + 3 = %d\n", 12+3); 
	return 0; 
}

מייצר את הפלט הזה:

12 + 3 = 15

ערך הביטוי 12+3 שכתבנו כפרמטר שאמור להחליף את הסימון d%, מחושב והתוצאה, 15 היא זו שמחליפה את ה - d% במחרוזת ההדפסה.

הנה מספר דוגמאות נוספות:

#include <stdio.h>
int main() {

	printf("\nA. I know how to multiply: %d\n", 12*3); 

	printf("\nB. And how to divide: %d\n", 12/3); 

	printf("\nC. But what if the result is not an integer: %d\n", 12/5); 

	printf("\nD. Oh, one should note that integer devision is actualy truncated to the floor value.\n");
	printf("If you want a rational result, make it explicit that you deal with rationals: %f\n", 12.0/5.0 ); 
	
	return 0; 
}

פלט:

A. I know how to multiply: 36

B. And how to divide: 4

C. But what if the result is not an integer: 2

D. Oh, one should note that integer devision is actualy truncated to the floor value.
If you want a rational result, make it explicit that you deal with rationals: 2.400000

כפי שניתן לראות מהדוגמה, חלוקה של מספרים שלמים נותנת את החלוקה השלמה (ללא השארית). אם רוצים תוצאה של שבר, יש להתייחס למספרים שבחלוקה כמספרים רציונאליים. למעשה מספיק שרק אחד מהם יהיה רציונאלי:

#include <stdio.h>
int main() {

	printf("\nNote that this cases compilation warnning and meaningless output: %f\n", 12/5); 

	printf("\nOnly the devided number is explicitly float: %f\n", 12.0/5); 

	printf("\nOnly the devidor is explicitly float: %f\n", 12/5.0); 
	
	return 0; 
}

פלט:

Note that this cases compilation warnning and meaningless output: 0.000000

Only the devided number is explicitly float: 2.400000

Only the devidor is explicitly float: 2.400000

הסיבה לאזהרת הקומפילציה כתוצאה מפקודת ההדפסה הראשונה היא שהיתה חוסר התאמה בין טיפוס הביטי 12/5 - שלם (int) לבין מה ש f% מצפה - שבר (נקודה צפה - float או double). במקרה כזה הפלט הוא חסר משמעות.

שתי ההדפסות הבאות מדגימות את מה שרצינו להראות, שבחלוקה, מספיק שרק אחד המספרים הוא מטיפוס רציונאלי בכדי שהתוצאה תהיה מטיפוס רציונאלי.

משתנים[עריכה]

המושג "משתנה" בתוכנה מייצג מקום בזכרון שבו אפשר לשמור ערכים. למרות שיש דמיון מסויים למושג "משתנה" באלגברה, יש הבדל משמעותי. באלגברה, מדובר בעצם בנעלם, ערך לא ידוע שמיוצג ע"י אות לועזית (או מחרוזת של אותיות). בתוכנה, מדובר על מקום בזכרון שמיוצג ע"י אות (או מחרוזת). משתנה בתוכנה מכיל בכל רגע נתון ערך מסויים. ערך זה יכל להשתנות בעתיד. אפשר לחשוב על משתנה כמו קופסא עם שם. בקופסא אפשר לשים ערך ולאחר מכן אפשר לשים במקומו ערך אחר.

לכל משתנה ב- C יש טיפוס (type). הטיפוס מציין את סוג הערכים שהמשתנה יכל להכיל. לדוגמה, טיפוס int מציין שמשתנה יכל לקבל רק מספרים שלמים. הנה דוגמה:


#include <stdio.h>
 
int main() {

	int a; 

	a = 17; 
	printf("The value of a is: %d\n",a);

	a = 181; 
	printf("Now a contains: %d\n",a);

	a = a + 1; 
	printf("a's value: %d\n",a);

	return 0; 
}

פלט:

The value of a is: 17
Now a contains: 181
a's value: 182

הסבר: בשורה 5 של הקוד הנ"ל, יש הצהרה על משתנה בשם a שהטיפוס שלו הוא int. המשתנה a נועד להכיל רק מספרים שלמים.

שורה 7 היא פקודת השמה לא השוואה. פקודה זו לא צריך לראות כמו משוואה מתמטית אלא כהוראה לשים בתוך המשתנה a את הערך 17. מכיוון שהטיפוס של הערך 17 גם הוא int כלומר מספר שלם, ההשמה היא חוקית.

(הערה: השימוש של שפת C בסימן '=' עבור פעולת השמה עלול להיות מבלבל. פעולת ההשמה איננה סימטרית: באגף הימני נמצא ערך ובאגף השמאלי נמצא משתנה שבו מאכסנים את הערך. ישנן שפות תכנות אחרות שבהם נהוגים סימונים לא סמטריים כמו =: או -> לפעולת ההשמה)

שורה 8 היא פקודת הדפסה רגילה. במקום ערך מספרי אליו היינו רגילים, מופיע המשתנה a. התוצאה היא הדפסת ערכו של a על המסך.

שורה 10 היא פקודת השמה נוספת. השמה של ערך חדש ב a מוחקת את הערך הישן שהיה בו. הפקודה הבאה היא פקודת הדפסה שתדפיס את הערך החדש - 181.

בשורה 13 אנו משימים ל a את הערך שמתקבל ע"י הערך שהיה בו בתוספת 1. שימו לב שכמשוואה מתמטית מדובר במשוואה ללא פתרון - אין אף מספר ששווה לעצמו ועוד אחד. דוגמה זו מחדדת את ההבדל בין משתנה לנעלם ובין פעולת השמה למשוואה. התוצאה של הפקודה שתארנו היא הגדלת הערך של a ב - 1. ההדפסה בשורה הבאה תהיה, אם כן, 182.

הדוגמה הבאה מדגימה שימוש במספר משתנים:

<

#include <stdio.h>
 
int main() {
	int a,b; 
	a = 17; 
	b = 21;  
	printf("The value of a+b is: %d, the value of a*b is: %d\n",a+b,a*b);
	int myResult = b-a; 
	printf("myResult = %d\n",myResult);
	return 0; 
}

פלט:

The value of a+b is: 38, the value of a*b is: 357
myResult = 4

כפי שניתן לראות, אפשר להצהיר על מספר משתנים מאותו טיפוס בפקודה אחת (שורה 4). משתנים יכולים להופיע במסגרת ביטוי אריתמטי (שורות 7 ו-8).שם משתנה יכול להכיל מחרוזת של אותיות (שורה 8) בשילוב מספרים ומספר סימנים נוספים.

טיפוסים בסיסיים[עריכה]

כאמור, טיפוס של ערך מגדיר את סוג האינפורמציה שלו. טיפוס של משתנה הוא טיפוס הערכים שהוא יכל להכיל. הטיפוסים הבסיסיים הם מספרים שלמים, מספרים רציונאליים ותוים. הדוגמה הבאה מראה שימוש בכולם:

#include <stdio.h>
 
int main() {
	int a = 17; 
	float b = 17.3; 
	char c = 'Y'; 
	
	printf("%d %f %c \n",a,b,c); 
	
	long a1 = 17; 
	double b1 = 17.3; 

	printf("%ld %lf \n",a1,b1); 
	
	printf("sizeof(char) = %d ( = %d) \n", sizeof(c), sizeof(char)); 
	printf("sizeof(int) = %d, sizeof(long) = %d \n", sizeof(int), sizeof(long)); 
	printf("sizeof(float) = %d, sizeof(double) = %d \n", sizeof(b), sizeof(b1)); 

	return 0; 
}

פלט:

17 17.299999 Y 
17 17.300000 
sizeof(char) = 1 ( = 1) 
sizeof(int) = 4, sizeof(long) = 4 
sizeof(float) = 4, sizeof(double) = 8

הסבר: את הטיפוסים int ו - float כבר הכרנו. הטיפוס char (קיצור של character - תו) משמעו תו בודד. בשורה 6 יצרנו משתנה מסוג char בשם c ונתנו לו את הערך Y (התו הבודד של האות הלועזית "וואי" גדולה). בשורה 8 אנו מדפיסים את ערכם של שלושת המשתנים שהגדרנו. שימו לב לשימוש ב - c% בכדי לציין ל - printf להדפיס ערך מטיפוס char.

אולי שמתם לב שבפלט, ההדפסה של ערך המשתנה b שונה במקצת מהערך שהשמנו לו. ההבדל הוא של מליונית ונובע משיטת הנקודה הצפה - האופן שבו נשמרים מספרים רציונאלים בזכרון.

בשורה 10 אנו מגדירים משתנה מסוג long, טיפוס שנועד לערכים של מספרים שלמים גדולים. על המערכת שלנו אין הבדל מעשי בינו לבין int. בשורה 11 אנו מגדירים משתנה מסוג double. טיפוס זה דומה במהותו לטיפוס float, אך מסוגל להכיל טווח ערכים גדול יותר בזכות שימוש במקום רב יותר בזכרון המחשב. בשורה 13 מדפיסים את ערכי שני המשתנים החדשים. שימו לב לשימוש בסימנים ld% ו - lf% במקום d% ו- f%. ה - l באה לציין long - ארוך. מספר ארוך בהצגה עשרונית ומספר נקודה צפה ארוך.

השורות הבאות משתמשות בפקודה חדשה - sizeof. פקודה זו מאפשרת לדעת כמה מקום בזכרון דורש טיפוס מסויים. היחידה בה נמדד הגודל הזה היא byte. בהמשך נדון המשמעות המדוייקת של byte אך בשלב זה מספיק להבין שמדובר בכמות זיכרון קטנה. ככל שטיפוס דורש יותר byte-ים (או בעברית - בתים), הוא יכל להכיל יותר אינפורמציה.

לפקודה sizeof אפשר לתת טיפוס או משתנה. אם היא מקבלת טיפוס, היא תתן את מספר הבתים הדרושים לאיכסונו בזכרון.אם היא מקבלת משתנה היא תתן את מספר הבתים הדרושים לאכסון המשתנה בזכרון או בלמילים אחרות את ה sizeof של טיפוסו.

ההדפסות בשורות 15-17 מדפיסות את מספר הבתים הדרושים לטיפוסים השונים. שימו לב שחלק מהגדלים הם תלויי מערכת. כלומר, על מחשב אחר, מערכת הפעלה אחרת או מהדר אחר, אנו עלולים לקבל תוצאות שונות עבור אותה תוכנית מחשב.


הערה: לא פירטנו כאן ממש את כל הטיפוסים הבסיסיים של שפת C. השפה מאפשרת גם להשתמש בטיפוסים המכילים רק מספרים חיוביים. הדבר נעשה ע"י שימוש במילה השמורה unsigned אבל בשלב זה לא נדבר על משתנים מסוג זה.

קליטת נתונים מהמשתמש[עריכה]

קליטת נתונים מהמשתמש מתבצעת באמצעות הפקודה scanf. הנה תוכנית לדוגמה:

#include <stdio.h>
 
int main() {
	printf("Please enter an integer: "); 
	int a; 
	scanf("%d", &a);  
	printf("The number you have entered: %d \n",a); 
	return 0; 
}

הרצה: (במקרה זה המשתמש הקליד 12)

Please enter an integer: 12
The number you have entered: 12

הסבר: הפקודה החדשה היחידה בקוד הזה היא ה - scanf. כפי שניתן לראות, היא משתמשת באותם מוסכמות של printf בכדי לציין איזה טיפוס של משתנה היא מצפה לקבל. במקרה זה היא מצפה ל int ואמורה לשמור את הערך שתקבל מהמשתמש במשתנה a. שימו לב שהכרחי להוסיף לפני המשתנה את הסימון &. את המשמעות של הסימן הזה נבין בהמשך, כאשר נדבר על מצביעים.

הנה דוגמה נוספת עם טיפוסים אחרים:

#include <stdio.h>
 
int main() {
	printf("char: "); 
	char c; 
	scanf("%c", &c);  

 	printf("float: "); 
	float a; 
	scanf("%f", &a);  

	printf("double: "); 
	double b; 
	scanf("%lf", &b);  
 
	printf("%c, %f, %lf \n", c, a, b);  
	return 0; 
}

פלט:

char: Q
float: 12.2
double: 13.4321
Q, 12.200000, 13.432100

תבנית:ניווט מבוא