בגרות במדעי המחשב תכנות באינטרנט 899372 - קיץ 2025
נבחנים אקסטרניים · שאלון 899372 · 9 שאלות · 2 שעות · פתרון מלא לכל סעיף
בחינת הבגרות במדעי המחשב, תכנות באינטרנט, קיץ 2025, כל 9 השאלות כמו בשאלון. לכל סעיף יש תשובה ופתרון מלא: הרעיון, הקוד או המעקב, ובדיקה קצרה. כל קוד מופיע ב-Java וב-C#. נסו לפתור לבד, ואז פתחו את הפתרון.
הוראות הבחינה (כמו בשאלון)
א. משך הבחינה: שעתיים.
ב. מבנה השאלון ומפתח הערכה: בשאלון זה שלושה פרקים.
פרק ראשון — (10x3) — 30 נקודות
פרק שני — (20x2)+(10x1) — 50 נקודות
פרק שלישי — (20x1) — 20 נקודות
סך הכול — 100 נקודות
ג. חומר עזר מותר בשימוש: כל חומר עזר, חוץ ממחשבון שיש בו אפשרות תכנות.
יש לכתוב במחברת הבחינה בלבד, יש לרשום "טיוטה" בראש כל עמוד המשמש טיוטה.
כתיבת טיוטה בדפים שאינם במחברת הבחינה עלולה לגרום לפסילת הבחינה.
השאלות בשאלון זה מנוסחות בלשון רבים, אף על פי כן על כל תלמידה וכל תלמיד להשיב עליהן באופן אישי.
בהצלחה!
פרק ראשון
ענו על שלוש השאלות 3-1 (לכל שאלה – 10 נקודות).
שאלה 1 · תפקיד האובייקט Response
מהו תפקידו של אובייקט Response בתקשורת בין השרת לדפדפן?
העתיקו למחברת הבחינה את התשובה הנכונה מבין האפשרויות א–ד שלפניכם.
א. לשלוח בקשות מהדפדפן לשרת
ב. לטפל באחסון נתונים במסד הנתונים
ג. האובייקט מכיל את התגובה מהשרת לדפדפן
ד. לאמת את זהות המשתמש באמצעות סיסמה
העתיקו למחברת הבחינה את התשובה הנכונה מבין האפשרויות א–ד.
◂ פתרון מלא לשאלה 1
פתרון
ג. האובייקט מכיל את התגובה מהשרת לדפדפן
מה נדרש: לבחור את התיאור הנכון של האובייקט Response.
רעיון: בתקשורת שרת-לקוח יש שני כיוונים:
Request (למשל Request.Form, Request.QueryString).Response: Response.Write(...) כותב HTML לדף שיישלח, Response.Redirect(...) שולח לדפדפן הוראה לעבור לדף אחר.פתרון: התשובה הנכונה היא ג – האובייקט מכיל את התגובה מהשרת לדפדפן.
בדיקה – למה האחרות שגויות:
שאלה 2 · שאילתה על טבלת חדרי בריחה
במסד נתונים של חדרי בריחה מוגדרת טבלה בשם EscapeRoom ובה מאפייני החדרים. בטבלה יש ארבע עמודות:
כתבו שאילתה בשפת SQL המאחזרת את שמות ונושאי החדרים, בהם 5 שחקנים יכולים לשחק.
כתבו שאילתה בשפת SQL המאחזרת את שמות ונושאי החדרים, בהם 5 שחקנים יכולים לשחק.
◂ פתרון מלא לשאלה 2
פתרון
SELECT name, subject FROM EscapeRoom WHERE minUser <= 5 AND maxUser >= 5;
מה נדרש: שמות ונושאים של החדרים שקבוצה של 5 שחקנים יכולה לשחק בהם.
רעיון: 5 שחקנים יכולים לשחק בחדר אם 5 נמצא בטווח המותר של החדר: המינימום לכל היותר 5 וגם המקסימום לפחות 5. בוחרים (SELECT) רק את שתי העמודות name ו-subject ומסננים (WHERE) בשני תנאים המחוברים ב-AND.
פתרון:
SELECT name, subject
FROM EscapeRoom
WHERE minUser <= 5 AND maxUser >= 5;(אפשר גם לכתוב WHERE 5 BETWEEN minUser AND maxUser – BETWEEN כולל את שני הקצוות.)
בדיקה: השאילתה על טבלה לדוגמה:
| name | subject | minUser | maxUser | מתאים ל-5? |
|---|---|---|---|---|
| הכספת הנסתרת | שוד | 2 | 6 | כן |
| המעבדה | מדע | 4 | 5 | כן (5 הוא המקסימום) |
| הצוללת | ים | 5 | 8 | כן (5 הוא המינימום) |
| בית הקברות | אימה | 2 | 4 | לא (מקסימום 4) |
| החללית | חלל | 6 | 10 | לא (מינימום 6) |
התקבלו שלוש השורות הראשונות בלבד, כמצופה.
טעות נפוצה: לכתוב minUser = 5 או maxUser = 5 – כך מפספסים חדרים שבהם 5 נמצא בתוך הטווח. טעות נוספת: minUser >= 5 (הכיוון הפוך).
שאלה 3 · פלט של Response.Write עם רשימה
לפניכם הפונקציה Func, הכתובה בצד שרת.
public void Func (int num) {
string str = "<ul>";
for (int i = 1; i <= num; i++) {
if (i % 2 == 0)
str += "<li>Even number: " + i + "</li>";
else
str += "<li>Odd number: " + i + "</li>";
}
str += "</ul>";
Response.Write(str);
}כתבו במחברת הבחינה את הפלט שיוצג בדפדפן לאחר זימון הפונקציה Func(10).
כתבו במחברת הבחינה את הפלט שיוצג בדפדפן לאחר זימון הפונקציה Func(10).
◂ פתרון מלא לשאלה 3
פתרון
רשימת תבליטים של 10 שורות: Odd number: 1, Even number: 2, Odd number: 3, ..., Odd number: 9, Even number: 10 (כל שורה עם תבליט • בתחילתה).
מה נדרש: מה יראה המשתמש בדפדפן (לא את מחרוזת ה-HTML, אלא את התצוגה שלה).
רעיון: הפונקציה בונה מחרוזת HTML: <ul> פותח רשימה לא ממוספרת (רשימת תבליטים), כל <li>...</li> הוא פריט ברשימה, ובסוף </ul> סוגר אותה. הלולאה רצה על i מ-1 עד 10: עבור i זוגי (i % 2 == 0) נוסף פריט "Even number: i", ועבור i אי-זוגי – "Odd number: i". Response.Write שולח את המחרוזת לדפדפן, והדפדפן מציג אותה כרשימה.
פתרון – מעקב:
| i | i % 2 | הפריט שנוסף |
|---|---|---|
| 1 | 1 | <li>Odd number: 1</li> |
| 2 | 0 | <li>Even number: 2</li> |
| 3 | 1 | <li>Odd number: 3</li> |
| … | … | … |
| 9 | 1 | <li>Odd number: 9</li> |
| 10 | 0 | <li>Even number: 10</li> |
המחרוזת שנשלחת לדפדפן:
<ul><li>Odd number: 1</li><li>Even number: 2</li><li>Odd number: 3</li><li>Even number: 4</li><li>Odd number: 5</li><li>Even number: 6</li><li>Odd number: 7</li><li>Even number: 8</li><li>Odd number: 9</li><li>Even number: 10</li></ul>הפלט שיוצג בדפדפן – רשימת תבליטים (נקודה • לפני כל שורה), כל פריט בשורה נפרדת:
בדיקה: 10 פריטים – 5 אי-זוגיים (1, 3, 5, 7, 9) ו-5 זוגיים (2, 4, 6, 8, 10), לסירוגין, מתחילים ב-Odd כי 1 אי-זוגי.
טעות נפוצה: לכתוב את התגיות <li> כחלק מהפלט, או לרשום מספרים 1–10 בתחילת השורות – <ul> מציגה תבליטים ולא מספור (מספור היה מתקבל עם <ol>).
פרק שני
ענו על שלוש שאלות: על שאלה 4 (חובה – 10 נקודות) ועל שתיים מן השאלות 7-5 (לכל שאלה – 20 נקודות).
שאלה 4 · טבלת HTML עם colspan/rowspan וקישור (10 נקודות)
תומר, תלמיד מדעי המחשב, פיתח אתר ובו מידע על פינת ליטוף בעלי חיים.
<!DOCTYPE html>
<html lang="he" >
<meta charset="utf-8"/>
<table style="width:150px" border=2px dir="ltr">
<tr >
<td colspan=2 align="center">Animals</td>
</tr>
<tr>
<td rowspan=2>Dog</td>
<td>Bonnie</td>
</tr>
<tr >
<td >Lilo</td>
</tr>
<tr>
<td>Turtle</td>
<td>Alfi</td>
</tr>
<tr >
<td colspan=2 align="center">Lunch time</td>
</tr>
</table>
</html>כיצד יוצג הדף? כתבו במחברת הבחינה את מספר התשובה הנכונה מבין האפשרויות (a-d).

