מצביע לעומת ערך
חלק מהיחידה תכנות מונחה עצמים במסלול ה-C של Coddy. שיעור 9 מתוך 61.
כשמעבירים struct לפונקציה, C נותנת לך שתי אפשרויות: להעביר אותו לפי ערך (להעתיק את כל ה־struct) או להעביר אותו באמצעות מצביע (להעתיק רק את הכתובת). לבחירה יש השפעה משמעותית על הביצועים.
העברה לפי ערך יוצרת עותק מלא של המבנה במחסנית. עבור מבנה קטן עם כמה מספרים שלמים, זה בסדר. אבל דמיינו מבנה בגודל מאות בתים: כל קריאה לפונקציה מעתיקה את כל הנתונים האלה:
typedef struct {
char name[100];
int scores[50];
double average;
} Student;
// לפי ערך: מעתיק ~308 בתים בכל קריאה
void print_by_value(Student s) {
printf("%s: %.2f\n", s.name, s.average);
}
// באמצעות מצביע: מעתיק רק 8 בתים (הכתובת)
void print_by_pointer(const Student *s) {
printf("%s: %.2f\n", s->name, s->average);
}
גם התחביר שונה. עם פרמטר מסוג ערך, משתמשים באופרטור הנקודה (s.name). עם מצביע, משתמשים באופרטור החץ (s->name).
גרסת המצביע יעילה יותר משום שהיא מעבירה רק כתובת זיכרון, בדרך כלל 8 בתים ללא קשר לגודל המבנה.
זו הסיבה שמתכנתי C כמעט תמיד מעבירים מבנים באמצעות מצביע. השתמשו ב־const כשהפונקציה לא אמורה לשנות את הנתונים, ובמצביע רגיל כשהיא אמורה לעשות זאת. כך מקבלים גם יעילות וגם כוונה ברורה.
אתגר
קלבוא נבנה מודול Product שמדגים את ההבדל בין העברת מבנים לפי ערך לבין העברתם באמצעות מצביע. תיצור שתי פונקציות תצוגה: אחת שמקבלת את המבנה כולו כעותק, ואחת שמקבלת רק מצביע אליו.
תיצור שלושה קבצים:
product.h: הכרז על מבנהProductעם שלושה איברים:char name[50],double priceו-int quantity. הכרז גם על שתי פונקציות:display_by_value: מקבלתProductלפי ערך ומדפיסה את המידע שלוdisplay_by_pointer: מקבלתconst Product *ומדפיסה את אותו מידע
PRODUCT_H.product.c: ממש את שתי הפונקציות. שים לב להבדל בתחביר: הגרסה שמעבירה לפי ערך משתמשת באופרטור נקודה (p.name), ואילו גרסת המצביע משתמשת באופרטור חץ (p->name). שתי הפונקציות צריכות להדפיס באותו פורמט.main.c: צור Product, ואז קרא לשתי פונקציות התצוגה כדי להראות שהן מפיקות פלט זהה, אף שהן משתמשות בסגנונות שונים של פרמטרים.
תקבל שלושה קלטים: שם המוצר (מחרוזת), המחיר (double) ו-הכמות (מספר שלם).
בקובץ הראשי, אתחל Product עם הערכים האלה, ואז קרא ל-display_by_value ואחריו ל-display_by_pointer.
שתי הפונקציות צריכות להדפיס בפורמט הזה:
Product: {name}, Price: {price}, Qty: {quantity}השתמש ב-%.2f עבור המחיר כדי להציג שתי ספרות אחרי הנקודה העשרונית.
לדוגמה, עבור הקלטים Laptop, 999.99 ו-5, הפלט יהיה:
Product: Laptop, Price: 999.99, Qty: 5
Product: Laptop, Price: 999.99, Qty: 5נסו בעצמכם
#include <stdio.h>
#include <string.h>
#include "product.h"
int main() {
char name[50];
double price;
int quantity;
// קראו את נתוני הקלט
scanf("%s", name);
scanf("%lf", &price);
scanf("%d", &quantity);
// TODO: צרו משתנה מסוג Product ואתחלו אותו בערכי הקלט
// רמז: השתמשו ב-strcpy כדי להעתיק את השם לשדה name של ה-struct
// TODO: קראו ל-display_by_value עם ה-Product
// TODO: קראו ל-display_by_pointer עם מצביע ל-Product
return 0;
}
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה תכנות מונחה עצמים
4כימוס
המושג של מצביעים אטומיםהגדרת מבנים אטומיםפונקציות Get ו-Setאימות ב-Settersסיכום: הקופסה הסודית2אובייקטים ומתודות
מבנים כאובייקטיםמצביע 'Self'נכונות constמצביע לעומת ערךמתודות עזרחזרה: מנהל נקודות5פרויקט: חשבון בנק פשוט
הגדרת הפרויקטמימוש החשבוןתרגלו בעצמכם: קומפיילר C אונליין