הצגת כתובת של מערך

זהיר

New member
אבל יש הבדל

http://www.eskimo.com/~scs/C-faq/s6.html http://www.eskimo.com/~scs/C-faq/q6.20.html
 

voguemaster

New member
כן, אני מודע לזה ../images/Emo13.gif

אבל תודה על הלינק, 6.18 זה בדיוק הדבר המתאים.
 

voguemaster

New member
והנה הסוגיה בעצם

אם לדוגמא יש לנו פונקציה שצריכה לקבל מערך דו מימדי בגודל משתנה (כלומר מצביע למצביע), איך נעביר לה מערך שהוגדר כמערך בעצם ? כלומר:
void f( float **mat, int n); typedef float[4][4] matrix; matrix m; f( m, 4); // this generates a warning​
מה הפיתרון בעצם ? אז נכון שאפשר להעביר מערך של מערכים אבל בדוגמא הזו כשיש טיפוס מוגדר מסוג מערך דו מימדי, מה הפיתרון הכי נכון ?
 

eyalbd

New member
עדיף לא לעבוד עם מערכים רב-מימדיים

אם אתה רוצה לעבוד עם מטריצות. עדיף לך ליצור struct (זה C לא?) שמייצג את המטריצה משהו כמו (לא בדוק)
struct MyMatrix { int rows; int cols; float* data; }; typedef struct MyMatrix* Matrix; // Allocate and Free // Matrix alloc_matrix(int row, int col); void free_matrix(Matrix m); // Element access // #define MVALUE(mat, r, c) (*((mat)->data + (r) * (mat)->col + (c))) THEN: int main() { Matrix m = alloc_matrix(4, 4); MVALUE(m, 0, 0) = 5.0; MVALUE(m, 0, 1) = 7.0; call_matrix_function(m); }​
 

voguemaster

New member
אתה בהחלט צודק

אבל הדוגמא שנתתי מתייחסת לעבודה עם מטריצות. אומנם אם הייתי כותב תוכנית שבה היה לי חופש מוחלט ליצור לעצמי טיפוס מטריצה הייתי עובד או עם מערך רציף או עם מערך של מערכים אבל לפעמים יש אילוצים. לדוגמא, D3D מגדיר את טיפוס המטריצה שלו בתור מערך דו מימדי של float (לפחות באחת הצורות, יש עוד צורה). ד"א, אם עובדים רציף עדיף עדיין לעבוד עם מערך של מערכים. יש דוגמא לזה ב-C FAQ שזהיר הביא: הם משתמשים באריתמטיקה של פוינטרים כדי לאתחל אותם למקומות הנכונים בתוך המערך הרציף. נו שוין
 

זהיר

New member
לא להכנס לצרה

לפי תשובה 6.19 שם (הפנייה מתשובה 6.20) אין דרך לבצע זאת ולהישאר בSTRICT CONFORMANCE עם הסטנדרד. לדעתי, צריך לקבל את העובדה שבשפת C אין גמישות בהעברת מערכים ממימד > 1 לפונקציות: חייבים לספק מספר מימדים וגודל כל אחד (חוץ מהראשון). למעשה זה נובע מכך שבשפת C יש רק מערכים ממימד 1 וכל השאר זה "סימולציה". לכן דוגמה כמו שנתת (מערך ספציפי שנשלח לפונקציה כללית) מרמז על שימוש לא נכון בשפה. אינטואיטיבית, בשביל גישה מהירה אתה רוצה מערך שהוא יחידה אחת, ואז הדבר הנכון הוא לבצע הקצאה דינמית כאילו מערך חד-מימדי (ובמקרים יוצאי דופן מערך חד-מימדי על המחסנית - [ INT A[4*4 בדוגמה שלך). אבל עם ביצועי CACHE וחישוב ספקולטיבי של המעבדים היום, לא ברור שמערך של מצביעים עבור מערכים יהיה איטי יותר. תכנתו בזהירות
 

voguemaster

New member
יש שם דוגמא

ליצירה של מערך של מערכים (או יותר נכון מערך של מצביעים
) ששם הם מאתחלים ידנית את המערך של המצביעים שיצביעו לתוך הבאפר הרציף שהם הקצו. נראה לי כמו הפיתרון הכי טוב..
 

annefan

New member
זו לא סיבה

על מנת שתוכנית תהיה STRICT CONFORMANT, מותר לך להשתמש אך ורק בשפה ובספריה הסטנדרטית שלה כפי שהן מופיעות בתקן. כמובן, שאסור להגיע ל-Undefined behavior, Unspecified Behaviour או Implementation Defined behaviour, אבל ההגבלה הראשונה היא הקשה ביותר. אסור לך להכליל שום header שקשור למערכת ההפעלה, להשתמש באיזו ספריה שמשתמשת בעצמה בפונקציות חיצוניות לתקן וכו'.
 

זהיר

New member
רק להדפסת הכתובת לא משנה

הטיפוסים של כל אחד מבין
a, &a, &a[0]​
הם שונים: ARRAY OF INT OF A CERTAIN SIZE POINTER TO ARRAY OF INT OF A CERTAIN SIZE A POINTER TO INT תכנתו בזהירות
 

Fingertip

New member
גם אני רוצה../images/Emo70.gif

מערך הוא אוסף של תאי זכרון צמודים. לפיכך, בתנאי שיש לנו אוסף תאי זכרון כזה, אפשר לתאר מערך בצורה הבאה: [A[i הוא הכתובת בזכרון של תחילת המערך ועוד i*גודל תא בזכרון. מכיוון ש(לגמרי במקרה
) אם p הוא מצביע לתא בזכרון מסוג מסויים, אז: p+i היא בדיוק הכתובת של התא שנמצא i תאי זכרון מאותו הסוג אחריו. אמחיש באמצעות דוגמה: טיפוס התא הוא int בגודל 3 בתים. הכתובת עליה מצביע p היא 500 והיא בדיוק הכתובת בה מתחיל המערך A של תאים מסוג int. הכתובות מרווחות לפי בתים. לפיכך:
p+2 = 506 A[2] = *506 (506 כלומר, הערך שנמצא בתא)​
כלומר, אין הבדל ממשי בין [A[2 לבין (p+2)*. ב-C אין הבדל כלל בין:[A[2 לבין (A + 2)*. יתר על כן, [a[b בתורגם בדיוק להיות:
*(a+b)​
ולכן כל הביטויים הבאים שקולים:
a == *(a + i) == *(i + a) == i[a]

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

gmorphus

New member
לא נראה לי

אלא אם יש משהו שאני מפספס הביטוי הזה לא ברור ואני לא חושב שהוא נכון...
 

Fingertip

New member
בטוח.

מתוך הספר "The C Programming Language" (שנכתב על ידי הבחור החביב שהמציא את C):
"Rather more surprising, at least at first sight, is the fact that a reference to a can also be written as *(a+i). In evaluation a, C converts it to *(a+i) immediately; the two forms are equivalent. Applying the operator & to both parts of this equivalence, it follows that $(a and a+i are also identical: a+i is the address of the i-th element beyond a. As the other side of this coin, if pa is a pointer, expressions may use it with a subscript; pa is identical to *(pa + i). In short, an array-and-index expression is equivalent to one written as a pointer and offset. [...] The array subscripting operation is defined so that E1[E2] is identical to *(E1+E2). Therefore, despite its asymmetric appearance, subscripting is a commutative operation." (The C Programming Language by Brian Kernighan and Dennis Ritchie, 2nd Ed., p. 99, 217)

כמובן שמומלץ לנסות ולבדוק... אהד.
 
למעלה