מתכונת 1 במדעי המחשב - תכנות באינטרנט 899372
נבחנים אקסטרניים · שאלון 899372 · 9 שאלות · 2 שעות · פתרון מלא לכל סעיף
מבחן מתכונת במדעי המחשב, תכנות באינטרנט, במבנה של בחינת הבגרות. כל שאלה בו בנויה כמו שאלה מבגרות אחרת. לכל סעיף יש תשובה ופתרון מלא, וכל קוד מופיע ב-Java וב-C#. פתרו בזמן של הבחינה, ורק אחר כך פתחו את הפתרונות.
הוראות הבחינה
א. משך הבחינה: שעתיים.
ב. מבנה השאלון ומפתח הערכה: בשאלון זה שלושה פרקים.
פרק ראשון — (10x3) — 30 נקודות
פרק שני — (20x2)+(10x1) — 50 נקודות
פרק שלישי — (20x1) — 20 נקודות
סך הכול — 100 נקודות
ג. חומר עזר מותר בשימוש: כל חומר עזר, חוץ ממחשבון שיש בו אפשרות תכנות.
יש לכתוב במחברת הבחינה בלבד, יש לרשום "טיוטה" בראש כל עמוד המשמש טיוטה.
כתיבת טיוטה בדפים שאינם במחברת הבחינה עלולה לגרום לפסילת הבחינה.
השאלות בשאלון זה מנוסחות בלשון רבים, אף על פי כן על כל תלמידה וכל תלמיד להשיב עליהן באופן אישי.
בהצלחה!
פרק ראשון
ענו על שלוש השאלות 3-1 (לכל שאלה – 10 נקודות).
שאלה 1 · מהי JavaScript
בבניית אתרים משתמשים לעיתים קרובות בשפה JavaScript. מהי JavaScript?
העתיקו למחברת הבחינה את התשובה הנכונה מבין האפשרויות א–ד שלפניכם.
א. שפת שאילתות לשליפת נתונים מטבלאות במסד הנתונים.
ב. תגית HTML שבעזרתה מוסיפים תמונה לדף.
ג. אובייקט בשרת השומר מידע עבור משתמש מסוים.
ד. שפת תכנות שהקוד שלה רץ בדפדפן ומאפשר לדף להגיב לפעולות המשתמש.
העתיקו למחברת הבחינה את התשובה הנכונה מבין האפשרויות א–ד.
◂ פתרון מלא לשאלה 1
פתרון
ד. שפת תכנות שהקוד שלה רץ בדפדפן ומאפשר לדף להגיב לפעולות המשתמש.
מה נדרש: לבחור את ההגדרה הנכונה של JavaScript.
רעיון: JavaScript היא שפת תכנות של צד הלקוח: הקוד נשלח לדפדפן יחד עם דף ה-HTML (בתוך תגית <script>) והדפדפן מריץ אותו. בעזרתה הדף מגיב לפעולות המשתמש – לחיצה על כפתור, הקלדה בתיבה – בלי לפנות שוב לשרת. לדוגמה:
<button onclick="alert('שלום!')">לחצו כאן</button>בלחיצה על הכפתור הדפדפן מריץ את הקוד alert('שלום!') ומקפיץ הודעה.
פתרון – מעבר על האפשרויות:
<img>. לא נכון.תשובה: ד.
בדיקה: כל אחת מהאפשרויות א–ג מתארת מושג אחר מהחומר (SQL, תגית <img>, Session); רק ד' מתארת שפת תכנות שרצה בצד הלקוח.
טעות נפוצה: לבלבל בין JavaScript לבין Java – אלה שתי שפות שונות לגמרי, ו-JavaScript היא זו שרצה בדפדפן.
שאלה 2 · מהו IsPostBack
מהו IsPostBack?
(1) פעולה המחזירה את המשתמש לדף הקודם שבו ביקר.
(2) משתנה Session שהשרת יוצר כאשר המשתמש שולח טופס.
(3) פקודה בצד הלקוח השולחת את הטופס לשרת.
(4) תכונה של הדף בצד השרת שערכה true כאשר הדף נטען מחדש בעקבות שליחת טופס מאותו דף, ו-false כאשר הדף נטען בפעם הראשונה.
מהו IsPostBack?
◂ פתרון מלא לשאלה 2
פתרון
(4)
מה נדרש – לבחור את ההגדרה הנכונה של IsPostBack.
רעיון – הפעולה Page_Load בצד השרת רצה בכל טעינה של הדף: גם בכניסה הראשונה וגם כשהמשתמש לוחץ על כפתור שליחה בטופס שנשלח לאותו דף ("postback"). IsPostBack מאפשר להבחין בין שני המצבים.
פתרון
IsPostBack היא תכונה (property) של הדף בצד השרת, מסוג bool:
false – הדף נטען בפעם הראשונה (המשתמש הגיע אליו מקישור או מהקלדת כתובת).true – הדף נטען שוב כי המשתמש שלח טופס מאותו הדף.שימוש טיפוסי:
if (!IsPostBack)
{
// פעולות שיש לבצע רק בכניסה הראשונה, למשל מילוי ערכי ברירת מחדל
}| תשובה | נכון/לא נכון | למה |
|---|---|---|
| (1) | ✘ | חזרה לדף קודם היא פעולה של הדפדפן (כפתור "חזרה"), לא IsPostBack. |
| (2) | ✘ | IsPostBack אינו משתנה Session; זו תכונה של הדף בבקשה הנוכחית. |
| (3) | ✘ | IsPostBack נבדק בצד השרת, והוא אינו שולח דבר. |
| (4) | ✔ נכון | זו ההגדרה. |
התשובה: (4).
בדיקה – דף שבו if (!IsPostBack) קובע בתיבת העיר ערך ברירת מחדל Haifa. בכניסה הראשונה (IsPostBack = false) נקבע Haifa; המשתמש הקליד Eilat ושלח, ובטעינה השנייה (IsPostBack = true) הקוד לא דרס את הערך, ונשאר Eilat.
טעות נפוצה: לשכוח את הבדיקה if (!IsPostBack) – אז ערכי ברירת המחדל נקבעים מחדש בכל שליחה ודורסים את מה שהמשתמש הקליד.
שאלה 3 · פלט של Response.Write עם כותרות
לפניכם הפונקציה Steps, הכתובה בצד שרת.
public void Steps (int num) {
string str = "";
for (int i = 1; i <= num; i++) {
str += "<h" + i + ">";
for (int j = 1; j <= i; j++)
str += "*";
str += "</h" + i + ">";
if (i % 2 == 0)
str += "<hr>";
}
Response.Write(str);
}כתבו במחברת הבחינה את הפלט שיוצג בדפדפן לאחר זימון הפונקציה Steps(4).
כתבו במחברת הבחינה את הפלט שיוצג בדפדפן לאחר זימון הפונקציה Steps(4).
◂ פתרון מלא לשאלה 3
פתרון
ארבע שורות כוכביות מודגשות שגודלן הולך וקטן: * (כותרת h1, הגדולה ביותר), (h2), קו אופקי, * (h3), (h4), קו אופקי.
מה נדרש: מה יראה המשתמש בדפדפן לאחר Steps(4).
רעיון: בכל סיבוב i (מ-1 עד 4) נבנית כותרת <hi> – כלומר <h1>, <h2>, <h3>, <h4> – והלולאה הפנימית מכניסה לתוכה i כוכביות. כותרות מוצגות מודגשות, כל אחת בשורה נפרדת, ו-h1 היא הגדולה ביותר; ככל שהמספר גדל הגופן קטן. אחרי כל i זוגי נוסף <hr> – קו אופקי לרוחב הדף.
פתרון – מעקב:
| i | הכוכביות (לולאת j) | i % 2 == 0? | מה נוסף |
|---|---|---|---|
| 1 | * | לא | <h1>*</h1> |
| 2 | כן | <h2>**</h2><hr> | |
| 3 | * | לא | <h3>***</h3> |
| 4 | כן | <h4>****</h4><hr> |
המחרוזת שנשלחת לדפדפן:
<h1>*</h1><h2>**</h2><hr><h3>***</h3><h4>****</h4><hr>הפלט שיוצג בדפדפן:
* – בגופן הגדול ביותר (h1), מודגש** – קטן יותר (h2)*** – קטן יותר (h3)**** – הקטן מבין הארבעה (h4)
בדיקה: מספר הכוכביות עולה (1, 2, 3, 4) בזמן שגודל הגופן יורד (h1 → h4); שני קווים – אחרי i = 2 ואחרי i = 4.
טעות נפוצה: לחשוב שהשורה עם יותר כוכביות גדולה יותר – הגודל נקבע לפי מספר הכותרת, ו-h1 היא הגדולה. טעות נוספת: לשכוח את הקו שאחרי השורה האחרונה (גם 4 זוגי).
פרק שני
ענו על שלוש שאלות: על שאלה 4 (חובה – 10 נקודות) ועל שתיים מן השאלות 7-5 (לכל שאלה – 20 נקודות).
שאלה 4 · JavaScript – בדיקת קוד יציאה הפוך (השלמת קוד)
באתר של חדר בריחה מקוון יש שדה שבו השחקן מזין את קוד היציאה מהחדר:
<input type="text" maxlength="12" name="exitCode" id="exitCode" />בכל חדר מוצגת לשחקן מחרוזת רמז (clue). קוד היציאה (answer) תקין אם הוא מחרוזת הרמז בסדר הפוך: התו הראשון של answer הוא התו האחרון של clue, התו השני של answer הוא התו הלפני אחרון של clue, וכן הלאה – עד שהתו האחרון של answer הוא התו הראשון של clue. בפרט, לשתי המחרוזות אותו אורך.
דוגמה:
clue = "LOCK7"
answer = "7KCOL"
הקוד תקין.
דוגמאות נוספות עבור clue = "LOCK7":
answer = "7KCOD" – הקוד שגוי (התו האחרון אינו L)
answer = "KCOL" – הקוד שגוי (חסר התו 7)
הפעולה isReverse שלפניכם מחזירה true אם answer הוא קוד יציאה תקין עבור clue, ו־false אחרת. בפעולה חסרים שישה ביטויים המסומנים במספרים (1)–(6).
כתבו במחברת הבחינה את המספרים (1)–(6) ואת הביטויים החסרים שכל מספר מייצג.
<script>
function isReverse (clue, answer)
{
var i = 0;
var j = answer.length - 1;
// נסרוק את clue מתחילתה ואת answer מסופה
while (_______(1)_______ && _______(2)_______)
{
// אם התווים במיקומים המתאימים אינם שווים – הקוד שגוי
if (_______(3)_______)
return false;
// נתקדם בשתי המחרוזות
_____(4)_____; // i
_____(5)_____; // j
}
// אם באחת המחרוזות נשארו תווים שלא נבדקו – הקוד שגוי
if (_______(6)_______)
return false;
return true;
}
</script>כתבו במחברת הבחינה את המספרים (1)–(6) ואת הביטויים החסרים שכל מספר מייצג.
◂ פתרון מלא לשאלה 4
פתרון
(1) i < clue.length
(2) j >= 0
(3) clue.charAt(i) != answer.charAt(j)
(4) i++
(5) j--
(6) i < clue.length || j >= 0
מה נדרש – להשלים שישה ביטויים בפעולה שבודקת אם answer הוא clue בסדר הפוך.
רעיון – משתמשים בשני אינדקסים שנעים בכיוונים מנוגדים:
i עובר על clue מההתחלה (0, 1, 2, ...);j עובר על answer מהסוף (answer.length − 1, ..., 1, 0) – לכן הוא מאותחל ל-answer.length - 1.בכל צעד משווים את התו ה-i ב-clue לתו ה-j ב-answer; אם הם שונים – הקוד שגוי. הלולאה נעצרת כשאחד האינדקסים יוצא מגבולות המחרוזת שלו. אם בסוף נשארו תווים שלא נבדקו באחת המחרוזות (i עדיין קטן מאורך clue, או j עדיין לא ירד מתחת ל־0) – האורכים שונים והקוד שגוי.
פתרון
| מספר | ביטוי | הסבר |
|---|---|---|
| (1) | i < clue.length | לא הגענו לסוף clue |
| (2) | j >= 0 | j עדיין בתוך answer (לא ירדנו מתחת למקום 0) |
| (3) | clue.charAt(i) != answer.charAt(j) | התווים במיקומים המתאימים שונים |
| (4) | i++ | מתקדמים תו אחד קדימה ב-clue |
| (5) | j-- | מתקדמים תו אחד אחורה ב-answer |
| (6) | i < clue.length || j >= 0 | נשארו תווים שלא נבדקו באחת המחרוזות |
גם ביטויים שקולים מתקבלים, למשל j > -1 במקום j >= 0, i = i + 1 במקום i++ ו-j = j - 1 במקום j--.
הפעולה המלאה:
function isReverse (clue, answer)
{
var i = 0;
var j = answer.length - 1;
// נסרוק את clue מתחילתה ואת answer מסופה
while (i < clue.length && j >= 0)
{
// אם התווים במיקומים המתאימים אינם שווים – הקוד שגוי
if (clue.charAt(i) != answer.charAt(j))
return false;
// נתקדם בשתי המחרוזות
i++; // i
j--; // j
}
// אם באחת המחרוזות נשארו תווים שלא נבדקו – הקוד שגוי
if (i < clue.length || j >= 0)
return false;
return true;
}בדיקה
מעקב עבור clue = "LOCK7", answer = "7KCOL" (שני האורכים 5):
| i | j | clue.charAt(i) | answer.charAt(j) | שווים? |
|---|---|---|---|---|
| 0 | 4 | L | L | כן |
| 1 | 3 | O | O | כן |
| 2 | 2 | C | C | כן |
| 3 | 1 | K | K | כן |
| 4 | 0 | 7 | 7 | כן |
| 5 | −1 | – | – | הלולאה נעצרת |
בסוף: 5 < 5 שקר ו--1 >= 0 שקר ⇐ התנאי (6) שקר ⇐ מוחזר true.
התוצאות:
isReverse("LOCK7", "7KCOL") → trueisReverse("LOCK7", "7KCOD") → false (כבר בהשוואה הראשונה: L מול D)isReverse("LOCK7", "KCOL") → false (ארבע ההשוואות מצליחות, אבל j יורד ל־−1 כש-i = 4 – נשאר תו ב-clue, ולכן (6) אמת)isReverse("LOCK7", "77KCOL") → false (חמש ההשוואות מצליחות, אבל כש-i מגיע ל־5 נשאר j = 0 – נשאר תו ב-answer, ולכן (6) אמת)טעות נפוצה: לאתחל או לקדם את j כמו את i (j++), או לבדוק בסוף רק את אחד האינדקסים – אז מחרוזת קצרה או ארוכה מדי תתקבל כתקינה.
שאלה 5 · Session – סוג משלוח בחנות מקוונת
בחנות המקוונת ״ספורט פלוס״ קובעים לכל הזמנה את סוג המשלוח. לשם כך אנו משתמשים במספר משתני Session:
בהתבסס על משתנים אלה, אנו מעדכנים את המשתנה delivery ומפנים את הלקוח לדף המתאים:
א. הזמנה שסכומה 400 ש״ח ומעלה תעודכן למשלוח free ותועבר לדף freeDelivery.aspx
ב. הזמנה של חבר מועדון שסכומה 150 ש״ח לפחות תעודכן למשלוח reduced ותועבר לדף clubDelivery.aspx
ג. שאר ההזמנות יעודכנו למשלוח standard ויועברו לדף delivery.aspx
כתבו קוד בצד השרת המתאים לדרישות.
כתבו קוד בצד השרת המתאים לדרישות.
◂ פתרון מלא לשאלה 5
פתרון
double cartSum = (double)Session["cartSum"]; bool isClub = (bool)Session["isClub"]; ואז: cartSum >= 400 ⇐ free + freeDelivery.aspx; אחרת isClub && cartSum >= 150 ⇐ reduced + clubDelivery.aspx; אחרת standard + delivery.aspx.
מה נדרש: קוד צד-שרת ב-C# שקורא את סכום העגלה ואת סטטוס המועדון מה-Session, מעדכן את Session["delivery"] ומפנה לדף המתאים.
רעיון:
object צריכה להתאים לטיפוס שנשמר: הסכום נשמר כ-double ⇐ (double)Session["cartSum"]; חבר מועדון נשמר כ-bool ⇐ (bool)Session["isClub"]. משתנה בוליאני אפשר לכתוב ישירות בתנאי: if (isClub && ...) (אין צורך ב-isClub == true).
if – else if – else: קודם המשלוח החינמי (לכל לקוח, חבר מועדון או לא), אחר כך המשלוח המוזל – רק אם גם הלקוח חבר מועדון וגם הסכום לפחות 150 ⇐ &&.Session["delivery"] לפני Response.Redirect.פתרון – הקוד המלא בלשונית C#:
protected void Page_Load(object sender, EventArgs e)
{
double cartSum = (double)Session["cartSum"];
bool isClub = (bool)Session["isClub"];
if (cartSum >= 400)
{
Session["delivery"] = "free";
Response.Redirect("freeDelivery.aspx");
}
else if (isClub && cartSum >= 150)
{
Session["delivery"] = "reduced";
Response.Redirect("clubDelivery.aspx");
}
else
{
Session["delivery"] = "standard";
Response.Redirect("delivery.aspx");
}
}בדיקה:
| cartSum | isClub | delivery | הפניה |
|---|---|---|---|
| 520.5 | false | free | freeDelivery.aspx |
| 400 | true | free | freeDelivery.aspx |
| 399.9 | true | reduced | clubDelivery.aspx |
| 150 | true | reduced | clubDelivery.aspx |
| 149.9 | true | standard | delivery.aspx |
| 250 | false | standard | delivery.aspx |
| 0 | false | standard | delivery.aspx |
שימו לב לשורה 400/true: חבר מועדון עם 400 ש״ח מקבל free ולא reduced, כי התנאי הראשון נבדק קודם.
טעות נפוצה: להמיר את הסכום ל-(int) – אם נשמר בו double ההמרה נכשלת בזמן ריצה (וגם הסכום 149.9 היה נחתך); או להפוך את סדר התנאים, ואז חבר מועדון עם 500 ש״ח יקבל בטעות reduced.
protected void Page_Load(object sender, EventArgs e)
{
double cartSum = (double)Session["cartSum"];
bool isClub = (bool)Session["isClub"];
if (cartSum >= 400)
{
Session["delivery"] = "free";
Response.Redirect("freeDelivery.aspx");
}
else if (isClub && cartSum >= 150)
{
Session["delivery"] = "reduced";
Response.Redirect("clubDelivery.aspx");
}
else
{
Session["delivery"] = "standard";
Response.Redirect("delivery.aspx");
}
}שאלה 6 · פעולת שרת IsPeak – ספרת אחדות מקסימלית
נגדיר מספר Peak – מספר שלם חיובי שספרת האחדות שלו גדולה ממש מכל אחת מהספרות האחרות שלו, וגם סכום הספרות שלו הוא מספר זוגי.
דוגמאות למספרים Peak:
דוגמאות למספרים שאינם Peak:
הניחו כי num הוא מספר בן שתי ספרות לפחות.
כתבו בצד שרת פעולה בשם IsPeak המקבלת מספר שלם חיובי – num, ומחזירה אמת אם המספר הוא Peak. אחרת, מחזירה שקר.
כתבו בצד שרת פעולה בשם IsPeak המקבלת מספר שלם חיובי – num, ומחזירה אמת אם המספר הוא Peak. אחרת, מחזירה שקר.
◂ פתרון מלא לשאלה 6
פתרון
units = num % 10, sum = units; בלולאה על שאר הספרות: אם ספרה ≥ units מחזירים false, אחרת מוסיפים לסכום; בסוף מחזירים sum % 2 == 0.
מה נדרש – פעולה בוליאנית ב-C# בצד השרת שבודקת שני תנאים על ספרות המספר: ספרת האחדות גדולה ממש מכל שאר הספרות, וסכום כל הספרות זוגי.
רעיון
units = num % 10. היא גם הערך ההתחלתי של הסכום.n = num / 10) ועוברים בלולאה על שאר הספרות.sum % 2 == 0.פתרון
public bool IsPeak(int num)
{
int units = num % 10;
int sum = units;
int n = num / 10;
while (n > 0)
{
int digit = n % 10;
if (digit >= units)
return false;
sum += digit;
n = n / 10;
}
return sum % 2 == 0;
}בדיקה:
| num | ספרת אחדות | ספרות אחרות קטנות ממנה? | סכום | תוצאה |
|---|---|---|---|---|
| 1359 | 9 | כן | 18 | true |
| 446 | 6 | כן | 14 | true |
| 24 | 4 | כן | 6 | true |
| 249 | 9 | כן | 15 | false |
| 466 | 6 | לא (6 = 6) | – | false |
| 394 | 4 | לא (9 > 4) | – | false |
| 90 | 0 | לא | – | false |
המספרים Peak בין 10 ל־100: 13, 15, 17, 19, 24, 26, 28, 35, 37, 39, 46, 48, 57, 59, 68, 79.
טעות נפוצה: לבדוק digit > units במקום digit >= units – ואז 466 יתקבל בטעות, כי "גדולה ממש" פירושו שספרה שווה פוסלת. טעות נוספת: לשכוח להוסיף את ספרת האחדות עצמה לסכום.
public bool IsPeak(int num)
{
int units = num % 10;
int sum = units;
int n = num / 10;
while (n > 0)
{
int digit = n % 10;
if (digit >= units)
return false;
sum += digit;
n = n / 10;
}
return sum % 2 == 0;
}שאלה 7 · SQL – שאילתה עם כמה תנאים (OR)
במסד נתונים של אתר להזמנת חדרים במלונות יש טבלה ששמה HotelsTable המכילה את נתוני המלונות באתר.
העמודות בטבלה הן:
א. name (שם המלון), מסוג טקסט.
ב. city (העיר שבה נמצא המלון), מסוג טקסט.
ג. stars (מספר כוכבים), מסוג מספר שלם.
ד. rooms (מספר החדרים במלון), מסוג מספר שלם.
ה. occupied (מספר החדרים התפוסים הלילה), מסוג מספר שלם.
ו. price (מחיר לילה בש"ח), מסוג מספר שלם.
דוגמה לטבלה ובה כמה מן המלונות באתר:
| name | city | stars | rooms | occupied | price |
|---|---|---|---|---|---|
| מלון הים | אילת | 4 | 120 | 115 | 900 |
| נוף הכרמל | חיפה | 3 | 60 | 35 | 420 |
| מצפה המדבר | מצפה רמון | 5 | 40 | 38 | 1200 |
| העיר העתיקה | ירושלים | 4 | 150 | 140 | 600 |
| חוף הצפון | נהריה | 2 | 30 | 12 | 300 |
| גלי הכנרת | טבריה | 3 | 80 | 50 | 340 |
כתבו שאילתה אחת בשפת SQL המבקשת להציג את שמות המלונות המקיימים אחד או יותר מהתנאים הבאים:
א. מספר החדרים הפנויים הלילה (חדרים שאינם תפוסים) הוא 20 לפחות.
ב. המלון נמצא בעיר אילת.
ג. מחיר לילה בין 350 ש"ח ל־600 ש"ח (כולל).
◂ פתרון מלא לשאלה 7
פתרון
SELECT name FROM HotelsTable WHERE rooms - occupied >= 20 OR city = 'אילת' OR price BETWEEN 350 AND 600;
(על טבלת הדוגמה: מלון הים, נוף הכרמל, העיר העתיקה, גלי הכנרת)
מה נדרש – שאילתה אחת שמחזירה את שמות המלונות שמקיימים לפחות אחד משלושת התנאים.
רעיון – "אחד או יותר מהתנאים" ⇒ מחברים את התנאים ב־OR:
rooms - occupied. "20 לפחות" ⇒ rooms - occupied >= 20.city = 'אילת'.price BETWEEN 350 AND 600 (BETWEEN כולל את שני הקצוות; שקול ל־price >= 350 AND price <= 600).פתרון
SELECT name
FROM HotelsTable
WHERE rooms - occupied >= 20
OR city = 'אילת'
OR price BETWEEN 350 AND 600;בדיקה – על טבלת הדוגמה. לכל שורה – אילו תנאים מתקיימים:
| name | א: rooms − occupied ≥ 20 | ב: city = אילת | ג: 350 ≤ price ≤ 600 | מוצג? |
|---|---|---|---|---|
| מלון הים | 5 ✘ | ✔ | 900 ✘ | כן |
| נוף הכרמל | 25 ✔ | ✘ | 420 ✔ | כן |
| מצפה המדבר | 2 ✘ | ✘ | 1200 ✘ | לא |
| העיר העתיקה | 10 ✘ | ✘ | 600 ✔ | כן |
| חוף הצפון | 18 ✘ | ✘ | 300 ✘ | לא |
| גלי הכנרת | 30 ✔ | ✘ | 340 ✘ | כן |
התוצאה: מלון הים, נוף הכרמל, העיר העתיקה, גלי הכנרת.
טעות נפוצה: לחבר את התנאים ב־AND – אז נדרשים כל התנאים יחד, ובטבלת הדוגמה לא מוחזר אף מלון. טעות נוספת: לכתוב את תנאי ג כ־price > 350 AND price < 600 למרות ש"כולל" – אז "העיר העתיקה" (600 בדיוק) לא תוצג. ואם משלבים AND בתוך OR – חובה סוגריים: ... OR (price >= 350 AND price <= 600).
פרק שלישי
ענו על שאלה אחת מן השאלות 9-8.
שאלה 8 · בדיקת קוד קופון מול מסד הנתונים
בדף התשלום של חנות ספרים מקוונת יכול הלקוח להקליד קוד קופון הנחה בשדה זה:
<input type="text" name="coupon" id="coupon"/>בבסיס הנתונים של האתר קיימת טבלה בשם coupons ובה שלוש עמודות:
| code | discount | remaining |
|---|---|---|
| SUMMER10 | 10 | 25 |
| VIP30 | 30 | 0 |
| BOOK15 | 15 | 1 |
לפניכם קטע קוד חלקי תקין של פעולה בשם CheckCoupon הבודקת את קוד הקופון שהוקלד. יש להפנות את הלקוח לעמוד המתאים על פי החוקים הבאים:
protected void CheckCoupon(string connectionString){
SqlConnection connection = new SqlConnection(connectionString);
SqlCommand command = new SqlCommand();
DataSet ds = new DataSet();
command.CommandText = string.Format("Select * From coupons Where code = '{0}'",
Request.Form["coupon"]);
command.Connection = connection;
connection.Open();
SqlDataAdapter adapter = new SqlDataAdapter(command);
adapter.Fill(ds);
connection.Close();
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
}יש להשלים את הקוד החסר בסוף הפעולה (מסומן בכוכביות)
◂ פתרון מלא לשאלה 8
פתרון
if (ds.Tables[0].Rows.Count == 0)
{
Response.Redirect("badCoupon.aspx");
}
else
{
DataRow row = ds.Tables[0].Rows[0];
int remaining = int.Parse(row["remaining"].ToString());
if (remaining == 0)
{
Response.Redirect("usedUp.aspx");
}
else
{
Session["discount"] = int.Parse(row["discount"].ToString());
Response.Redirect("cart.aspx");
}
}
מה נדרש – להשלים את סוף הפעולה: אחרי שהשאילתה רצה והתוצאות נמצאות ב־ds, להחליט לאיזה מבין שלושת הדפים להפנות, ובמקרה של קופון תקף – גם לשמור את אחוז ההנחה ב־Session.
רעיון
code שווה לקוד שהוקלד בשדה coupon. התוצאה נמצאת ב־ds.Tables[0].ds.Tables[0].Rows.Count == 0) ⇒ הקוד לא קיים ⇒ badCoupon.aspx.ds.Tables[0].Rows[0] וקוראים ממנה את remaining ואת discount. ערך בתא של DataRow הוא object, ולכן ממירים: int.Parse(row["remaining"].ToString()).remaining == 0 ⇒ usedUp.aspx.Session["discount"] = ... ואז Response.Redirect("cart.aspx"). את ה־Session שומרים לפני ההפניה.פתרון – הקוד שנכתב במקום הכוכביות:
if (ds.Tables[0].Rows.Count == 0)
{
Response.Redirect("badCoupon.aspx");
}
else
{
DataRow row = ds.Tables[0].Rows[0];
int remaining = int.Parse(row["remaining"].ToString());
if (remaining == 0)
{
Response.Redirect("usedUp.aspx");
}
else
{
Session["discount"] = int.Parse(row["discount"].ToString());
Response.Redirect("cart.aspx");
}
}הפעולה המלאה:
protected void CheckCoupon(string connectionString){
SqlConnection connection = new SqlConnection(connectionString);
SqlCommand command = new SqlCommand();
DataSet ds = new DataSet();
command.CommandText = string.Format("Select * From coupons Where code = '{0}'",
Request.Form["coupon"]);
command.Connection = connection;
connection.Open();
SqlDataAdapter adapter = new SqlDataAdapter(command);
adapter.Fill(ds);
connection.Close();
// ---- the missing code ----
if (ds.Tables[0].Rows.Count == 0)
{
Response.Redirect("badCoupon.aspx");
}
else
{
DataRow row = ds.Tables[0].Rows[0];
int remaining = int.Parse(row["remaining"].ToString());
if (remaining == 0)
{
Response.Redirect("usedUp.aspx");
}
else
{
Session["discount"] = int.Parse(row["discount"].ToString());
Response.Redirect("cart.aspx");
}
}
}בדיקה – הפעולה המלאה על הטבלה coupons מהשאלה:
| coupon | הפניה | Session["discount"] |
|---|---|---|
| SUMMER10 | cart.aspx | 10 |
| BOOK15 | cart.aspx | 15 |
| VIP30 | usedUp.aspx | (לא נשמר) |
| WINTER20 | badCoupon.aspx | (לא נשמר) |
טעות נפוצה: לגשת ל־Rows[0] לפני שבודקים שיש שורות – כשהקוד לא קיים זו שגיאת זמן ריצה. טעות נוספת: להשוות row["remaining"] == 0 בלי המרה – זו השוואה בין object למספר, שגיאת הידור.
הערה: בניית שאילתה משרשור הקלט של המשתמש (string.Format עם Request.Form) חשופה ל־SQL Injection; באתר אמיתי משתמשים בפרמטרים. כאן הקוד הנתון כתוב כך, ואנו רק משלימים אותו.
protected void CheckCoupon(string connectionString){
SqlConnection connection = new SqlConnection(connectionString);
SqlCommand command = new SqlCommand();
DataSet ds = new DataSet();
command.CommandText = string.Format("Select * From coupons Where code = '{0}'",
Request.Form["coupon"]);
command.Connection = connection;
connection.Open();
SqlDataAdapter adapter = new SqlDataAdapter(command);
adapter.Fill(ds);
connection.Close();
// ---- the missing code ----
if (ds.Tables[0].Rows.Count == 0)
{
Response.Redirect("badCoupon.aspx");
}
else
{
DataRow row = ds.Tables[0].Rows[0];
int remaining = int.Parse(row["remaining"].ToString());
if (remaining == 0)
{
Response.Redirect("usedUp.aspx");
}
else
{
Session["discount"] = int.Parse(row["discount"].ToString());
Response.Redirect("cart.aspx");
}
}
}שאלה 9 · דיווח על אבדות ומציאות – Request.Form ו-INSERT
לפניכם התוכנית הבאה בדף Found.aspx (אין טעויות תחביר). בעזרת הדף תלמידים מדווחים על חפצים שמצאו בבית הספר; כל דיווח נשמר בטבלה Found.
01. <%@ Page Language="C#" %>
02. <%@ Import Namespace="System.Data" %>
03. <%@ Import Namespace="System.Data.SqlClient" %>
04.
05. <script runat="server">
06. public string msg = "";
07. protected void Page_Load(object sender, EventArgs e)
08. {
09. if (Request.Form["item"] != null)
10. {
11. string item = Request.Form["item"];
12. string place = Request.Form["place"];
13. if (item == "" || place == "")
14. {
15. msg = "יש למלא את כל השדות";
16. }
17. else
18. {
19. string connectionString = @"Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\school.mdf;Integrated Security=True";
20. SqlConnection connection = new SqlConnection(connectionString);
21. string sql = string.Format("Insert Into Found (Item, Place) Values ('{0}', '{1}')", item, place);
22. SqlCommand command = new SqlCommand(sql, connection);
23. connection.Open();
24. command.ExecuteNonQuery();
25. connection.Close();
26. if (Session["count"] == null)
27. Session["count"] = 0;
28. Session["count"] = (int)Session["count"] + 1;
29. msg = "הדיווח נשמר. מספר הדיווחים שלך: " + Session["count"];
30. }
31. }
32. }
33. </script>
34. <html xmlns="http://www.w3.org/1999/xhtml">
35. <head runat="server">
36. <title>Lost and Found</title>
37. </head>
38. <body>
39. <form id="form1" action="Found.aspx" method="post">
40. חפץ: <input type="text" name="item" />
41. מקום: <input type="text" name="place" />
42. <input type="submit" value="Send" />
43. </form>
44. <p><%= msg %></p>
45. </body>
46. </html>לפניכם חמישה הגדים, רשמו עבור כל הגד נכון / לא נכון.
לפניכם חמישה הגדים, רשמו עבור כל הגד נכון / לא נכון.
◂ פתרון מלא לשאלה 9
פתרון
1 – נכון; 2 – לא נכון; 3 – נכון; 4 – נכון; 5 – לא נכון
מה נדרש – לקבוע לכל אחד מחמשת ההגדים אם הוא נכון.
רעיון – לעקוב מתי רץ כל חלק של Page_Load: הטופס (שורה 39) נשלח בשיטה post לאותו דף, ולכן נתוני הטופס נקראים ב-Request.Form; בבקשה רגילה (get) Request.Form["item"] הוא null.
פתרון
מה הקוד עושה: רק כשיש נתוני טופס (שורה 9) נקראים החפץ והמקום. אם אחד מהם ריק – מוצגת הודעה ולא נשמר דבר (שורות 13–16). אחרת נבנית פקודת INSERT מהטקסט שהוקלד (שורה 21), היא מתבצעת (שורות 22–25), ומונה הדיווחים של הגולש הזה ב-Session גדל ב-1 (שורות 26–28).
| הגד | תשובה | הסבר |
|---|---|---|
| 1 | נכון | הקלדת כתובת היא בקשת get בלי נתוני טופס: Request.Form["item"] הוא null, ושום שורה לא נוספת. |
| 2 | לא נכון | השדה place נשלח כמחרוזת ריקה "", התנאי בשורה 13 מתקיים ומוצגת ההודעה "יש למלא את כל השדות" – בלי INSERT. |
| 3 | נכון | המונה נשמר ב-Session, שהוא נפרד לכל גולש. אצל כל אחד מהם Session["count"] מתחיל ב-null, מאותחל ל-0 וגדל ל-1. |
| 4 | נכון | השורות 19–29 נמצאות בתוך if של שורה 9 (יש נתוני טופס) ובחלק ה-else של שורה 13 (שני השדות אינם ריקים). |
| 5 | לא נכון | הפקודה נבנית בשרשור (string.Format): Values ('ג'קט כחול', 'אולם הספורט'). הגרש סוגר את המחרוזת של SQL באמצע המילה, הפקודה אינה תקינה, ו-ExecuteNonQuery זורק שגיאה – הדיווח לא נשמר. (הפתרון: פקודה עם פרמטרים, או הכפלת הגרש.) |
בדיקה – קוד השרת (שורות 6–32), כשפקודת ה-INSERT מתבצעת על הטבלה:
| בקשה | תוצאה | שורות בטבלה |
|---|---|---|
| דנה נכנסת לדף (get) | הודעה ריקה | 0 |
| דנה שולחת חפץ "קלמר אדום" ומקום ריק | "יש למלא את כל השדות" | 0 |
| דנה שולחת דיווח תקין | "...מספר הדיווחים שלך: 1" | 1 |
| יוסי שולח דיווח תקין | "...מספר הדיווחים שלך: 1" | 2 |
| דנה שולחת דיווח נוסף | "...מספר הדיווחים שלך: 2" | 3 |
| יוסי שולח "ג'קט כחול" | שגיאת תחביר ב-SQL (near "קט") | 3 |
טעות נפוצה: לחשוב שמונה ב-Session משותף לכל התלמידים (זה Application), ולענות על הגד 5 "נכון" בלי לבדוק איך נבנית פקודת ה-SQL מהטקסט שהוקלד.
טבלת התשובות
| שאלה | סעיף | תשובה |
|---|---|---|
| 1 | - | ד. שפת תכנות שהקוד שלה רץ בדפדפן ומאפשר לדף להגיב לפעולות המשתמש. |
| 2 | - | (4) |
| 3 | - | ארבע שורות כוכביות מודגשות שגודלן הולך וקטן: * (כותרת h1, הגדולה ביותר), (h2), קו אופקי, * (h3), (h4), קו אופקי. |
| 4 | - | (1) i < clue.length |
| 5 | - | double cartSum = (double)Session["cartSum"]; bool isClub = (bool)Session["isClub"]; ואז: cartSum >= 400 ⇐ free + freeDelivery.aspx; אחרת isClub && cartSum >= 150 ⇐ reduced + clubDelivery.aspx; אחרת standard + delivery.aspx. |
| 6 | - | units = num % 10, sum = units; בלולאה על שאר הספרות: אם ספרה ≥ units מחזירים false, אחרת מוסיפים לסכום; בסוף מחזירים sum % 2 == 0. |
| 7 | - | SELECT name FROM HotelsTable WHERE rooms - occupied >= 20 OR city = 'אילת' OR price BETWEEN 350 AND 600; |
| 8 | - | if (ds.Tables[0].Rows.Count == 0) |
| 9 | - | 1 – נכון; 2 – לא נכון; 3 – נכון; 4 – נכון; 5 – לא נכון |