מתכונת 5 במדעי המחשב - תכנות באינטרנט 899372
נבחנים אקסטרניים · שאלון 899372 · 9 שאלות · 2 שעות · פתרון מלא לכל סעיף
מבחן מתכונת במדעי המחשב, תכנות באינטרנט, במבנה של בחינת הבגרות. כל שאלה בו בנויה כמו שאלה מבגרות אחרת. לכל סעיף יש תשובה ופתרון מלא, וכל קוד מופיע ב-Java וב-C#. פתרו בזמן של הבחינה, ורק אחר כך פתחו את הפתרונות.
הוראות הבחינה
א. משך הבחינה: שעתיים.
ב. מבנה השאלון ומפתח הערכה: בשאלון זה שלושה פרקים.
פרק ראשון — (10x3) — 30 נקודות
פרק שני — (20x2)+(10x1) — 50 נקודות
פרק שלישי — (20x1) — 20 נקודות
סך הכול — 100 נקודות
ג. חומר עזר מותר בשימוש: כל חומר עזר, חוץ ממחשבון שיש בו אפשרות תכנות.
יש לכתוב במחברת הבחינה בלבד, יש לרשום "טיוטה" בראש כל עמוד המשמש טיוטה.
כתיבת טיוטה בדפים שאינם במחברת הבחינה עלולה לגרום לפסילת הבחינה.
השאלות בשאלון זה מנוסחות בלשון רבים, אף על פי כן על כל תלמידה וכל תלמיד להשיב עליהן באופן אישי.
בהצלחה!
פרק ראשון
ענו על שלוש השאלות 3-1 (לכל שאלה – 10 נקודות).
שאלה 1 · הפקודה Response.Redirect
בקוד צד השרת של הדף login.aspx, לאחר שהמשתמש הזין שם משתמש וסיסמה נכונים, מתבצעת הפקודה:
Response.Redirect("menu.aspx");מה קורה בעקבות ביצוע הפקודה?
א. הטקסט menu.aspx נכתב בתוך הדף login.aspx המוצג בדפדפן
ב. השרת שולח לדפדפן הוראה לעבור לדף menu.aspx, והדפדפן שולח לשרת בקשה חדשה לדף זה
ג. שם הדף menu.aspx נשמר באובייקט Session של המשתמש
ד. הדף menu.aspx נשמר במסד הנתונים של האתר
מה קורה בעקבות ביצוע הפקודה Response.Redirect("menu.aspx"); בקוד צד השרת?
◂ פתרון מלא לשאלה 1
פתרון
ב. השרת שולח לדפדפן הוראה לעבור לדף menu.aspx, והדפדפן שולח לשרת בקשה חדשה לדף זה
מה נדרש – להבין מה עושה הפעולה Redirect של האובייקט Response.
רעיון – האובייקט Response מייצג את התגובה שהשרת שולח ללקוח (לדפדפן). הפעולה Response.Redirect(url) אינה שולחת לדפדפן את תוכן הדף, אלא הוראת הפניה: "עבור לכתובת menu.aspx". הדפדפן מקבל את ההוראה, שולח לשרת בקשה חדשה לדף menu.aspx, והשרת מריץ את הדף ומחזיר אותו. כך, לאחר התחברות מוצלחת, המשתמש מגיע לדף התפריט.
פתרון – התשובה הנכונה: ב.
בדיקה – למה האחרות שגויות:
Response.Write(...), לא Redirect.Session["page"] = "menu.aspx";. Redirect אינו שומר דבר.השרת מחזיר תגובה עם קוד 302 (הפניה), הכתובת Location = menu.aspx וגוף דף ריק – כלומר רק הוראה לדפדפן לבקש דף אחר.
טעות נפוצה: לחשוב שהשרת "מדביק" את הדף menu.aspx בתוך הדף הנוכחי – בפועל הדפדפן מבקש את הדף החדש בבקשה נפרדת.
שאלה 2 · תגית לשורה בטבלה
איזו תגית HTML משמשת ליצירת שורה בטבלה?
א. <td>
ב. <th>
ג. <table>
ד. <tr>
איזו תגית HTML משמשת ליצירת שורה בטבלה?
◂ פתרון מלא לשאלה 2
פתרון
ד. <tr>
מה נדרש: לזהות את התגית שיוצרת שורה בטבלת HTML.
רעיון: טבלה בנויה משורות, וכל שורה בנויה מתאים. שורה = Table Row, ובקיצור tr.
פתרון:
<td> – תא רגיל בתוך שורה (Table Data).<th> – תא כותרת (Table Header); הטקסט שבו מודגש וממורכז.<table> – הטבלה כולה (התגית העוטפת).<tr> – שורה בטבלה (Table Row). ✓דוגמה – טבלה עם שתי שורות ושני תאים בכל שורה:
<table border="1">
<tr>
<td>שם</td>
<td>ציון</td>
</tr>
<tr>
<td>דנה</td>
<td>95</td>
</tr>
</table>תשובה: ד.
בדיקה: בדוגמה יש שתי תגיות <tr> וארבע תגיות <td>. בטבלה יש בדיוק 2 שורות ו-2 עמודות – מספר השורות שווה למספר תגיות ה-<tr>.
טעות נפוצה: לבחור <td> – אבל <td> יוצרת תא אחד בתוך שורה, ולא את השורה עצמה.
שאלה 3 · פלט של פעולת שרת – טבלת HTML בשורה אחת
לפניכם פעולה בשם Draw הכתובה בצד שרת. העתיקו למחברתכם את מה שיוצג בדפדפן לאחר הרצת הפעולה Draw עם הפרמטר n = 7.
public void Draw (int n) {
string str = "<table border = '1'><tr>";
for (int i = n; i >= 1; i--)
{
if (i % 4 == 0)
str += "<td>Tik</td>";
else if (i % 2 == 0)
str += "<td>" + (i * 10) + "</td>";
else
str += "<td>" + i + "</td>";
}
str += "</tr></table>";
Response.Write (str);
}העתיקו למחברתכם את מה שיוצג בדפדפן לאחר הרצת הפעולה Draw עם הפרמטר n = 7.
◂ פתרון מלא לשאלה 3
פתרון
טבלה עם מסגרת, שורה אחת ו־7 תאים, משמאל לימין: 7, 60, 5, Tik, 3, 20, 1
מה נדרש – לא את קוד ה-HTML, אלא את מה שהדפדפן מציג אחרי שהשרת שולח לו את המחרוזת str.
רעיון – לפני הלולאה נפתחות הטבלה (עם מסגרת, border = '1') ושורה אחת (<tr>). בכל סיבוב של הלולאה נוסף תא (<td>) לאותה שורה, ורק אחרי הלולאה השורה והטבלה נסגרות. לכן מתקבלת טבלה בעלת שורה אחת ו־7 תאים זה לצד זה. הלולאה רצה מ־n כלפי מטה (i = 7, 6, ..., 1), ולכן התא הראשון הוא של i = 7. שימו לב שהבדיקה i % 4 == 0 נעשית לפני i % 2 == 0.
פתרון – מעקב:
| i | i % 4 == 0 ? | i % 2 == 0 ? | התא שנוסף |
|---|---|---|---|
| 7 | לא | לא | <td>7</td> |
| 6 | לא | כן | <td>60</td> (6 * 10) |
| 5 | לא | לא | <td>5</td> |
| 4 | כן | (לא נבדק) | <td>Tik</td> |
| 3 | לא | לא | <td>3</td> |
| 2 | לא | כן | <td>20</td> (2 * 10) |
| 1 | לא | לא | <td>1</td> |
המחרוזת שנשלחת לדפדפן:
<table border = '1'><tr><td>7</td><td>60</td><td>5</td><td>Tik</td><td>3</td><td>20</td><td>1</td></tr></table>מה יוצג בדפדפן – טבלה עם מסגרת סביב כל תא, שורה אחת ושבעה תאים (משמאל לימין):
| 7 | 60 | 5 | Tik | 3 | 20 | 1 |
|---|
בדיקה – עבור n = 7 מתקבלת בדיוק המחרוזת שלמעלה – שורה אחת (<tr> אחד) ושבעה תאים.
טעות נפוצה: לכתוב 40 עבור i = 4 (כי 4 זוגי) – אבל התנאי הראשון i % 4 == 0 מתקיים ולכן נכתב Tik. טעות נוספת: לצייר את התאים זה מתחת לזה – כל התאים נמצאים באותו <tr>, ולכן הם מוצגים באותה שורה.
פרק שני
ענו על שלוש שאלות: על שאלה 4 (חובה – 10 נקודות) ועל שתיים מן השאלות 7-5 (לכל שאלה – 20 נקודות).
שאלה 4 · טבלת HTML עם colspan/rowspan וקישור לדף באתר (10 נקודות)
עידו, תלמיד מדעי המחשב, בנה אתר ובו מידע על שמורות טבע בצפון הארץ. באתר תיקייה בשם Images ובה תמונה של הר בשם mountain.png, ותיקייה בשם Pages ובה הדף meron.html.
<!DOCTYPE html>
<html lang="he">
<meta charset="utf-8"/>
<table style="width:240px" border="2" dir="rtl">
<tr>
<td colspan="3">שמורות טבע בצפון</td>
</tr>
<tr>
<td rowspan="2">נחלים</td>
<td>תל דן</td>
<td>בניאס</td>
</tr>
<tr>
<td>נחל עמוד</td>
<td>נחל כזיב</td>
</tr>
<tr>
<td>הרים</td>
<td colspan="2">הר מירון</td>
</tr>
<tr>
<td colspan="3" align="center">
<img src="Images/mountain.png" />
</td>
</tr>
</table>
</html>כיצד יוצג הדף? כתבו במחברת הבחינה את האות של התשובה הנכונה מבין האפשרויות (a-d).