כתבו שורת קוד מתאימה ב- html כך שלחיצה על המילה Animals תעביר לאתר:
https://he.wikipedia.org/wiki/Animal
◂ פתרון מלא לשאלה 4
סעיף א
b
מה נדרש: לזהות איך הדפדפן מסדר את תאי הטבלה.
רעיון: עוברים שורה-שורה (<tr>) ומניחים כל תא (<td>) במקום הפנוי הבא בשורה. colspan=2 – התא תופס שתי עמודות; rowspan=2 – התא תופס גם את המקום שלו בשורה הבאה. dir="ltr" – התא הראשון בכל שורה נמצא משמאל.
פתרון – בניית הטבלה:
| שורה | מה כתוב בקוד | התוצאה |
|---|---|---|
| 1 | Animals עם colspan=2, ממורכז | Animals על פני שתי העמודות |
| 2 | Dog עם rowspan=2, ואחריו Bonnie | Dog בעמודה השמאלית (תופס גם את שורה 3), Bonnie מימין |
| 3 | רק Lilo | העמודה השמאלית תפוסה ע"י Dog, ולכן Lilo נכנס לעמודה הימנית – מתחת ל-Bonnie |
| 4 | Turtle, Alfi | Turtle משמאל, Alfi מימין |
| 5 | Lunch time עם colspan=2, ממורכז | Lunch time על פני שתי העמודות |
מתקבלת הטבלה של אפשרות b.
בדיקה: הצגנו את הקוד בדפדפן וקיבלנו בדיוק את סידור התאים של b. האפשרויות האחרות נפסלות:
סעיף ב
<td colspan=2 align="center"><a href="https://he.wikipedia.org/wiki/Animal">Animals</a></td>
מה נדרש: להפוך את המילה Animals לקישור.
רעיון: קישור נכתב בתגית <a> עם התכונה href שמכילה את כתובת היעד. הטקסט שבין <a ...> ל-</a> הוא מה שלוחצים עליו. עוטפים את המילה Animals בתוך התא הקיים (התא נשאר עם colspan=2 ו-align="center").
פתרון: מחליפים את שורת התא הראשון בשורה:
<td colspan=2 align="center"><a href="https://he.wikipedia.org/wiki/Animal">Animals</a></td>בדיקה: בהצגת הדף המילה Animals מופיעה כקישור (כחול עם קו תחתון) במרכז השורה העליונה, ולחיצה עליה מעבירה ל-https://he.wikipedia.org/wiki/Animal. מבנה הטבלה לא השתנה.
טעות נפוצה: לשים את <a> מחוץ ל-<td> (בין <tr> ל-<td>) – זה HTML לא תקין. טעות נוספת: לשכוח את המירכאות או את https:// בכתובת.
שאלה 5 · ניתוב בין דפים לפי משתני Session
באתר חדר בריחה "הכספת הנסתרת", על השחקן לפתוח כספת גדולה בחדר הראשון. על מנת להשיג זאת, האתר משתמש במספר משתני Session:
בהתבסס על משתנים אלה, המשתמש עובר לדף מתאים לפי החוקיות הבאה:
– אם time_room1 קטן מ-25 וגם solved_colors הוא true וגם keys_found שווה ל-5 ומעלה, השחקן מועבר לדף פתיחת הכספת openSafe.aspx.
– אם keys_found גדול או שווה ל- 3 וגם לפחות אחד משני התנאים הבאים מתקיים:
time_room1 קטן מ- 30 או solved_colors הוא true,
השחקן מועבר לדף רמזים cluePage.aspx.
– שאר השחקנים מועברים חזרה לדף הפתיחה openPage.aspx.
כתבו קוד המתאים לדרישות.
כתבו קוד המתאים לדרישות.
◂ פתרון מלא לשאלה 5
פתרון
קוראים את שלושת משתני ה-Session עם המרה (int)/(bool), ואז: if (time < 25 && solved && keys >= 5) Response.Redirect("openSafe.aspx"); else if (keys >= 3 && (time < 30 || solved)) Response.Redirect("cluePage.aspx"); else Response.Redirect("openPage.aspx");
מה נדרש: קוד צד שרת (C#) שמעביר את השחקן לאחד משלושה דפים לפי ערכי שלושה משתני Session.
רעיון:
(int) למספרים ו-(bool) לבוליאני.||) חייב להיות בתוך סוגריים.Response.Redirect("שם הדף").פתרון (בקובץ ה-code behind של הדף):
protected void Page_Load(object sender, EventArgs e)
{
int time = (int)Session["time_room1"];
bool solved = (bool)Session["solved_colors"];
int keys = (int)Session["keys_found"];
if (time < 25 && solved && keys >= 5)
Response.Redirect("openSafe.aspx");
else if (keys >= 3 && (time < 30 || solved))
Response.Redirect("cluePage.aspx");
else
Response.Redirect("openPage.aspx");
}בדיקה: בכל הצירופים של הערכים הקוד מפנה לדף הנכון. כמה דוגמאות:
| time_room1 | solved_colors | keys_found | הדף |
|---|---|---|---|
| 20 | true | 5 | openSafe.aspx |
| 20 | false | 5 | cluePage.aspx (אין חידת צבעים, אבל 3 מפתחות ומעלה וזמן < 30) |
| 40 | true | 3 | cluePage.aspx (הזמן גדול, אבל solved_colors = true) |
| 28 | false | 4 | cluePage.aspx |
| 40 | false | 6 | openPage.aspx (אף אחד משני התנאים הפנימיים לא מתקיים) |
| 10 | true | 2 | openPage.aspx (פחות מ-3 מפתחות) |
טעות נפוצה:
keys >= 3 && time < 30 || solved בלי סוגריים – בגלל ש-&& קודם ל-||, שחקן עם 0 מפתחות שפתר את חידת הצבעים היה מועבר לדף הרמזים.Session["keys_found"] ישירות בהשוואה בלי המרה ל-int – לא יעבור הידור.protected void Page_Load(object sender, EventArgs e)
{
int time = (int)Session["time_room1"];
bool solved = (bool)Session["solved_colors"];
int keys = (int)Session["keys_found"];
if (time < 25 && solved && keys >= 5)
Response.Redirect("openSafe.aspx");
else if (keys >= 3 && (time < 30 || solved))
Response.Redirect("cluePage.aspx");
else
Response.Redirect("openPage.aspx");
}שאלה 6 · זוג "ראש זנב"
זוג "ראש זנב" הוא זוג של מספרים חיוביים ושלמים שבו הספרה הראשונה באחד מן המספרים זהה לספרה האחרונה במספר האחר. אם יש רק ספרה אחת במספר, מספר זה נחשב כספרה ראשונה או כספרה אחרונה.
הערה: אין חשיבות לסדר המספרים בזוג המספרים.
דוגמאות לזוגות מספרים שהם "ראש זנב":
| מספר 1 | מספר 2 |
|---|---|
| 123 | 38 |
| 9 | 159 |
| 45 | 254 |
כתבו פונקציה בשם IsHeadTail בצד שרת, המקבלת שני מספרים שלמים ומחזירה אמת אם הם זוג "ראש זנב". אחרת, הפונקציה מחזירה שקר.
הערה: ניתן להשתמש בפעולות עזר.
כתבו פונקציה בשם IsHeadTail בצד שרת, המקבלת שני מספרים שלמים ומחזירה אמת אם הם זוג "ראש זנב". אחרת, הפונקציה מחזירה שקר.
◂ פתרון מלא לשאלה 6
פתרון
return FirstDigit(num1) == num2 % 10 || FirstDigit(num2) == num1 % 10; (FirstDigit מחלקת ב-10 כל עוד המספר ≥ 10)
מה נדרש: פונקציה בוליאנית שבודקת אם הספרה הראשונה של אחד המספרים שווה לספרה האחרונה של המספר האחר.
רעיון:
num % 10.num % 10 הוא המספר עצמו – כלומר הספרה היחידה נחשבת גם ראשונה וגם אחרונה, כנדרש.פתרון:
// פעולת עזר: מחזירה את הספרה הראשונה (השמאלית) של מספר חיובי
public int FirstDigit(int num)
{
while (num >= 10)
num = num / 10;
return num;
}
public bool IsHeadTail(int num1, int num2)
{
// הספרה הראשונה של אחד שווה לספרה האחרונה של האחר (בכל אחד משני הכיוונים)
return FirstDigit(num1) == num2 % 10 || FirstDigit(num2) == num1 % 10;
}בדיקה:
| num1 | num2 | חישוב | תוצאה |
|---|---|---|---|
| 123 | 38 | ראשונה של 38 היא 3, אחרונה של 123 היא 3 | True |
| 9 | 159 | ראשונה של 9 היא 9, אחרונה של 159 היא 9 | True |
| 45 | 254 | ראשונה של 45 היא 4, אחרונה של 254 היא 4 | True |
| 12 | 34 | 1≠4 וגם 3≠2 | False |
| 10 | 21 | ראשונה של 10 היא 1, אחרונה של 21 היא 1 | True |
| 100 | 23 | 1≠3 וגם 2≠0 | False |
טעות נפוצה: לבדוק רק כיוון אחד (ראשונה של num1 מול אחרונה של num2) – אז הזוג (9, 159) מהדוגמה כן עובד, אבל (123, 38) נכשל. טעות נוספת: לולאה while (num > 0) num = num / 10; – היא מגיעה ל-0 ומאבדת את הספרה.
// פעולת עזר: מחזירה את הספרה הראשונה (השמאלית) של מספר חיובי
public int FirstDigit(int num)
{
while (num >= 10)
num = num / 10;
return num;
}
public bool IsHeadTail(int num1, int num2)
{
// הספרה הראשונה של אחד שווה לספרה האחרונה של האחר (בכל אחד משני הכיוונים)
return FirstDigit(num1) == num2 % 10 || FirstDigit(num2) == num1 % 10;
}שאלה 7 · שאילתות SQL על טבלת פעילויות (20 נקודות)
במסד נתונים של קבוצת הצופים בעיר מסוימת יש טבלה ששמה GroupActivities המכילה את נתוני פעילויות הקבוצה. העמודות בטבלה הן:
דוגמה לטבלה:
| activityName | count | duration | dayNum | eveningNum |
|---|---|---|---|---|
| "טיול אופניים" | 40 | 240 | 25 | 30 |
| "סדנת יצירה" | 35 | 60 | 30 | 35 |
| "הפנינג קיץ" | 80 | 180 | 70 | 40 |
| "פיסול" | 15 | 50 | 10 | 7 |
יש לבחור 2 מתוך 4 הסעיפים הבאים:
כתבו שאילתה בשפת SQL שמחזירה את כמות הפעילויות בהם מספר המשתתפים המקסימלי גדול מ-20. דוגמה: בטבלה הנוכחית יוחזר הערך 3 (עבור סדנת יצירה, טיול אופניים והפנינג קיץ)
כתבו שאילתה בשפת SQL המחזירה את מספר המשתתפים הגדול ביותר שהיה בפעילות בשעות היום (הניחו שיש פעילות אחת כזו). דוגמה: בטבלה הנוכחית יוחזר הערך 70 ("הפנינג קיץ").
כתבו שאילתה בשפת SQL שמחזירה את שמות הפעילויות ואת משך הפעילות שלהם (בדקות), בפעילויות בהם מספר המשתתפים בערב גדול ממספר המשתתפים ביום.
כתבו שאילתה בשפת SQL שמחזירה את סך כל המשתתפים, בכל סוגי פעילויות, שהיו בפעילות יום. דוגמה: בטבלה הנוכחית יוחזר הערך 135 (25+30+70+10).
◂ פתרון מלא לשאלה 7
סעיף א
SELECT COUNT(*) AS numActivities FROM GroupActivities WHERE [count] > 20;
מה נדרש: מספר הפעילויות (כמה שורות) שבהן count גדול מ-20.
רעיון: מסננים ב-WHERE את השורות עם count > 20, וסופרים אותן בפונקציית הצבירה COUNT(*). שם העמודה count זהה לשם הפונקציה COUNT, ולכן כדאי לעטוף אותו בסוגריים מרובעים [count] כדי שיובן כשם עמודה.
פתרון:
SELECT COUNT(*) AS numActivities
FROM GroupActivities
WHERE [count] > 20;בדיקה: על טבלת הדוגמה: השורות המתאימות הן טיול אופניים (40), סדנת יצירה (35), הפנינג קיץ (80); פיסול (15) לא. התקבל 3, כמו בדוגמה.
טעות נפוצה: להחזיר את השמות (SELECT activityName) במקום את הכמות, או לכתוב >= 20 במקום > 20.
סעיף ב
SELECT MAX(dayNum) AS maxDay FROM GroupActivities;
מה נדרש: הערך הגדול ביותר בעמודה dayNum.
רעיון: פונקציית הצבירה MAX מחזירה את הערך המקסימלי בעמודה. אין צורך ב-WHERE – בודקים את כל הפעילויות.
פתרון:
SELECT MAX(dayNum) AS maxDay
FROM GroupActivities;בדיקה: הערכים בעמודה dayNum הם 25, 30, 70, 10. התקבל 70, כמו בדוגמה.
טעות נפוצה: לחפש את המקסימום בעמודה count (המספר המקסימלי המותר) – אבל השאלה שואלת על מספר המשתתפים בפועל בשעות היום, כלומר dayNum.
סעיף ג
SELECT activityName, duration FROM GroupActivities WHERE eveningNum > dayNum;
מה נדרש: שם ומשך של כל פעילות שבה eveningNum > dayNum.
רעיון: בוחרים את העמודות activityName ו-duration, ובתנאי WHERE משווים בין שתי עמודות באותה שורה – SQL מאפשר להשוות עמודה לעמודה, לא רק לקבוע.
פתרון:
SELECT activityName, duration
FROM GroupActivities
WHERE eveningNum > dayNum;בדיקה: על טבלת הדוגמה:
| activityName | duration |
|---|---|
| טיול אופניים | 240 |
| סדנת יצירה | 60 |
(30 > 25 ו-35 > 30; בהפנינג קיץ 40 < 70 ובפיסול 7 < 10.)
סעיף ד
SELECT SUM(dayNum) AS totalDay FROM GroupActivities;
מה נדרש: סכום העמודה dayNum על כל השורות.
רעיון: פונקציית הצבירה SUM מחברת את כל הערכים בעמודה.
פתרון:
SELECT SUM(dayNum) AS totalDay
FROM GroupActivities;בדיקה: 25 + 30 + 70 + 10 = 135 – התוצאה 135, כמו בדוגמה.
טעות נפוצה: להשתמש ב-COUNT(dayNum) – זה סופר שורות (4) ולא מחבר ערכים.
פרק שלישי
ענו על שאלה אחת מן השאלות 9-8.
שאלה 8 · ספירת כניסות עם Session ו-Application (20 נקודות)
בדף כניסה לאתר, על המשתמש להכניס שם משתמש וסיסמה. למשתמש יש 3 ניסיונות כניסה.
מטרת הקוד שלפניכם היא לספור את מספר הכניסות התקינות לאתר.
הקוד משתמש בפעולה Login כדי לבדוק שהשם משתמש והסיסמה תקינים (הניחו שהפעולה נתונה).
protected void Page_Load (object sender, EventArgs e)
{
if (Session["log"] == null) // איתחול
__________(1)___________;
if (_________(2)________) // LOGIN מותר מקסימום 3 נסיונות
Response.Write("חרגת ממספר הנסיונות האפשריים");
else
{
// המשתנים UserName, PassWord מכילים את שם המשתמש והסיסמא שהמשתמש הכניס בטופס
bool ok = Login(UserName, PassWord);
if (ok)
{
Application.Lock();
if (Application["myCount"] == null)
Application["myCount"] = 0;
Application["myCount"] = (int) (_________(3)________;
Application(_________(4)________ ();
}// End if
else
{
Session["log"] = ________(5)_________;
}// End else
}// End else
} // End Page_loadהשלימו את הקוד: כיתבו ליד כל מספר 5-1, את הביטוי החסר.
הסבירו מה התפקיד של Application["myCount"] בקטע הקוד .
הסבירו מה התפקיד של Session["log"] בקטע הקוד.
◂ פתרון מלא לשאלה 8
סעיף א
(1) Session["log"] = 0 (2) (int)Session["log"] >= 3 (3) Application["myCount"]) + 1 (4) UnLock (5) (int)Session["log"] + 1
מה נדרש: להשלים חמישה ביטויים בקוד שסופר כניסות תקינות ומגביל כל משתמש ל-3 ניסיונות.
רעיון:
Session["log"] – מונה אישי (לכל משתמש) של ניסיונות כניסה שנכשלו. בפעם הראשונה הוא null ולכן מאתחלים אותו ל-0.Application["myCount"]; כניסה שגויה מגדילה את המונה האישי.Application.Lock() ל-Application.UnLock(), כדי ששני משתמשים לא יעדכנו את המונה בו-זמנית.פתרון:
| מספר | הביטוי החסר | הסבר |
|---|---|---|
| (1) | Session["log"] = 0 | אתחול מונה הניסיונות הכושלים של המשתמש |
| (2) | (int)Session["log"] >= 3 | המשתמש כבר נכשל 3 פעמים – אין לו עוד ניסיונות |
| (3) | Application["myCount"]) + 1 | השורה המלאה: Application["myCount"] = (int) (Application["myCount"]) + 1; – המרה ל-int והוספת 1 |
| (4) | UnLock | שחרור הנעילה: Application.UnLock(); |
| (5) | (int)Session["log"] + 1 | ניסיון כושל – מגדילים את המונה האישי ב-1 |
הקוד המלא:
protected void Page_Load (object sender, EventArgs e)
{
if (Session["log"] == null) // איתחול
Session["log"] = 0;
if ((int)Session["log"] >= 3) // LOGIN מותר מקסימום 3 נסיונות
Response.Write("חרגת ממספר הנסיונות האפשריים");
else
{
// המשתנים UserName, PassWord מכילים את שם המשתמש והסיסמא שהמשתמש הכניס בטופס
bool ok = Login(UserName, PassWord);
if (ok)
{
Application.Lock();
if (Application["myCount"] == null)
Application["myCount"] = 0;
Application["myCount"] = (int) (Application["myCount"]) + 1;
Application.UnLock();
}// End if
else
{
Session["log"] = (int)Session["log"] + 1;
}// End else
}// End else
} // End Page_loadהערה: בשורה (4) מודפס בשאלון Application( – כנראה טעות דפוס במקום Application.; הפקודה הנדרשת היא Application.UnLock();.
בדיקה: Session נפרד לכל משתמש ו-Application משותף (סיסמה נכונה בדוגמה: 1234):
| פעולה | log של המשתמש | myCount |
|---|---|---|
| דנה – סיסמה שגויה | 1 | null |
| דנה – סיסמה נכונה | 1 | 1 |
| אבי – 3 סיסמאות שגויות | 1, 2, 3 | 1 |
| אבי – סיסמה נכונה | 3 – מוצגת ההודעה "חרגת ממספר הנסיונות האפשריים" | 1 |
| דנה – סיסמה נכונה | 1 | 2 |
טעות נפוצה: להשוות Session["log"] >= 3 בלי המרה – object אי אפשר להשוות למספר, והקוד לא עובר הידור. טעות נוספת: לשכוח את UnLock – אז הנעילה נשארת עד שהשרת מסיים לטפל בבקשה, ובינתיים בקשות של משתמשים אחרים שצריכות את Application ממתינות. משחררים את הנעילה מיד אחרי העדכון.
protected void Page_Load (object sender, EventArgs e)
{
if (Session["log"] == null) // איתחול
Session["log"] = 0;
if ((int)Session["log"] >= 3) // LOGIN מותר מקסימום 3 נסיונות
Response.Write("חרגת ממספר הנסיונות האפשריים");
else
{
// המשתנים UserName, PassWord מכילים את שם המשתמש והסיסמא שהמשתמש הכניס בטופס
bool ok = Login(UserName, PassWord);
if (ok)
{
Application.Lock();
if (Application["myCount"] == null)
Application["myCount"] = 0;
Application["myCount"] = (int) (Application["myCount"]) + 1;
Application.UnLock();
}// End if
else
{
Session["log"] = (int)Session["log"] + 1;
}// End else
}// End else
} // End Page_loadסעיף ב
מונה משותף לכל משתמשי האתר, שסופר את מספר הכניסות התקינות לאתר (מכל המשתמשים יחד).
מה נדרש: להסביר מה מייצג המשתנה Application["myCount"].
רעיון: משתנה Application נשמר בשרת אחד לכל האתר ומשותף לכל המשתמשים, ונשאר קיים כל זמן שהאתר פועל (לא נמחק כשמשתמש עוזב).
פתרון: Application["myCount"] הוא מונה הכניסות התקינות לאתר – של כל המשתמשים יחד. בכל פעם שמשתמש כלשהו מתחבר בהצלחה (Login מחזירה true), המונה גדל ב-1. בפעם הראשונה הוא null ולכן מאותחל ל-0. מאחר שכמה משתמשים עשויים להתחבר באותו רגע, העדכון נעשה בין Application.Lock() ל-Application.UnLock(), כדי שלא יאבדו ספירות.
בדיקה: אחרי שתי כניסות תקינות של דנה (ומשתמש נוסף שנחסם) הערך הוא 2 – אותו ערך נראה מכל ה-Session-ים.
סעיף ג
מונה אישי לכל משתמש של ניסיונות הכניסה שנכשלו; כשהוא מגיע ל-3 המשתמש נחסם.
מה נדרש: להסביר מה מייצג המשתנה Session["log"].
רעיון: משתנה Session נשמר בשרת בנפרד לכל משתמש (לכל דפדפן/גלישה), ולכן מתאים לשמירת מידע אישי בין טעינות של הדף.
פתרון: Session["log"] הוא מונה ניסיונות הכניסה הכושלים של המשתמש הנוכחי. בטעינה הראשונה הוא מאותחל ל-0; בכל ניסיון כושל (Login מחזירה false) הוא גדל ב-1; לפני כל ניסיון בודקים אותו, וכשהגיע ל-3 – המשתמש לא יכול לנסות שוב ומוצגת לו ההודעה "חרגת ממספר הנסיונות האפשריים". כך כל משתמש מוגבל ל-3 ניסיונות, בלי להשפיע על משתמשים אחרים.
בדיקה: אבי נחסם אחרי 3 כישלונות (log = 3) ואילו אצל דנה, באותו זמן, log = 1 והיא ממשיכה להתחבר.
שאלה 9 · הצגת טבלה ממסד נתונים ב-ASP.NET
שאלה זו מתייחסת לטבלת הנתונים GroupActivities המוצגת בשאלה 7.
ראש צוות הצופים מעוניין להפיק טבלה ובה נתוני כל הפעילויות אשר נמשכות לפחות 90 דקות ומתאימות לקבוצה של לפחות 15 אנשים. הפונקציה מקבלת מחרוזת התחברות למסד הנתונים connectionString ומציגה בטבלה את כל העמודות של הפעילויות המתאימות.
בפונקציה חסרים שמונה ביטויים מסומנים במספרים בין סוגריים עגולים. כתבו במחברת הבחינה את מספרי הביטויים החסרים (8-1), וכתבו ליד כל מספר את הביטוי החסר שהוא מייצג.
protected void printTable(string connectionString){
string resultStr = ______(1)_______;
DataSet ds = new DataSet();
SqlConnection connection = new SqlConnection(____(2)________);
SqlCommand cmd = new SqlCommand();
cmd.CommandText = "SELECT * FROM [dbo].[ GroupActivities ] WHERE ___(3)___ >= 90
____(4)____ count >= 15";
cmd.Connection = connection;
connection.___(5)____();
SqlDataAdapter adapter = new ____(6)______(cmd);
adapter.Fill(ds);
connection.Close();
resultStr += "<table dir=rtl><tr><th>activityName</th><th>duration</th>
<th>count</th><th>dayNum</th><th>eveningNum</th></tr>";
foreach (DataRow dr in ds.Tables[0].Rows) {
resultStr += "<___(7)_____>";
resultStr += "<td>" + dr["activityName"] + "</td>";
resultStr += "<td>" + dr["duration"] + "</td>";
resultStr += "<td>" + dr["count"] + "</td>";
resultStr += "<td>" + dr["dayNum"] + "</td>";
resultStr += "<td>" + dr["eveningNum"] + "</td>";
resultStr += "</tr>";
}
resultStr += "</table>";
Response.___(8)_____(resultStr);
}כתבו במחברת הבחינה את מספרי הביטויים החסרים (8-1), וכתבו ליד כל מספר את הביטוי החסר שהוא מייצג.
◂ פתרון מלא לשאלה 9
פתרון
(1) "" (2) connectionString (3) duration (4) AND (5) Open (6) SqlDataAdapter (7) tr (8) Write
מה נדרש: להשלים שמונה ביטויים בפונקציה ששולפת ממסד הנתונים את הפעילויות המתאימות ומציגה אותן בטבלת HTML.
רעיון – שלבי העבודה עם מסד נתונים:
SqlConnection) בעזרת מחרוזת ההתחברות.SqlCommand) עם טקסט השאילתה ומקשרים אותה לחיבור.DataSet בעזרת SqlDataAdapter, וסוגרים את החיבור.ds.Tables[0] ובונים מחרוזת HTML: שורת <tr> לכל פעילות, ובה תא <td> לכל עמודה.Response.Write.התנאי בשאלה: "נמשכות לפחות 90 דקות" ← duration >= 90, "ומתאימות לקבוצה של לפחות 15" ← count >= 15 – שני התנאים יחד, כלומר AND.
פתרון:
| מספר | הביטוי החסר | הסבר |
|---|---|---|
| (1) | "" | מחרוזת ריקה – מוסיפים לה בהמשך ב-+= |
| (2) | connectionString | מחרוזת ההתחברות שהפונקציה קיבלה כפרמטר |
| (3) | duration | עמודת משך הפעילות בדקות (≥ 90) |
| (4) | AND | שני התנאים צריכים להתקיים יחד |
| (5) | Open | connection.Open(); – פתיחת החיבור לפני השליפה |
| (6) | SqlDataAdapter | new SqlDataAdapter(cmd) – המתאם שממלא את ה-DataSet |
| (7) | tr | פתיחת שורה בטבלה, <tr> (נסגרת בהמשך ב-</tr>) |
| (8) | Write | Response.Write(resultStr); – שליחת הטבלה לדפדפן |
הפונקציה המלאה:
protected void printTable(string connectionString){
string resultStr = "";
DataSet ds = new DataSet();
SqlConnection connection = new SqlConnection(connectionString);
SqlCommand cmd = new SqlCommand();
cmd.CommandText = "SELECT * FROM [dbo].[GroupActivities] WHERE duration >= 90 AND count >= 15";
cmd.Connection = connection;
connection.Open();
SqlDataAdapter adapter = new SqlDataAdapter(cmd);
adapter.Fill(ds);
connection.Close();
resultStr += "<table dir=rtl><tr><th>activityName</th><th>duration</th><th>count</th><th>dayNum</th><th>eveningNum</th></tr>";
foreach (DataRow dr in ds.Tables[0].Rows) {
resultStr += "<tr>";
resultStr += "<td>" + dr["activityName"] + "</td>";
resultStr += "<td>" + dr["duration"] + "</td>";
resultStr += "<td>" + dr["count"] + "</td>";
resultStr += "<td>" + dr["dayNum"] + "</td>";
resultStr += "<td>" + dr["eveningNum"] + "</td>";
resultStr += "</tr>";
}
resultStr += "</table>";
Response.Write(resultStr);
}הערה: בשאלון השאילתה ושורת הכותרות של הטבלה מודפסות על פני שתי שורות, ובסוגריים המרובעים מופיעים רווחים ([ GroupActivities ]). בקוד C# אמיתי מחרוזת רגילה חייבת להיות בשורה אחת ושם הטבלה בלי רווחים, ולכן בפתרון הן כתובות כך.
בדיקה: הפונקציה על טבלת הדוגמה משאלה 7. השאילתה מחזירה את טיול אופניים (240 דקות, 40) ואת הפנינג קיץ (180 דקות, 80); סדנת יצירה (60 דקות) ופיסול (50 דקות) נפסלות בגלל משך הפעילות. המחרוזת שנשלחה לדפדפן:
<table dir=rtl><tr><th>activityName</th><th>duration</th><th>count</th><th>dayNum</th><th>eveningNum</th></tr><tr><td>טיול אופניים</td><td>240</td><td>40</td><td>25</td><td>30</td></tr><tr><td>הפנינג קיץ</td><td>180</td><td>80</td><td>70</td><td>40</td></tr></table>טעות נפוצה: להשלים ב-(4) OR – אז תוצג גם פעילות קצרה שמתאימה ל-15 אנשים (למשל סדנת יצירה). טעות נוספת: ב-(1) לכתוב null – זה עובד ב-C# אבל לא נכון רעיונית; מאתחלים מחרוזת שמוסיפים לה כמחרוזת ריקה.
protected void printTable(string connectionString){
string resultStr = "";
DataSet ds = new DataSet();
SqlConnection connection = new SqlConnection(connectionString);
SqlCommand cmd = new SqlCommand();
cmd.CommandText = "SELECT * FROM [dbo].[GroupActivities] WHERE duration >= 90 AND count >= 15";
cmd.Connection = connection;
connection.Open();
SqlDataAdapter adapter = new SqlDataAdapter(cmd);
adapter.Fill(ds);
connection.Close();
resultStr += "<table dir=rtl><tr><th>activityName</th><th>duration</th><th>count</th><th>dayNum</th><th>eveningNum</th></tr>";
foreach (DataRow dr in ds.Tables[0].Rows) {
resultStr += "<tr>";
resultStr += "<td>" + dr["activityName"] + "</td>";
resultStr += "<td>" + dr["duration"] + "</td>";
resultStr += "<td>" + dr["count"] + "</td>";
resultStr += "<td>" + dr["dayNum"] + "</td>";
resultStr += "<td>" + dr["eveningNum"] + "</td>";
resultStr += "</tr>";
}
resultStr += "</table>";
Response.Write(resultStr);
}טבלת התשובות
| שאלה | סעיף | תשובה |
|---|---|---|
| 1 | - | ג. האובייקט מכיל את התגובה מהשרת לדפדפן |
| 2 | - | SELECT name, subject FROM EscapeRoom WHERE minUser <= 5 AND maxUser >= 5; |
| 3 | - | רשימת תבליטים של 10 שורות: Odd number: 1, Even number: 2, Odd number: 3, ..., Odd number: 9, Even number: 10 (כל שורה עם תבליט • בתחילתה). |
| 4 | א | b |
| ב | <td colspan=2 align="center"><a href="https://he.wikipedia.org/wiki/Animal">Animals</a></td> | |
| 5 | - | קוראים את שלושת משתני ה-Session עם המרה (int)/(bool), ואז: if (time < 25 && solved && keys >= 5) Response.Redirect("openSafe.aspx"); else if (keys >= 3 && (time < 30 || solved)) Response.Redirect("cluePage.aspx"); else Response.Redirect("openPage.aspx"); |
| 6 | - | return FirstDigit(num1) == num2 % 10 || FirstDigit(num2) == num1 % 10; (FirstDigit מחלקת ב-10 כל עוד המספר ≥ 10) |
| 7 | א | SELECT COUNT(*) AS numActivities FROM GroupActivities WHERE [count] > 20; |
| ב | SELECT MAX(dayNum) AS maxDay FROM GroupActivities; | |
| ג | SELECT activityName, duration FROM GroupActivities WHERE eveningNum > dayNum; | |
| ד | SELECT SUM(dayNum) AS totalDay FROM GroupActivities; | |
| 8 | א | (1) Session["log"] = 0 (2) (int)Session["log"] >= 3 (3) Application["myCount"]) + 1 (4) UnLock (5) (int)Session["log"] + 1 |
| ב | מונה משותף לכל משתמשי האתר, שסופר את מספר הכניסות התקינות לאתר (מכל המשתמשים יחד). | |
| ג | מונה אישי לכל משתמש של ניסיונות הכניסה שנכשלו; כשהוא מגיע ל-3 המשתמש נחסם. | |
| 9 | - | (1) "" (2) connectionString (3) duration (4) AND (5) Open (6) SqlDataAdapter (7) tr (8) Write |