שפת C/פעולות חשבוניות: הבדלים בין גרסאות בדף

תוכן שנמחק תוכן שנוסף
Atavory (שיחה | תרומות)
Atavory (שיחה | תרומות)
אין תקציר עריכה
שורה 8:
שפת C מאפשרת לחבר (ע"י +), לחסר (ע"י -), להכפיל (ע"י *), לחלק (ע"י /), ולמצוא שארית (ע"י %). להלן מספר דוגמאות:
 
<source lang = "cpp">
<div style="text-align:left; direction:ltr;">
<pre>
int x = 2, y = 3;
 
שורה 23 ⟵ 22:
/* Prints 2 % 3 = 0. */
printf("%d * %d = %d\n" % x, y, x % y);
</presource>
</div>
 
 
אפשר לבצע פעולות חשבוניות על מספרים, משתנים, או כל שילוב של משתנים ומספרים:
<source lang = "cpp">
<div style="text-align:left; direction:ltr;">
<pre>
int x = 2, y = 3;
 
printf("%d\n" % x + y + 5);
</presource>
</div>
==סדר פעולות החשבון==
סדר פעולות החשבון בשפת C הוא המקובל
ב[[אלגברה תיכונית/חוקי החשבון/חוקי פעולות החשבון#הסכם סדר הפעולות|אלגברה בסיסית]], ולכן כפל (*), לדוגמה, מבוצע לפני חיבור (+). השורה הבאה, לדוגמה, תדפיס 17
<source lang = "cpp">
<div style="text-align:left; direction:ltr;">
<pre>
printf("%d\n" % 2 + 3 * 5);
</presource>
</div>
בדיוק כבאלגברה בסיסית, ניתן להשתמש בסוגריים כדי לציין סדר פעולות שונה. השורה הבאה, לדוגמה, תדפיס 25
<source lang = "cpp">
<div style="text-align:left; direction:ltr;">
<pre>
printf("%d\n" % (2 + 3) * 5);
</presource>
</div>
==השמת ערכים==
===השמה ואתחול===
כפי שראינו ב[[שפת C/משתנים|משתנים]], אפשר להשתמש בסימן = להשמה ואתחול.
<source lang = "cpp">
<div style="text-align:left; direction:ltr;">
<pre>
int x = 2, y = 3;
 
int z = x + y + 5;
</presource>
</div>
חשוב להבין מה קורה כאן בשורה השניה. ראשית מעריכים את הביטוי x + y + 5 (ערכו כאן 10). משימים ערך זה למשתנה z. אפשר גם להשים למשתנה ערך חדש שתלוי בערכו הקודם. נתבונן לדוגמה בשורה
<source lang = "cpp">
<div style="text-align:left; direction:ltr;">
<pre>x = x+2;</pre>
</divsource>
הכוונה איננה ל[[אלגברה תיכונית|משוואה אלגברית]] על x (שאגב, נטולת פתרון). הכוונה היא להעריך את ערכו של הביטוי x + 2, ולהשים ערך זה חזרה לx (דבר זה ידרוס את הערך הקודם).
 
===סימני קיצור בהשמה עצמית===
כפי שראינו,
<source lang = "cpp">
<div style="text-align:left; direction:ltr;">
<pre>x=x+2;</pre>
</divsource>
משמעו השמה עצמית של x לערכו הקודם ועוד משהו (2 במקרה זה). בפועל, סוג זה של השמה עצמית נפוץ מאד. שפת C ידועה בקצרנותה הרבה לביטויים נפוצים. אפשר לכתוב את הביטוי הקודם גם באופן הבא, הקצר יותר:
<source lang = "cpp">
<div style="text-align:left; direction:ltr;">
<pre>x += 2;</pre>
</divsource>
המשמעות כאן זהה לחלוטין: מעריכים את x + 2, ומשימים את הערך לx.
 
שפת C כוללת סימונים מקוצרים להשמות עצמיות לכל חמש [[שפת C/פעולות חשבוניות#הפעולות הבסיסיות|פעולות החשבון הבסיסיות]]:
<source lang = "cpp">
<div style="text-align:left; direction:ltr;">
<pre>
/* x = x + 1 */
x += 1;
שורה 93 ⟵ 82:
/* p = p % 2 */
p %= 2;
</presource>
</div>
 
==הגדלה עצמית והקטנה עצמית==
===הגדלה עצמית===
נניח שאנו רוצים לקדם את x ב1. כבר ראינו שאפשר לרשום זאת כך:
<source lang = "cpp">
<div style="text-align:left; direction:ltr;">
<pre>
x = x + 1
</presource>
</div>
או, באופן קצר יותר, כך:
<source lang = "cpp">
<div style="text-align:left; direction:ltr;">
<pre>
x += 1;
</presource>
</div>
כשנגיע ל[[שפת C/תנאים ולולאות#לולאות|לולאות]], נראה שהגדלה עצמית משתנה דווקא ב1 (כלומר, שהמשתנה מקבל את ערכו הקודם ועוד 1) היא פעולה נפוצה במיוחד. פעולה זו, הגדלה עצמית (increment) יכולה להיכתב כך:
<source lang = "cpp">
<div style="text-align:left; direction:ltr;">
<pre>
x++;
</presource>
</div>
או כך:
<source lang = "cpp">
<div style="text-align:left; direction:ltr;">
<pre>
++x;
</presource>
</div>
(נעמוד על ההבדלים בין שתי הצורות ב[[שפת C/פעולות חשבוניות#הגדלה עצמית והקטנה עצמית לכתחילה ובדיעבד|כאן]].)
 
שורה 127 ⟵ 107:
 
באותו אופן כהגדלה עצמית, ניתן להוריד 1 מערך משתנה כך:
<source lang = "cpp">
<div style="text-align:left; direction:ltr;">
<pre>
x--;
</presource>
</div>
או כך:
<source lang = "cpp">
<div style="text-align:left; direction:ltr;">
<pre>
--x;
</presource>
</div>
===הגדלה עצמית והקטנה עצמית לכתחילה ובדיעבד===
לעתים, קיים ביטוי בו משתנה הן מקודם והן מוערך. נניח, לדוגמה, שx מכיל את הערך 3, ונתבונן בשורה:
<source lang = "cpp">
<div style="text-align:left; direction:ltr;">
<pre>
z = x++;
</presource>
</div>
שני דברים מתבצעים כאן:
* x מקודם ב1
* z מקבל ערך כלשהו
השאלה היא, אבל, מה קודם למה. אם קודם x מקודם, אז בסיום השורה, z יכיל את הערך 4. מצד שני, אם קודם z מקבל ערך, אז בסיום השורה, z יכיל את הערך 3 (כי x קודם ל4 רק אחרי שz קיבל את ערכו הקודם). לצורך כך מכילה שפת C הן הגדלה עצמית לכתחילה, והן הגדלה עצמית בדיעבד. משמעות הגדלה עצמית בדיעבד (post-increment)
<source lang = "cpp">
<div style="text-align:left; direction:ltr;">
<pre>
x++
</presource>
</div>
היא הערך את x ורק אז קדם אותו. לעומת זאת, משמעות הגדלה עצמית לכתחילה (pre-increment)
<source lang = "cpp">
<div style="text-align:left; direction:ltr;">
<pre>
++x
</presource>
</div>
היא קדם את x והערך את התוצאה. הדבר דומה להקטנה עצמית בדיעבד (post-decrement)
<source lang = "cpp">
<div style="text-align:left; direction:ltr;">
<pre>
x--
</presource>
</div>
לעומת הקטנה עצמית לכתחילה
(pre-decrement)
<source lang = "cpp">
<div style="text-align:left; direction:ltr;">
<pre>
--x
</presource>
</div>
 
==פעולות חשבוניות על שלמים ונקודות צפות==
שורה 179 ⟵ 145:
 
כבר ראינו ב[[שפת C/משתנים|משתנים]] על ההבדלים בין שלמים לנקודות צפות. כדאי לשים לב לנקודה, שכן בלעדיה נוכל לקבל תוצאות מפתיעות. נתבונן בקטע הקוד הבא:
<source lang = "cpp">
<div style="text-align:left; direction:ltr;">
<pre>
int x = 3, y = 8;
 
printf("The average is %f\n" % (x + y) / 2);
</presource>
</div>
אם נהדר ונריץ את הקוד, נראה שהממוצע המודפס הוא
5.0000, ולא
שורה 203 ⟵ 167:
 
נתבונן בקטע הקוד הבא:
<source lang = "cpp">
<div style="text-align:left; direction:ltr;">
<pre>
char x = 3;
 
int y = x;
</presource>
</div>
בשורה הראשונה מושם הערך 3 למשתנה x, שהוא מסוג תו. השורה הבאה משימה את ערכו של x לתוך המשתנה y, שהוא מסוג שלם. האם מידע יכול לאבוד כאן? לא, מפני שתחום הערכים שיכול להכיל int כולל את תחום הערכים שיכול להכיל char. המרה זו נטולת בעיות, מפני שאנו ממירים ערך במשתנה בעל תחום קטן, במשתנה בעל תחום רחב יותר.
 
שורה 217 ⟵ 179:
 
נתבונן בקטע הקוד הבא:
<source lang = "cpp">
<div style="text-align:left; direction:ltr;">
<pre>
int x = 3;
 
char y = x;
</presource>
</div>
 
כאן יש בעיה פוטנציאלית, משום שאנו ממירים ערך במשתנה בעל תחום גדול, במשתנה בעל תחום צר יותר. חלק מהמידע ילך לאיבוד.
שורה 231 ⟵ 191:
 
כאשר המהדר מבצע חישובים על מספר ערכים מסוגים שונים, הוא עורך המרות מרחיבות במידת הצורך עד שהחישוב פועל על ערכים מאותו סוג. לדוגמה, נתבונן בקטע הקוד הבא:
<source lang = "cpp">
<div style="text-align:left; direction:ltr;">
<pre>
int x = 2, y = 3;
 
printf("The average is %f\n", (x + y) / 2.0);
</presource>
</div>
קטע קוד זה מדפיס שהממוצע הוא 2.5, כנדרש. היות ש2.0 הוא משתנה נקודה צפה, המהדר יבצע המרה מרחיבה כך שx + y יהיה נקודה צפה, על אף שהן x והן y שלמים (ועל כן סכומם אמור היה להיות שלם).
 
שורה 245 ⟵ 203:
 
נניח שc מייצג טמפרטורה נתונה במעלות בשיטת [[w:en:Celsius|Celsius]], ואנו רוצים למצוא את f, המעלות בשיטת [[w:en:Fahrenheit|Fahrenheit]]. על פי נוסחה ידועה, f הוא {{משמאל לימין|9 / 5 * c + 32}}. נניח גם שהדיוק אינו חשוב לנו במיוחד, ואנו מוכנים לעבוד במספרים שלמים (על אף שגיאת העיגול). להלן תכנית המקבלת כקלט מעלה בFahrenheit, ומדפיסה אותו בCelsius:
<source lang = "cpp">
<div style="text-align:left; direction:ltr;">
<pre>
#include <stdio.h>
 
שורה 262 ⟵ 219:
return 0;
}
</presource>
</div>
להפתעתנו (או לא), התוכנית פשוט תפלוט תמיד את {{משמאל לימין|c + 32}} - שגיאה שחורגת בהרבה מסתם שגיאת עיגול. מדוע הדבר קורה? ראינו ב[[שפת C/פעולות חשבוניות#פעולות חשבוניות על שלמים ונקודות צפות|פעולות חשבוניות על שלמים ונקודות צפות]] שכל פעולה על טיפוסים שלמים מניבה תמיד תוצאה מסוג שלם. {{משמאל לימין|9 / 5}}, לכן, מתורגם ל1, ולכן מקבלים {{משמאל לימין|1 * c + 32}} בפועל.
 
נוכל לתקן זאת על ידי כך שנחליף את {{משמאל לימין|9 / 5}} ב1.8, שהוא מספר נקודה צפה:
<source lang = "cpp">
<div style="text-align:left; direction:ltr;">
<pre>
f = 1.8 * c + 32;
</presource>
</div>
כעת מדובר בחישוב מעורב, והשלמים בצד ימין של הסימן = יומרו במספרי נקודה צפה. לאחר החישוב, הערך יושם בf שהוא מספר שלם, ורק החלק העשרוני יאבד (כלומר, נקבל רק שגיאת עיגול).