הוסיפו קוד HTML מתאים כך שלחיצה על הכיתוב "הר מירון" תעביר לדף meron.html שבתיקייה Pages באתר.
◂ פתרון מלא לשאלה 4
סעיף א
c
מה נדרש – לזהות איזה מארבעת הציורים מתאים לטבלה שבקוד.
רעיון – עוברים שורה־שורה (<tr>) וסופרים תאים. colspan – תא שמתפרש על כמה עמודות; rowspan – תא שמתפרש על כמה שורות. dir="rtl" – התא הראשון בכל שורה מופיע מימין. בטבלה 3 עמודות (שורה 2 מכילה 3 תאים).
פתרון
colspan="3" – "שמורות טבע בצפון" לרוחב כל הטבלה.rowspan="2" בעמודה הימנית, תופס גם את שורה 3; משמאל לו "תל דן" ואחריו "בניאס".colspan="2" – על פני שתי העמודות השמאליות.colspan="3" עם align="center" – תמונת ההר במרכז שורה ברוחב כל הטבלה.נפסול את האפשרויות האחרות:
תשובה: c.
בדיקה – בדפדפן הקוד מוצג בדיוק כמו ציור c; שלושת הציורים האחרים מתאימים לגרסאות שגויות של הקוד (בלי rowspan, ltr, בלי colspan בשורה 4).
טעות נפוצה: לחשוב שבשורה 3 התא הראשון ("נחל עמוד") יופיע בעמודה הימנית – אבל המקום הזה תפוס על ידי התא עם rowspan משורה 2.
סעיף ב
עוטפים את הכיתוב בתגית קישור עם כתובת יחסית:
<td colspan="2"><a href="Pages/meron.html">הר מירון</a></td>
מה נדרש – שלחיצה על הכיתוב "הר מירון" תעביר לדף meron.html שנמצא בתיקייה Pages של האתר.
רעיון – קישור נוצר בתגית <a href="...">, ומה שנמצא בין <a> ל־</a> הוא האזור הלחיץ. הדף נמצא באותו אתר, לכן מספיקה כתובת יחסית – שם התיקייה ושם הקובץ: Pages/meron.html (בדיוק כמו Images/mountain.png בתגית התמונה).
פתרון – התא של "הר מירון" הופך ל:
<td colspan="2"><a href="Pages/meron.html">הר מירון</a></td>הדף המלא אחרי השינוי:
<!DOCTYPE html>
<html lang="he">
<meta charset="utf-8"/>
<table style="width:240px" border="2" dir="rtl">
<tr>
<td colspan="3">שמורות טבע בצפון</td>
</tr>
<tr>
<td rowspan="2">נחלים</td>
<td>תל דן</td>
<td>בניאס</td>
</tr>
<tr>
<td>נחל עמוד</td>
<td>נחל כזיב</td>
</tr>
<tr>
<td>הרים</td>
<td colspan="2"><a href="Pages/meron.html">הר מירון</a></td>
</tr>
<tr>
<td colspan="3" align="center">
<img src="Images/mountain.png" />
</td>
</tr>
</table>
</html>בדיקה – הצגנו את הדף המתוקן בדפדפן: מבנה הטבלה לא השתנה, והכיתוב "הר מירון" מוצג כקישור (קו תחתון) שמוביל ל־Pages/meron.html. בהשוואה לקוד המקורי השתנתה שורה אחת בלבד.
טעות נפוצה: לשים את תגית <a> מחוץ ל־<td> (בין <tr> ל־<td>) – זה HTML לא תקין בטבלה. טעות נוספת: לכתוב href="meron.html" בלי שם התיקייה – הדפדפן יחפש את הקובץ ליד הדף הנוכחי ולא ימצא אותו.
שאלה 5 · הצגת מתנדבים מעיר נבחרת – השלמת ביטויים
בעמותה "לב פתוח" מתנדבים תושבים מכמה ערים. במסד הנתונים קיימת טבלה - Volunteers, השומרת לכל מתנדב את שמו (FullName), את העיר שבה הוא גר (City) ואת מספר שעות ההתנדבות שלו החודש (Hours, מספר שלם).
לפניכם פונקציה שכותרתה: protected void showVolunteers(string connectionString, string city)
הפונקציה מקבלת מחרוזת connectionString שמפנה לבסיס הנתונים, ושם של עיר city. הפונקציה מציגה בדף טבלת HTML ובה השם ומספר השעות של כל המתנדבים מהעיר city, מסודרים מהמתנדב שהתנדב הכי הרבה שעות להכי מעט, ובשורה האחרונה של הטבלה – סך כל השעות של מתנדבי העיר.
דוגמה לטבלה שתוצג עבור city = "חיפה":
| שם המתנדב | שעות |
|---|---|
| מאיה פרץ | 51 |
| נועה כהן | 34 |
| רוני אדלר | 19 |
| יונתן אזולאי | 8 |
| סך הכול | 112 |
בפונקציה חסרים שמונה ביטויים מסומנים במספרים בין סוגריים עגולים. כתבו במחברת הבחינה את מספרי הביטויים החסרים (1) – (8), בסדר עולה, וכתבו ליד כל מספר את הביטוי החסר שהוא מייצג.
protected void showVolunteers(string connectionString, string city)
{
string html = "";
int total = 0;
DataSet ds = ______(1)______;
SqlConnection conn = new SqlConnection(connectionString);
SqlCommand cmd = new SqlCommand();
cmd.CommandText = "SELECT FullName, Hours FROM Volunteers WHERE ______(2)______ ORDER BY Hours DESC";
cmd.Connection = ______(3)______;
SqlDataAdapter adapter = new SqlDataAdapter(cmd);
conn.Open();
adapter.Fill(ds, "vol");
conn.Close();
DataTable t = ds.Tables[______(4)______];
html += "<table border='1'><tr><th>שם המתנדב</th><th>שעות</th></tr>";
for (int i = 0; i < ______(5)______; i++)
{
DataRow row = t.Rows[i];
html += "<tr><td>" + row["FullName"] + "</td><td>" + row["Hours"] + "</td></tr>";
total = total + ______(6)______;
}
html += "<tr><td>סך הכול</td><td>" + total + "</td></tr>";
html += ______(7)______;
______(8)______;
}בפונקציה חסרים שמונה ביטויים מסומנים במספרים בין סוגריים עגולים. כתבו במחברת הבחינה את מספרי הביטויים החסרים (1) – (8), בסדר עולה, וכתבו ליד כל מספר את הביטוי החסר שהוא מייצג.
◂ פתרון מלא לשאלה 5
פתרון
(1) new DataSet()
(2) City = '" + city + "'
(3) conn
(4) "vol"
(5) t.Rows.Count
(6) (int)row["Hours"]
(7) "</table>"
(8) Response.Write(html)
מה נדרש – להשלים 8 ביטויים בפונקציה שקוראת ממסד הנתונים את המתנדבים של עיר אחת, מציגה אותם בטבלת HTML ומחשבת את סך השעות.
רעיון – הדרך הרגילה לקרוא נתונים: חיבור (SqlConnection) ← פקודה (SqlCommand) עם שאילתה וחיבור ← מתאם (SqlDataAdapter) שממלא DataSet ← לוקחים מה-DataSet את ה-DataTable ← עוברים על השורות, בונים מחרוזת HTML ובדרך צוברים סכום ← Response.Write.
פתרון
| מספר | הביטוי החסר | הסבר |
|---|---|---|
| (1) | new DataSet() | יוצרים את ה-DataSet שהמתאם ימלא בהמשך. |
| (2) | City = '" + city + "' | תנאי הסינון: רק השורות שבהן העיר שווה לפרמטר city. ערך טקסט ב-SQL נכתב בין גרשיים בודדים, ולכן סוגרים את המחרוזת של C#, משרשרים את city ופותחים אותה שוב: התוצאה היא למשל WHERE City = 'חיפה' ORDER BY Hours DESC. |
| (3) | conn | הפקודה צריכה לדעת דרך איזה חיבור לעבוד – החיבור conn שנוצר בשורה הקודמת. |
| (4) | "vol" | המתאם מילא את ה-DataSet בטבלה בשם "vol" (Fill(ds, "vol")), ולכן ניגשים אליה בשמה. גם 0 (הטבלה הראשונה) נכון. |
| (5) | t.Rows.Count | הלולאה עוברת לפי מספר (אינדקס) על כל שורות הטבלה – מספר השורות הוא t.Rows.Count. |
| (6) | (int)row["Hours"] | צוברים את מספר השעות של השורה. row["Hours"] הוא מטיפוס object, ולכן צריך המרה למספר: (int)row["Hours"] או Convert.ToInt32(row["Hours"]). |
| (7) | "</table>" | סוגרים את טבלת ה-HTML. |
| (8) | Response.Write(html) | שולחים את מחרוזת ה-HTML לדפדפן. |
הפונקציה המלאה:
protected void showVolunteers(string connectionString, string city)
{
string html = "";
int total = 0;
DataSet ds = new DataSet();
SqlConnection conn = new SqlConnection(connectionString);
SqlCommand cmd = new SqlCommand();
cmd.CommandText = "SELECT FullName, Hours FROM Volunteers WHERE City = '" + city + "' ORDER BY Hours DESC";
cmd.Connection = conn;
SqlDataAdapter adapter = new SqlDataAdapter(cmd);
conn.Open();
adapter.Fill(ds, "vol");
conn.Close();
DataTable t = ds.Tables["vol"];
html += "<table border='1'><tr><th>שם המתנדב</th><th>שעות</th></tr>";
for (int i = 0; i < t.Rows.Count; i++)
{
DataRow row = t.Rows[i];
html += "<tr><td>" + row["FullName"] + "</td><td>" + row["Hours"] + "</td></tr>";
total = total + (int)row["Hours"];
}
html += "<tr><td>סך הכול</td><td>" + total + "</td></tr>";
html += "</table>";
Response.Write(html);
}בדיקה – טבלה עם 7 מתנדבים והפונקציה המלאה ב-C#. עבור "חיפה" נשלחה השאילתה SELECT FullName, Hours FROM Volunteers WHERE City = 'חיפה' ORDER BY Hours DESC והתקבלה בדיוק הטבלה שבדוגמה: מאיה פרץ 51, נועה כהן 34, רוני אדלר 19, יונתן אזולאי 8, ובשורה האחרונה סך הכול 112. עבור עיר שאין בה מתנדבים התקבלה טבלה עם שורת הכותרות ושורת "סך הכול" 0 בלבד. גם עם Tables[0] ועם Convert.ToInt32(row["Hours"]) התקבלה אותה תוצאה.
טעות נפוצה: לכתוב ב-(2) City = city – כך מחפשים עמודה בשם city ולא את הערך שהתקבל בפרמטר; וב-(6) לכתוב total + row["Hours"] בלי המרה – זו שגיאת הידור (object).
protected void showVolunteers(string connectionString, string city)
{
string html = "";
int total = 0;
DataSet ds = new DataSet();
SqlConnection conn = new SqlConnection(connectionString);
SqlCommand cmd = new SqlCommand();
cmd.CommandText = "SELECT FullName, Hours FROM Volunteers WHERE City = '" + city + "' ORDER BY Hours DESC";
cmd.Connection = conn;
SqlDataAdapter adapter = new SqlDataAdapter(cmd);
conn.Open();
adapter.Fill(ds, "vol");
conn.Close();
DataTable t = ds.Tables["vol"];
html += "<table border='1'><tr><th>שם המתנדב</th><th>שעות</th></tr>";
for (int i = 0; i < t.Rows.Count; i++)
{
DataRow row = t.Rows[i];
html += "<tr><td>" + row["FullName"] + "</td><td>" + row["Hours"] + "</td></tr>";
total = total + (int)row["Hours"];
}
html += "<tr><td>סך הכול</td><td>" + total + "</td></tr>";
html += "</table>";
Response.Write(html);
}שאלה 6 · זוג "תאומים"
זוג "תאומים" הוא זוג של מספרים חיוביים ושלמים שבהם מספר הספרות זהה וגם סכום הספרות זהה.
דוגמאות לזוגות מספרים שהם "תאומים":
| מספר 1 | מספר 2 | הסבר |
|---|---|---|
| 352 | 514 | בשניהם 3 ספרות, סכום הספרות 10 |
| 47 | 74 | בשניהם 2 ספרות, סכום הספרות 11 |
| 1090 | 2008 | בשניהם 4 ספרות, סכום הספרות 10 |
הזוג 1234 ו-55 אינו זוג "תאומים": סכום הספרות בשניהם הוא 10, אך מספר הספרות שונה.
כתבו פונקציה בשם IsTwins בצד שרת, המקבלת שני מספרים שלמים חיוביים ומחזירה אמת אם הם זוג "תאומים". אחרת, הפונקציה מחזירה שקר.
הערה: ניתן להשתמש בפעולות עזר.
כתבו פונקציה בשם IsTwins בצד שרת, המקבלת שני מספרים שלמים חיוביים ומחזירה אמת אם הם זוג "תאומים". אחרת, הפונקציה מחזירה שקר.
◂ פתרון מלא לשאלה 6
פתרון
return CountDigits(num1) == CountDigits(num2) && SumDigits(num1) == SumDigits(num2); (שתי פעולות עזר: ספירת ספרות וסכום ספרות בלולאת while (num > 0) עם % 10 ו-/ 10)
מה נדרש: פונקציה בוליאנית שבודקת ששני מספרים זהים גם במספר הספרות וגם בסכום הספרות.
רעיון:
num % 10 היא ספרת האחדות, ו-num / 10 (חילוק שלמים) "מוחק" אותה. ממשיכים כל עוד num > 0.&&.פתרון:
// פעולת עזר: מחזירה את מספר הספרות של מספר חיובי
public int CountDigits(int num)
{
int count = 0;
while (num > 0)
{
count++;
num = num / 10;
}
return count;
}
// פעולת עזר: מחזירה את סכום הספרות של מספר חיובי
public int SumDigits(int num)
{
int sum = 0;
while (num > 0)
{
sum = sum + num % 10;
num = num / 10;
}
return sum;
}
public bool IsTwins(int num1, int num2)
{
return CountDigits(num1) == CountDigits(num2) && SumDigits(num1) == SumDigits(num2);
}בדיקה:
| num1 | num2 | ספרות | סכומים | תוצאה |
|---|---|---|---|---|
| 352 | 514 | 3, 3 | 10, 10 | True |
| 47 | 74 | 2, 2 | 11, 11 | True |
| 1090 | 2008 | 4, 4 | 10, 10 | True |
| 1234 | 55 | 4, 2 | 10, 10 | False |
| 305 | 44 | 3, 2 | 8, 8 | False |
| 7 | 16 | 1, 2 | 7, 7 | False |
טעות נפוצה: לבדוק רק את סכום הספרות (אז 1234 ו-55 ייחשבו בטעות "תאומים"). טעות נוספת: לכתוב את שתי הלולאות ישירות בפונקציה על num1 – אחרי הלולאה הראשונה num1 כבר 0, והלולאה השנייה לא רצה. בפעולות עזר אין בעיה, כי כל פעולה מקבלת עותק של המספר.
// פעולת עזר: מחזירה את מספר הספרות של מספר חיובי
public int CountDigits(int num)
{
int count = 0;
while (num > 0)
{
count++;
num = num / 10;
}
return count;
}
// פעולת עזר: מחזירה את סכום הספרות של מספר חיובי
public int SumDigits(int num)
{
int sum = 0;
while (num > 0)
{
sum = sum + num % 10;
num = num / 10;
}
return sum;
}
public bool IsTwins(int num1, int num2)
{
return CountDigits(num1) == CountDigits(num2) && SumDigits(num1) == SumDigits(num2);
}שאלה 7 · סל קניות במאפייה – ערך שאינו נשמר בין לחיצות
לפניכם דף האינטרנט הבא (צד שרת) של מאפייה:
בדף שני כפתורים: לחם (12 ש"ח) ועוגה (45 ש"ח). מטרת התוכנית היא שבכל לחיצה על אחד הכפתורים יתווסף פריט לסל, והדף יציג את מספר הפריטים בסל ואת הסכום הכולל לתשלום על כל הפריטים, אולם התוכנית אינה מבצעת את הנדרש.
רשמו והסברו היכן התקלה וכיצד ניתן לתקנה.
<%@ Page Language="C#" %>
<script runat="server">
public int total = 0;
public void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
Session["items"] = 0;
}
}
void Bread_Click(object sender, EventArgs e)
{
total = total + 12;
Session["items"] = (int)Session["items"] + 1;
}
void Cake_Click(object sender, EventArgs e)
{
total = total + 45;
Session["items"] = (int)Session["items"] + 1;
}
</script>
<html>
<head>
</head>
<body>
<form id="form1" runat="server">
<input type="button" runat="server" id="btnBread" value="לחם – 12 ש"ח" onserverclick="Bread_Click" />
<input type="button" runat="server" id="btnCake" value="עוגה – 45 ש"ח" onserverclick="Cake_Click" />
<div runat="server" id="div1">
פריטים בסל: <% =Session["items"] %> , לתשלום: <% =total %> ש"ח
</div>
</form>
</body>
</html>רשמו והסברו היכן התקלה וכיצד ניתן לתקנה.
◂ פתרון מלא לשאלה 7
פתרון
הסכום נשמר בשדה של הדף (public int total = 0). בכל לחיצה (postback) נוצר אובייקט דף חדש ו-total מתחיל מ-0, ולכן מוצג רק מחיר הפריט האחרון (12 או 45). התיקון: לשמור את הסכום ב-Session – לאתחל Session["total"] = 0 בתוך if (!IsPostBack), בכל לחיצה Session["total"] = (int)Session["total"] + מחיר, ולהציג <% =Session["total"] %>.
מה נדרש – למצוא למה הדף אינו מציג את הסכום הכולל, ולתקן.
רעיון – כל לחיצה על כפתור עם runat="server" ו-onserverclick שולחת את הטופס לשרת (postback). בכל בקשה השרת יוצר אובייקט דף חדש, ולכן כל שדה של הדף (משתנה שמוגדר בתוך ה-script מחוץ לפעולות) מתחיל מחדש בערך ההתחלתי שלו. רק Session (או Application) שומר ערך בין בקשות.
פתרון
Session["items"], מאותחל ל-0 רק בכניסה הראשונה (!IsPostBack) וגדל ב-1 בכל לחיצה – הוא מוצג נכון.public int total = 0;. בכל לחיצה נוצר אובייקט דף חדש ו-total מתחיל שוב מ-0, הפעולה מוסיפה לו רק את מחיר הפריט שנלחץ עכשיו, ולכן מוצג תמיד מחיר הפריט האחרון (12 או 45) ולא הסכום של כל הסל.התיקון – לשמור את הסכום ב-Session: לאתחל Session["total"] = 0 בכניסה הראשונה, להוסיף את המחיר ל-Session["total"] בכל לחיצה (עם המרה (int)), ולהציג את Session["total"]. קטע הסקריפט המתוקן:
public void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
Session["items"] = 0;
Session["total"] = 0;
}
}
void Bread_Click(object sender, EventArgs e)
{
Session["total"] = (int)Session["total"] + 12;
Session["items"] = (int)Session["items"] + 1;
}
void Cake_Click(object sender, EventArgs e)
{
Session["total"] = (int)Session["total"] + 45;
Session["items"] = (int)Session["items"] + 1;
}ושורת התצוגה בדף:
<div runat="server" id="div1">
פריטים בסל: <% =Session["items"] %> , לתשלום: <% =Session["total"] %> ש"ח
</div>(השדה total כבר לא נחוץ, ואפשר למחוק אותו.)
בדיקה – הדמינו את מחזור החיים (אובייקט דף חדש בכל בקשה, אותו Session, Page_Load ואחריו פעולת הלחיצה):
| בקשה | הדף המקורי | הדף המתוקן |
|---|---|---|
| כניסה ראשונה | פריטים בסל: 0 , לתשלום: 0 | פריטים בסל: 0 , לתשלום: 0 |
| לחיצה על לחם | פריטים בסל: 1 , לתשלום: 12 | פריטים בסל: 1 , לתשלום: 12 |
| לחיצה על עוגה | פריטים בסל: 2 , לתשלום: 45 | פריטים בסל: 2 , לתשלום: 57 |
| לחיצה על לחם | פריטים בסל: 3 , לתשלום: 12 | פריטים בסל: 3 , לתשלום: 69 |
| לחיצה על עוגה | פריטים בסל: 4 , לתשלום: 45 | פריטים בסל: 4 , לתשלום: 114 |
טעות נפוצה: להוסיף if (!IsPostBack) סביב האתחול של total – זה לא עוזר, כי השדה מאותחל ל-0 בכל יצירה של אובייקט הדף, לא ב-Page_Load.
public void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
Session["items"] = 0;
Session["total"] = 0;
}
}
void Bread_Click(object sender, EventArgs e)
{
Session["total"] = (int)Session["total"] + 12;
Session["items"] = (int)Session["items"] + 1;
}
void Cake_Click(object sender, EventArgs e)
{
Session["total"] = (int)Session["total"] + 45;
Session["items"] = (int)Session["items"] + 1;
}פרק שלישי
ענו על שאלה אחת מן השאלות 9-8.
שאלה 8 · הוספת רץ למרוץ בעזרת DataSet
באתר של מרוץ הלילה העירוני נרשמים רצים למרוץ. בטופס ההרשמה ממלא הרץ את שמו, בוחר את אורך המקצה ומקליד את עיר המגורים שלו:
<input type="text" name="runner" id="runner" />
<select name="dist" id="dist">
<option value="5">5 ק"מ</option>
<option value="10">10 ק"מ</option>
<option value="21">21 ק"מ</option>
</select>
<input type="text" name="city" id="city" />בבסיס הנתונים קיימת טבלה בשם runners ובה שלוש עמודות:
דוגמה לטבלה:
| fullName | distance | city |
|---|---|---|
| Maya Levi | 10 | Haifa |
| Avi Cohen | 21 | Eilat |
לפניכם קטע קוד חלקי תקין של פעולה בשם AddRunner, המוסיפה לטבלה את הרץ שנרשם בטופס. השלימו את הקוד החסר.
protected void AddRunner(string connectionString)
{
SqlConnection connection = new SqlConnection(connectionString);
SqlCommand command = new SqlCommand();
command.CommandText = "Select * From runners";
command.Connection = connection;
connection.Open();
SqlDataAdapter adapter = new SqlDataAdapter(command);
SqlCommandBuilder builder = new SqlCommandBuilder(adapter);
DataSet ds = new DataSet();
adapter.Fill(ds);
string runner = Request.Form["runner"];
string dist = Request.Form["dist"];
string city = Request.Form["city"];
************************************
************************************
adapter.Update(ds);
connection.Close();
}יש להשלים את הקוד החסר (מסומן בכוכביות).
יש להשלים את הקוד החסר (מסומן בכוכביות).
◂ פתרון מלא לשאלה 8
פתרון
DataRow row = ds.Tables[0].NewRow();
row["fullName"] = runner;
row["distance"] = int.Parse(dist);
row["city"] = city;
ds.Tables[0].Rows.Add(row);מה נדרש: להשלים את הקוד כך שהרץ החדש (השם, אורך המקצה והעיר שהגיעו מהטופס) יתווסף כשורה לטבלה runners.
רעיון: הקוד הנתון כבר התחבר למסד, ביצע Select * From runners, מילא את ה-DataSet (adapter.Fill(ds) – הטבלה נמצאת ב-ds.Tables[0]), יצר SqlCommandBuilder (שבונה עבור ה-adapter את פקודת ההוספה) וקרא את שלושת השדות מהטופס. adapter.Update(ds) בסוף שולח למסד את השינויים שנעשו ב-DataSet. לכן חסר רק להוסיף לטבלה שב-DataSet שורה חדשה:
ds.Tables[0].NewRow().Request.Form הוא מחרוזת, אבל העמודה distance היא מסוג מספר שלם – לכן ממירים: int.Parse(dist).ds.Tables[0].Rows.Add(row).פתרון – הקוד החסר (במקום הכוכביות):
DataRow row = ds.Tables[0].NewRow();
row["fullName"] = runner;
row["distance"] = int.Parse(dist);
row["city"] = city;
ds.Tables[0].Rows.Add(row);הפעולה המלאה – בלשונית C#.
בדיקה: טבלה עם השורות Maya Levi 10 Haifa ו-Avi Cohen 21 Eilat, כשהטופס שולח runner=Tamar Golan, dist=5, city=Ashdod. אחרי הקריאה בטבלה 3 שורות, והשורה החדשה היא Tamar Golan | 5 | Ashdod, כשהערך 5 נשמר כמספר שלם (Int32).
טעות נפוצה: לכתוב row["distance"] = dist; בלי המרה – מכניסים מחרוזת לעמודה מספרית. או ליצור שורה ב-NewRow() ולשכוח Rows.Add(row) – אז השורה לא שייכת לטבלה ו-Update לא ישמור אותה.
כתיבה מקוצרת: אפשר להוסיף את השורה גם בפקודה אחת, לפי סדר העמודות: ds.Tables[0].Rows.Add(runner, int.Parse(dist), city);
protected void AddRunner(string connectionString)
{
SqlConnection connection = new SqlConnection(connectionString);
SqlCommand command = new SqlCommand();
command.CommandText = "Select * From runners";
command.Connection = connection;
connection.Open();
SqlDataAdapter adapter = new SqlDataAdapter(command);
SqlCommandBuilder builder = new SqlCommandBuilder(adapter);
DataSet ds = new DataSet();
adapter.Fill(ds);
string runner = Request.Form["runner"];
string dist = Request.Form["dist"];
string city = Request.Form["city"];
// ---- הקוד החסר ----
DataRow row = ds.Tables[0].NewRow();
row["fullName"] = runner;
row["distance"] = int.Parse(dist);
row["city"] = city;
ds.Tables[0].Rows.Add(row);
// --------------------
adapter.Update(ds);
connection.Close();
}שאלה 9 · השלמת פעולה המציגה מתכונים ממסד הנתונים
באתר מתכונים יש במסד הנתונים טבלה בשם RecipesTable ובה ארבע עמודות: name (שם המתכון, טקסט), category (סוג המנה, טקסט), minutes (זמן ההכנה בדקות, מספר שלם) ו־calories (קלוריות למנה, מספר שלם).
דוגמה לטבלה:
| name | category | minutes | calories |
|---|---|---|---|
| עוגת שוקולד | קינוח | 60 | 450 |
| סלט ירקות | סלט | 15 | 120 |
| מוס פירות | קינוח | 20 | 180 |
| פשטידת תרד | מאפה | 35 | 320 |
| כדורי תמרים | קינוח | 40 | 150 |
| סלט פירות | קינוח | 10 | 90 |
עורכת האתר מעוניינת להציג טבלה של "קינוחים מהירים": כל המתכונים שסוג המנה שלהם הוא קינוח וזמן ההכנה שלהם קצר מ־40 דקות (לא כולל). הפעולה showQuickDesserts מקבלת מחרוזת התחברות למסד הנתונים connectionString, ומציגה בטבלה את שם המתכון, זמן ההכנה ומספר הקלוריות של המתכונים המתאימים.
בפעולה חסרים שמונה ביטויים המסומנים במספרים בין סוגריים עגולים. כתבו במחברת הבחינה את מספרי הביטויים החסרים (1) – (8), בסדר עולה, וכתבו ליד כל מספר את הביטוי החסר שהוא מייצג.
protected void showQuickDesserts(string connectionString)
{
string resultStr = "";
DataSet ds = _____(1)_____;
SqlConnection connection = new SqlConnection(connectionString);
SqlCommand cmd = new SqlCommand();
cmd.CommandText = "SELECT * FROM RecipesTable WHERE _____(2)_____";
cmd._____(3)_____ = connection;
connection._____(4)_____;
SqlDataAdapter adapter = new SqlDataAdapter(cmd);
adapter.Fill(ds);
connection.Close();
resultStr += "<table border='1'><tr><th>שם המתכון</th><th>זמן הכנה</th><th>קלוריות</th></tr>";
foreach (DataRow dr in _____(5)_____)
{
resultStr += "<tr>";
resultStr += "<td>" + _____(6)_____ + "</td>";
resultStr += "<td>" + dr["minutes"] + "</td>";
resultStr += "<td>" + dr["calories"] + "</td>";
resultStr += "_____(7)_____";
}
resultStr += "</table>";
Response._____(8)_____(resultStr);
}כתבו במחברת הבחינה את מספרי הביטויים החסרים (1) – (8), בסדר עולה, וכתבו ליד כל מספר את הביטוי החסר שהוא מייצג.
◂ פתרון מלא לשאלה 9
פתרון
(1) new DataSet()
(2) category = 'קינוח' AND minutes < 40
(3) Connection
(4) Open()
(5) ds.Tables[0].Rows
(6) dr["name"]
(7) </tr>
(8) Write
מה נדרש – להשלים 8 ביטויים חסרים בפעולה שמתחברת למסד הנתונים, שולפת את השורות המתאימות ומציגה אותן בטבלת HTML.
רעיון – התבנית הקבועה של קריאה ממסד נתונים ב־ASP.NET:
יצירת DataSet → חיבור (SqlConnection עם מחרוזת ההתחברות) → פקודה (SqlCommand עם טקסט השאילתה והחיבור) → פתיחת החיבור → SqlDataAdapter שמקבל את הפקודה וממלא (Fill) את ה־DataSet → סגירת החיבור → מעבר על השורות של ds.Tables[0] ובניית מחרוזת HTML: שורה <tr>...</tr> לכל רשומה ותא <td>...</td> לכל ערך → שליחה לדפדפן עם Response.Write.
פתרון
| מספר | הביטוי החסר | הסבר |
|---|---|---|
| (1) | new DataSet() | יצירת אובייקט DataSet חדש שיכיל את תוצאות השאילתה |
| (2) | category = 'קינוח' AND minutes < 40 | שני התנאים יחד ⇒ AND; טקסט בין גרשיים בודדים; "לא כולל" ⇒ < |
| (3) | Connection | התכונה של הפקודה שמקשרת אותה לחיבור |
| (4) | Open() | פתיחת החיבור לפני הרצת השאילתה (עם סוגריים – זו קריאה לפעולה) |
| (5) | ds.Tables[0].Rows | אוסף השורות של הטבלה הראשונה ב־DataSet |
| (6) | dr["name"] | שם המתכון מהשורה הנוכחית (העמודה name) |
| (7) | </tr> | סגירת השורה של הטבלה בסוף כל איטרציה |
| (8) | Write | Response.Write שולחת את מחרוזת ה־HTML לדפדפן |
הפעולה המלאה אחרי ההשלמה:
protected void showQuickDesserts(string connectionString)
{
string resultStr = "";
DataSet ds = new DataSet();
SqlConnection connection = new SqlConnection(connectionString);
SqlCommand cmd = new SqlCommand();
cmd.CommandText = "SELECT * FROM RecipesTable WHERE category = 'קינוח' AND minutes < 40";
cmd.Connection = connection;
connection.Open();
SqlDataAdapter adapter = new SqlDataAdapter(cmd);
adapter.Fill(ds);
connection.Close();
resultStr += "<table border='1'><tr><th>שם המתכון</th><th>זמן הכנה</th><th>קלוריות</th></tr>";
foreach (DataRow dr in ds.Tables[0].Rows)
{
resultStr += "<tr>";
resultStr += "<td>" + dr["name"] + "</td>";
resultStr += "<td>" + dr["minutes"] + "</td>";
resultStr += "<td>" + dr["calories"] + "</td>";
resultStr += "</tr>";
}
resultStr += "</table>";
Response.Write(resultStr);
}בדיקה – הפעולה המלאה על נתוני הטבלה מהשאלה. השורות שהוצגו:
| name | minutes | calories |
|---|---|---|
| מוס פירות | 20 | 180 |
| סלט פירות | 10 | 90 |
עוגת שוקולד (60 דקות) וכדורי תמרים (40 דקות בדיוק – "לא כולל") נפסלים בגלל זמן ההכנה; סלט ירקות ופשטידת תרד אינם קינוחים.
טעות נפוצה: ב־(2) לכתוב minutes <= 40 (אז יוצגו גם כדורי תמרים) או OR במקום AND (אז יוצגו כל הקינוחים, וגם סלט ירקות ופשטידת תרד). ב־(5) לכתוב ds.Rows – ל־DataSet אין Rows, רק לטבלה שבתוכו. ב־(4) לכתוב Open בלי סוגריים.
protected void showQuickDesserts(string connectionString)
{
string resultStr = "";
DataSet ds = new DataSet();
SqlConnection connection = new SqlConnection(connectionString);
SqlCommand cmd = new SqlCommand();
cmd.CommandText = "SELECT * FROM RecipesTable WHERE category = 'קינוח' AND minutes < 40";
cmd.Connection = connection;
connection.Open();
SqlDataAdapter adapter = new SqlDataAdapter(cmd);
adapter.Fill(ds);
connection.Close();
resultStr += "<table border='1'><tr><th>שם המתכון</th><th>זמן הכנה</th><th>קלוריות</th></tr>";
foreach (DataRow dr in ds.Tables[0].Rows)
{
resultStr += "<tr>";
resultStr += "<td>" + dr["name"] + "</td>";
resultStr += "<td>" + dr["minutes"] + "</td>";
resultStr += "<td>" + dr["calories"] + "</td>";
resultStr += "</tr>";
}
resultStr += "</table>";
Response.Write(resultStr);
}טבלת התשובות
| שאלה | סעיף | תשובה |
|---|---|---|
| 1 | - | ב. השרת שולח לדפדפן הוראה לעבור לדף menu.aspx, והדפדפן שולח לשרת בקשה חדשה לדף זה |
| 2 | - | ד. |
| 3 | - | טבלה עם מסגרת, שורה אחת ו־7 תאים, משמאל לימין: 7, 60, 5, Tik, 3, 20, 1 |
| 4 | א | c |
| ב | עוטפים את הכיתוב בתגית קישור עם כתובת יחסית: | |
| 5 | - | (1) new DataSet() |
| 6 | - | return CountDigits(num1) == CountDigits(num2) && SumDigits(num1) == SumDigits(num2); (שתי פעולות עזר: ספירת ספרות וסכום ספרות בלולאת while (num > 0) עם % 10 ו-/ 10) |
| 7 | - | הסכום נשמר בשדה של הדף (public int total = 0). בכל לחיצה (postback) נוצר אובייקט דף חדש ו-total מתחיל מ-0, ולכן מוצג רק מחיר הפריט האחרון (12 או 45). התיקון: לשמור את הסכום ב-Session – לאתחל Session["total"] = 0 בתוך if (!IsPostBack), בכל לחיצה Session["total"] = (int)Session["total"] + מחיר, ולהציג <% =Session["total"] %>. |
| 8 | - | C# |
| 9 | - | (1) new DataSet() |