C/C++ מדריכי
C הקדמה לתכנות ב
C++ הקדמה להיררכית מחלקות ב הצגה מזורזת :C++ הבנת דף הבית

שיעור 12: שימוש במצביעים עם מערכים

מערכים ומצביעים קשורים בצורה הדוקה ב C. כדי להשתמש במערכים בצורה יעילה, אתה חייב לדעת איך להשתמש בהם עם מצביעים. הבנה מלאה של היחסים בין השניים דורשת למידה של מספר שבועות או אפילו חודשים, לכן אל תירתע אם אתה לא מבין את זה מייד.

הבה נתחיל בהתנהגות מערכים בפסקל ושפות אחרות. בתחום זה C אינה דומה כלל לפסקל, כך שהיא תספק ניגוד טוב. להלן דוגמא של מערכים בפסקל:

program samp;  
const    
    max=9;  
var    
    a,b:array[0..max] of integer;    
    i:integer;  
begin    
    for i:=0 to max do      
        a[i]:=i;    
    b:=a;  
end. 

האלמנטים של המערך a מאותחלים, ולאחר מכן כל האלמנטים ב a מועתקים ל b, כך ש a ו b הם זהים. נשווה את גרסת C:

#define MAX 10 
 
void main()  
{    
    int a[MAX];    
    int b[MAX];    
    int i; 
     for(i=0; i<MAX; i++) 
        a[i]=i;   
    b=a;  
} 

הקלד קוד זה ונסה להדר אותו. תמצא ש C לא תהדר אותו. אם אתה רוצה להעתיק את a ל b, תצטרך לכתוב משהו כזה:

for (i=0; i<MAX; i++)      
    a[i]=b[i];

או, באופן תמציתי יותר:

for (i=0; i<MAX; a[i]=b[i], i++);

טוב עוד יותר להשתמש בשירות ה memcpy ב string.h.

מערכים ב C הם לא רגילים בכך שמשתנים a ו b אינם, מבחינה טכנית, מערכים עצמם אלא מצביעים קבועים למערכים. לכן, הם מצביעים לגושי זיכרון שמחזיקים את המערכים. הם מחזיקים את הכתובות של מערכים ממשיים, אבל כיוון שהם מצביעים קבועים, לא ניתן לשנות את הכתובות שלהם. לפיכך הפקודה a=b; לא עובדת.

כיוון ש a ו b הם מצביעים, ניתן לבצע מספר דברים מעניינים עם מצביעים ומערכים. לדוגמא, הקוד הבא פועל:

#define MAX 10 
 
void main()  
{    
    int a[MAX];     
    int b[MAX];    
    int i;    
    int *p,*q; 
     
    for(i=0; i<MAX; i++);  
        a[i]=i;   
    p=a;    
    printf("%d\n",*p);  
} 

הפקודה ;p=a עובדת כיוון ש a הוא מצביע. מבחינה טכנית, a מצביע לכתובת של האלמנט ה 0 במערך עצמו. אלמנט זה הוא מספר שלם, כך ש a הוא מצביע למספר שלם בודד. לכן, הצהרה על p כמצביע למספר שלם וקביעתו כשווה ל a עובדת. דרך אחרת לומר בדיוק את אותו הדבר תהיה להחליף את p=a; ב p=&a[0];. כיוון ש a מכיל את הכתובת של a[0], a ו &a[0] הם בעלי אותה משמעות. כעת כאשר p מצביע לאלמנט ה 0 של a, ניתן לעשות דברים מוזרים למדי אתו. המשתנה a הוא מצביע קבוע ולא יכול להשתנות, אבל p אינו כפוף להגבלות כאלו. C למעשה מעודדת אותך להזיז אותו תוך שימוש בחשבון מצביעים. לדוגמא, אם תכתוב ;++p, המהדר יודע ש p מצביע למספר שלם, ולכן פקודה זו מעלה את p במספר הבתים המתאים כדי להזיז אותו לאלמנט הבא במערך. אם p היה מצביע למערך של מבנים באורך 100 בתים, ;++p היה מקדם את p ב 100 בתים. C מטפלת בפרטים של גודל האלמנט. ניתן גם להעתיק את המערך a ל b תוך שימוש במצביעים. הקוד הבא יכול להחליף את
(for i=0; i<MAX; a[i]=b[i], i++);:

p=a;    
q=b;    
for (i=0; i<MAX; i++)    
{      
    *q = *p;      
    q++;      
    p++;    
} 

ניתן לקצר את הקוד כך:

p=a;    
q=b;    
for (i=0; i<MAX; i++)     
    *q++ = *p++; 

וניתן לקצר אותו עוד יותר ל:

for (p=a, q=b, i=0; i<MAX; *q++ = *p++, i++);

מה יקרה אם תעבור את הקצה של המערך a או b עם המצביעים p או q? ל C לא אכפת - היא ממשיכה בשמחה להעלות את p ו q, תוך העתקה על משתנים אחרים עם התרת רסן. עליך להיזהר כאשר אתה פונה באמצעות אינדקסים למערכים ב C, כיוון ש C מניחה שאתה יודע מה אתה עושה.

ניתן להעביר מערך כגון a או b לפונקציה בשני אופנים שונים. דמיין לעצמך פונקצית dump שמקבלת מערך של מספרים שלמים כפרמטר ומדפיסה את התוכן של המערך ל stdout. יש שתי דרכים לקודד את dump:

void dump(int a[],int nia)  
{    
    int i;     
     for (i=0; i<nia; i++)      
        printf("%d\n",a[i]);  
}

או:

void dump(int *p,int nia)  
{    
    int i;     
     for (i=0; i<nia; i++)      
        printf("%d\n",*p++);  
}

המשתנה nia (number_in_array) דרוש כדי שהגודל של המערך יהיה ידוע. שים לב שרק מצביע למערך, ולא התוכן של המערך, מועבר לפונקציה. שים לב גם שפונקציות C יכולות לקבל כפרמטרים מערכים בגודל משתנה, דבר שאינו אפשרי בפסקל.




לדף הראשון

<< לדף הקודם

לדף הבא >>