כיצד ליצור מצביעים ב- C?

תמיד אתחל את המצביעים לפני השימוש בהם, שכן מצביעים 'פרועים' מצביעים על כתובות אקראיות, והגישה אליהם תקרוס את התוכנית שלך.
מצביעים הם הסיוט של כל מתכנת C חדש. עם זאת, הם גם התכונה שהפכה את C לשפת התכנות הנרחבת והחזקה שהיא עד היום. כמו תכונות ותכניות תכנות רבות אחרות, יש גישה שיטתית ליצירת ושימוש במצבי C. מאמר זה הוא מדריך צעד אחר צעד ליצירה ושימוש במצבעים בצורה ברורה וקלה.
- מצביעים הם משתנים המחזיקים את הכתובת של מיקום זיכרון באופן כללי (מיקום זיכרון זה יכול להכיל את נתוני המשתנה או עדיין לא הוקצה).
- הפניות הן משתנים המחזיקים את כתובת הזיכרון של משתנה אחר.
- ההבדל העיקרי בין הפניה למצביע הוא שהפניות מצביעות על מיקומי זיכרון שהוקצו ואילו מצביעים יכולים להצביע על מיקומי זיכרון שלא הוקצו.
- קיים הבדל בין מפעיל הכתובת (המשמש למשתנים להחזרת כתובתם בזיכרון), למפעיל הצהרת ההתייחסות (המשמש בהצהרת התייחסות כדי לציין שהמשתנה המוצהר הוא הפניה) לבין המפעיל קצת "ו", לכולם אותו סמל (&)
- ניתן להגדיל ולהוריד מצביעים (מה שמאפשר לשנות את המיקום אליו מצביע המצביע).
- ניתן להקצות מצביעים בכל אחת מהשיטות הבאות:
- הקצאת הפניה למצביע מה שהופך את המצביע לאותו מיקום בזיכרון כמו ההפניה.
- הקצאת כל מצביע אחר מאותו סוג למצביע מה שגורם לשתי המצביעים להצביע על אותו מיקום.
- הקצאת ערך ספרתי למצביע (בפורמט הקסדצימלי) גורמת למצביע להצביע על מיקום הזיכרון הספציפי שמופנה באותה ספרה.
- הקצאת הכתובת של משתנה מסוג המצביע למצביע מה שהופך את המצביע למצב הזיכרון של הבייט הראשון של הייצוג הבינארי של המשתנה בזיכרון.
- ניתן להקצות הפניות באמצעות אחת מהשיטות הבאות:
- הקצאת התייחסות נוספת להפניה.
- הקצאת משתנה מאותו סוג כמו ההפניה תהפוך את נקודת הייחוס למשתנה.
- למצביעים ולהפניות יש סוגי נתונים, המציינים את סוג הנתונים שמצביע / הפניה מצביע עליהם.
- סוג ההפניה מגביל את ההקצאה של אותה התייחסות למשתנים / הפניות מאותו סוג נתונים. לדוגמא, אם אנו מצהירים על הפניה למספר שלם (int & d;), נוכל להקצות רק הפניה למספר שלם אחר או משתנה שלם להפניה (int i = 0; d = i;)
- סוג המצביע מגביל את הקצאת המצביע להפניות, כתובות של משתנים / מצביעים מאותו סוג הנתונים. זה משפיע גם על אחזור הנתונים שמצביעים עליהם כך שמצביע שלם ישיג מספר בתים השווים למספר הבתים שנלקחו על ידי מספר שלם במערכת. כמו כן, בחירת סוג הנתונים משפיעה על האופן בו מגדילים ומורידים מצביעים. כאשר מצביע מוגבר, הוא מצביע על הערך הבא של סוג הנתונים מהמיקום הנוכחי. לדוגמא, אם ערך שלם לוקח 4 בתים בזיכרון, הגדלת מצביע שלם, יגרום לו להצביע על המספר השלם הבא, שהוא 4 בתים אחרי המיקום הנוכחי ולכן הערך של המצביע עצמו גדל בכפולות של 4.
- שמות משתני מערך נחשבים למצביעים סטטיים / קבועים המצביעים על הבייט הראשון של הפריט הראשון במערך ובעל אותו סוג כמו פריטי המערך.

כיצד מיוצגות מצביעי פונקציות ב- C?
- 1החליטו את סוג המצביע (כלומר, סוג הנתונים שהמצביע יצביע עליהם). הטיפים הבאים עשויים לעזור:
- אם אתה מצהיר על מערך דינמי, השתמש בסוג הנתונים של פריטי המערך.
- אם אתה מצהיר על המצביע לגשת לנתונים של משתנה, השתמש באותו סוג נתונים כמו המשתנה.
- אם אתה מצהיר על המצביע לחצות מבנה רשימה, השתמש בסוג הנתונים של צומת הרשימה (בדרך כלל משתמש שיצר מבנה).
- אם אתה מצהיר על כך שהמצביע יעבור על עץ, השתמש בסוג הנתונים של צומת העץ, או עם מצביע לסוג צומת העץ כסוג (מצביע לסמן צומת עץ!).
- 2הכריזו על המצביע באמצעות תחביר כך: מזהה מצביע נתונים מסוג *; איפה
- סוג נתונים הוא הסוג שהחלטת בשלב 1
- מזהה מצביע הוא המזהה או השם של משתנה המצביע
- 3הקצה את המצביע למיקום זיכרון ראשוני. ניתן לעשות זאת באמצעות אחת מהשיטות הבאות:
- הקצאת זיכרון והצביעה עליו באמצעות המצביע: int * i = malloc (sizeof (int) * n); כאשר n הוא מספר חסימות הזיכרון שיש להקצות.
- הקצאת כתובת המשתנה למצביע: int * i = & x; כאשר "x" הוא מספר שלם ו- (&) פירושו כתובת של.
- הקצאת מזהה מערך למצביע: int * i = array1; כאשר מערך 1 הוא מערך שלם (int [] מערך 1;).
- הקצאת הפניה למצביע: int * i = a; כאשר "a" הוא הפניה למספר שלם (int & a;).
- הקצאת מצביע אחר למצביע: int * i = z; כאשר "z" הוא מצביע שלם אחר (int * z;)
- 4בכל פעם שאתה צריך לחלץ את פריט הנתונים שמצביע עליו מצביע כרגע, השתמש במפעיל ערך בכתובת (*): int x = * i; כאשר אני הוא מצביע שלם.
- 5השתמש במפעיל האינדקס על המצביע כאילו היה מערך בכל פעם שתרצה להשיג מיקום זיכרון ליד המצביע מבלי לקדם את המצביע בפועל. לדוגמא, אם יש לכם מצביע שלם i, תוכלו להשתמש ב- i [2] שיאחזר את המספר השלם שאחרי המספר השלם מיד אחרי המספר השלם אליו הצביע ההפניה (המספר השלם שנמצא 2 מספרים שלמים אחרי המיקום הנוכחי). המצביע i עדיין יצביע על אותו מיקום זיכרון. חלופה נוספת לכך היא קבלת הערך במצביע 2 שלבים אחרי המצביע הזה: * (i + 2)
- 6השתמש במפעילי התוספת (++), הקטנה (-), + = ו- - = בכל פעם שאתה צריך לשנות את המיקום הנוכחי. i + = 5; יקדם את מצביע השלמים i 5 מספרים שלמים קדימה.
- 7לאחר שסיימת באמצעות המצביע, אם אתה מוקצה זיכרון מצביע כי, להפוך בטוח שאתה לשחרר את הזיכרון שהוקצה באמצעות חופשית (הפונקציה). (חינם (i); איפה אני מצביע)

הקצאת כל מצביע אחר מאותו סוג למצביע מה שגורם לשתי המצביעים להצביע על אותו מיקום.
- אם יש לך מבנה שהקצית באמצעות malloc (), המחזיר מצביע למבנה, הפניות לחברי המבנה שהוקצה נעשות באמצעות האופרטור ->. בהנחה שמבנה s1 שוב, ו- s הוכרז כמצביע לסוג מבנה זה, הדברים הבאים יקצו את כתובת המשתנה ויתייחסו למשתנה בהתאמה: s-> c = & j; k = * s-> ג. יש מתכנתים שבוחרים לכתוב * (s-> c) לשם הבהרה, אם כי אין צורך בכך.
- הסתכל לתוך אספן האשפה של בוהם. לאחר ההתקנה, תוכל להשתמש בו על ידי הכללת gc.h והחלפת malloc () ב- gc_malloc (). שימוש בקולט אשפה מפחית באגים בזיכרון, אך בהתאם לתוכנית עשוי להגדיל או להקטין את הביצועים.
- שקול להשתמש בכלי ניפוי באגים כגון valgrind (לינוקס) שיכולים לעזור בזיהוי דליפות זיכרון, ובאיתור השימוש במצביעים לנתונים "מחוץ לתחום".
- בדרך כלל עדיף לשמור על מצביע שמצביע על כל זיכרון שתקצה כדי שתוכל לשחרר אותו מאוחר יותר.
- זה נוהג טוב לתכנות לבדוק אם malloc () הצליח להקצות את נתח הזיכרון המתאים על ידי בדיקה אם המצביע שהוחזר אינו שווה ל- NULL או 0.

כמו תכונות ותכניות תכנות רבות אחרות, יש גישה שיטתית ליצירת ושימוש במצבי C.
- השימוש במפעיל האינדקס על מצביעים עלול להיות מסוכן מכיוון שאתה עלול לנסות לגשת למיקומים בזיכרון שאינם מורשים או לקבל ערכי מיקום זיכרון שלא הוקצו.
- אל תשכח לפנות כל זיכרון שהקצית באמצעות malloc (). כישלון לעשות זאת עלול לגרום לקריסות, הצפת זיכרון ובעיות אחרות בתוכנית שלך.
- אל תקצה מיקום זיכרון ישיר (לפי כתובת) למצביע אלא אם כן אתה באמת צריך.
- תמיד אתחל את המצביעים לפני השימוש בהם, שכן מצביעים 'פרועים' מצביעים על כתובות אקראיות, והגישה אליהם תקרוס את התוכנית שלך.
קרא גם: כיצד לחשב הון חוזר?
שאלות ותשובות
- כיצד מיוצגות מצביעי פונקציות ב- C?הם מיוצגים באמצעות משתנה מסוג (return_type (* variable_name)) (param1_type, param2_type) בקוד C. הם מתנהגים כמו כל מצביע אחר, אלא שאפשר לקרוא להם.