לוגו אתר Fresh          
 
 
  אפשרות תפריט  ראשי     אפשרות תפריט  צ'אט     אפשרות תפריט  מבזקים     אפשרות תפריט  צור קשר     חץ שמאלה ‎print ‎"Hello World!"; if‎ ‎not rules.‎know ‎then rules.‎read(); חץ ימינה  

לך אחורה   לובי הפורומים > מחשבים > תכנות ובניית אתרים
שמור לעצמך קישור לדף זה באתרי שמירת קישורים חברתיים
תגובה
 
כלי אשכול חפש באשכול זה



  #1  
ישן 07-10-2008, 17:09
  משתמש זכר dorM dorM אינו מחובר  
מנהל
 
חבר מתאריך: 26.07.08
הודעות: 6,473
[שפת C] הגדרת NULL, וגם מה קורה כאשרים פונקציה מסוג char מחזירה NULL

שמתי לב ש-NULL מוגדר באופן הבא:

קוד:
#define NULL ((void *)0)


רציתי לדעת למה דווקא ההגדרה הזו, ומהו סוג ה-casting שבוצע על המספר 0 ?
האם זה הופך את NULL למצביע על התא שכתובתו 0, או למצביע שערכו הוא 0 (וכתובתו לא ידועה כביכול) ?

נניח ויש לי את הפונקציה Check_Something הבאה:

קוד:
#define NULL ((void *)0) int main(void) { // code ... if (Check_Something() == NULL) // bla bla... } char Check_Something() { return NULL; }


מה יהיה הערך שיוחזר מהפונקציה Check_Something ?
האם הוא יהיה NULL או שיתבצע עליו casting ל-char (כפי שצפוי) ?
אם יתבצע עליו casting ל-char, מה יהיה ערכו (מה הוא יהיה שווה) ?

נזכרתי בשאלה קטנה נוספת:
האם קיים אופרטור השוואה מסוג כמו:

קוד:
if (num1 === char2)


??

הכוונה היא לאופרטור השוואה שמשווה גם את סוג המשתנה (אם הוא int או char וכו'..)

תודה!
תגובה ללא ציטוט תגובה עם ציטוט חזרה לפורום
  #2  
ישן 07-10-2008, 17:25
  משתמש זכר eXtruct eXtruct אינו מחובר  
 
חבר מתאריך: 27.10.05
הודעות: 1,067
בתגובה להודעה מספר 1 שנכתבה על ידי dorM שמתחילה ב "[שפת C] הגדרת NULL, וגם מה קורה כאשרים פונקציה מסוג char מחזירה NULL"

לגבי NULL פעם ראשונה רואה את הגגדרה הזאתי, עד כמה שידוע לי NULL מוגדר כ 0 או 0L.
מה שקורה פה (בדוגמא שלך) הוא ש NULL פוינטר לכלום, NULL לרוב הערך שמוחזר מפונקציות שמקצות זכרון במקרה של תקלה, כלומר אם אין זיכרון המערך של יצביע ל NULL כלומר לכלום.
אני פשוט מתחייס לזה ככתובת 0 כיוון שלא נראה לי שכתובת 0 קיימת פיזית...

בקשר לפונקציה. לפני הומפילציה יהיה של של preporcessing והקוד שלך יהפוך ל:

#define NULL ((void *)0)

int main(void)
{
// code ...

if (Check_Something() == ((void *)0))
// bla bla...
}

char Check_Something()
{
return ((void *)0);
}


אני מאמין שהערך שיוחזר יהיה 0 או \0 (הכוונה לסוף מחרוזת.)

מה זאת אומרת אופטור שמשווה את סוג המשתנה? אתה מתכוון למשהוא כמו === ב PHP? אם כן אז לא קיים אופרטו כזה עד כמה שידוע לי.

נערך לאחרונה ע"י eXtruct בתאריך 07-10-2008 בשעה 17:28.
תגובה ללא ציטוט תגובה עם ציטוט חזרה לפורום
  #5  
ישן 07-10-2008, 18:34
צלמית המשתמש של maind
  maind maind אינו מחובר  
 
חבר מתאריך: 08.10.02
הודעות: 827
בתגובה להודעה מספר 1 שנכתבה על ידי dorM שמתחילה ב "[שפת C] הגדרת NULL, וגם מה קורה כאשרים פונקציה מסוג char מחזירה NULL"

NULL מוגדר כ0 ב C++,
בC הוא מוגדר כמו שהוא ציין מצביע לכתובת 0.

בפונקציה Check_Something שהראת הקומפילר ימיר את המצביע NULL למספר בין 0 ל 255, המספר לא חייב להיות 0! אך ברוב המערכות הוא כן יהיה ולכן נגיד והייתה משנה את הבדיקה שלך ל
קוד:
if (Check_Something() == 0)

והפונקציה הייתה מחזירה NULL, הביטוי לא היה מתפרש בכל המערכות כנכון.

זה מכיוון שבשפה יש מה שנקרא null pointer זה ערך יחודי למצביע מסוג מסוים (כן יכול להיות שלסוגים שונים הערך הוא שונה) שמסמל שהמצביע מצביע אל כלום, שאין מצב שהוא יצא שווה לערך של מצביע אחר מאותו סוג. והערך הזה לא חייב להיות 0.
אבל כשאתה כותב משהו בסגנון הבא:
קוד:
char *abc = 0

וקומפילר רואה שהצבת 0 בהקשר של מצביע וכבר בזמן קימפול (ורק אז) משנה את הערך לערך ה
null. וככה זה בכל מקרה שבוא הקומפיילר יראה 0 בהקשר של מצביע. ולכן NULL מוגדר כ
קוד:
(void *) 0

הקומפילר רואה 0 בהקשר של מצביע וממיר אותו לערך המיוחד הזה של null.

קצת קוד להמחשה:
קוד:
char *abc, *k = 0, i = 0, p = NULL; abc = 0; //abc points to null (abc is a null pointer) abc = NULL; //abc still points to null abc = k; //abc still points to null abc = p; //abc could be pointing to null abc = i; //abc could be pointing to null


ההצבה הראשונה ל abc תציב בו את הערך המיוחד של null (לא חובה שערך זה הוא 0) מכיוון שהקומפילר מזהה 0 בהקשר של מצביע (abc הוא מצביע) והוא יחליף את ה0 בערך המיוחד.
ההצבה השניה גם כן תציב את הערך המיוחד כפי שנאמר קודם. ההצבה השלישית גם כן תציב את הערך המיוחד מכיוון שהמצביע k גם כן מכיל את הערך המיוחד הזה. ההצבה הרביעית אינה בהכרח תעבוד כמו השאר מכיוון שהערך של null יכול להיות גדול יותר מ255 ולכן הוא לא יכנס במלואו ל p. בעצם ההצבה הרביעית תעבוד רק במקרה שבוא הערך המיוחד הזה קטן מ256 ההצבה האחרונה גם אינה בהכרח תעבוד מכיוון שi הוא לא מצביע, יוצב בו בו הערך 0 ולא הערך של null כי זה לא בהקשר של מצביע ואז הערך (אפס) יוצב ב abc ואם במערכת מצביע לכלום (null) מוגדר כערך שונה מאפס ההצבה לא תעבוד כרצוי.

קוד הבא הוא תקין ויפעל כצפוי - הערך X יודפס:
קוד:
char *do_something() { return 0; } if (do_something() == 0) { if (do_something() == NULL) { if (do_something()) { //Compiler see this as: if (do_something() == 0) printf("X"); } } }


עכשיו נחזור למקרה ההוא:
קוד:
if (Check_Something() == 0)


ונגיד שאתה מריץ אותה במערכת שבה הnull הוא לא 0 אלא 190,
הפונקציה מחזירה NULL אשר שווה למצביע לכתובת 190, אשר מומר ל char ולכן הפונקציה תחזיר
190, הקומפילר רואה השוואה ל0 אבל בהקשר של char ולכן הוא לא ממיר את ה0 לערך של null
והקוד לא יפעל כמתוכנן. אך אם נשנה את הפונקציה כך שתחזיר מצביע הכל יפעל כראוי כי הקומפילר
יחליף את הערך 0 לערך של null מכיוון שזה בהקשר של מצביע.

קצת ארוך יצא, אז מקווה שהבנת למרות זה.
_____________________________________
Error: Keyboard not found
Press F1 to continue


נערך לאחרונה ע"י maind בתאריך 07-10-2008 בשעה 19:04.
תגובה ללא ציטוט תגובה עם ציטוט חזרה לפורום
  #7  
ישן 07-10-2008, 22:40
  משתמש זכר dorM dorM אינו מחובר  
מנהל
 
חבר מתאריך: 26.07.08
הודעות: 6,473
בתגובה להודעה מספר 5 שנכתבה על ידי maind שמתחילה ב "NULL מוגדר כ0 ב C++, בC הוא..."

ציטוט:
במקור נכתב על ידי maind
NULL מוגדר כ0 ב C++,
בC הוא מוגדר כמו שהוא ציין מצביע לכתובת 0.


C ו-C++ זה לא אותה השפה?
שמתי לב שיש להם תחביר דומה (אם לא בדיוק אותו הדבר), ועד כמה שהבנתי - Cpp זו הרחבה של שפת C?

כל השאר אני חושב שהבנתי!

מלבד השורה הבאה:
קוד:
if (do_something()) { //Compiler see this as: if (do_something() == 0)


למה הקומפיילר מתרגם את זה למשפט-אמת אחר?

אני מניח שבמקרה זה, כל תנאי ה-if המקוננים הם דומים בתוצאתם, בכל המקרים.

כדי לבדוק שהבנתי נכון, אתקן את הקוד שכתבתי:
קוד:
#define NULL ((void *)0) int main(void) { if (Check_Something() == NULL) // bla bla... return 0; } char *Check_Something() { return 0; }


אבל מה קורה כאשר אני רוצה להחזיר מהפונקציה Check_Something() ערך char רגיל, כמו '1' ?
איך אני מבצע זאת?
הרי הגדרתי שהפונקציה מחזירה מצביע, ולכן כל ערך שאחזיר יהיה מצביע למקום מסויים בזיכרון. ואז לא אוכל להחזיר ערך רגיל כמו '1' או char אחר.

תודה על הפירוט!
תגובה ללא ציטוט תגובה עם ציטוט חזרה לפורום
  #8  
ישן 07-10-2008, 23:53
צלמית המשתמש של maind
  maind maind אינו מחובר  
 
חבר מתאריך: 08.10.02
הודעות: 827
בתגובה להודעה מספר 7 שנכתבה על ידי dorM שמתחילה ב "[QUOTE=maind]NULL מוגדר כ0 ב..."

התכוונתי ל:
קוד:
//Compiler see this as: if (do_something() != 0)


אתה לא אמור להחזיר מהפונקציה ערך רגיל כמו 1. הגדרת שהפונקציה מחזירה מצביע, אז אתה צריך להחזיר מצביע למשהו או מצביע לכלום - להחזיר NULL או 0. כמו ש malloc לדוגמא מחזיר מצביע לזכרון אשר הוקצה או מצביע לכלום (null pointer) אם הוא ניכשל כי אין זיכרון פנוי.

אם אתה צריך פוקנציה קצת יותר מסובכת למשל שאם היא מצליחה היא מחזירה מצביע, אבל אם היא לא אז היא תחזיר מצביע לכלום אך גם את סוג השגיאה אתה יכול משהו כזה:

קוד:
#include <stdio.h> #include <string.h> char *GetSecondLine(char *str, int &error) { int i, z; error = 0; if (*str == '\0') { error = 1; return NULL; } z = strlen(str); z--; for (i = 0; i < z; i++, str++) { if (*str == '\n') return ++str; } error = 2; return NULL; } int main() { char buf[] = "Hello World\nHow are you?"; char *SecLine = NULL; int error = -1; SecLine = GetSecondLine(buf, error); switch (error) { case 1: puts("Error: empty input string!\n"); break; case 2: puts("Error: No second line!\n"); break; case 0: printf("Second line: %s\n", SecLine); break; } return 0; }
_____________________________________
Error: Keyboard not found
Press F1 to continue

תגובה ללא ציטוט תגובה עם ציטוט חזרה לפורום
  #10  
ישן 08-10-2008, 02:54
  rtasjugythh rtasjugythh אינו מחובר  
 
חבר מתאריך: 08.10.08
הודעות: 177
בתגובה להודעה מספר 5 שנכתבה על ידי maind שמתחילה ב "NULL מוגדר כ0 ב C++, בC הוא..."

ציטוט:
במקור נכתב על ידי maind
זה מכיוון שבשפה יש מה שנקרא null pointer זה ערך יחודי למצביע מסוג מסוים (כן יכול להיות שלסוגים שונים הערך הוא שונה) שמסמל שהמצביע מצביע אל כלום, שאין מצב שהוא יצא שווה לערך של מצביע אחר מאותו סוג. והערך הזה לא חייב להיות 0.
אבל כשאתה כותב משהו בסגנון הבא:
קוד:
char *abc = 0

וקומפילר רואה שהצבת 0 בהקשר של מצביע וכבר בזמן קימפול (ורק אז) משנה את הערך לערך ה
null. וככה זה בכל מקרה שבוא הקומפיילר יראה 0 בהקשר של מצביע. ולכן NULL מוגדר כ
קוד:
(void *) 0

הקומפילר רואה 0 בהקשר של מצביע וממיר אותו לערך המיוחד הזה של null.

קצת קוד להמחשה:
קוד:
char *abc, *k = 0, i = 0, p = NULL; abc = 0; //abc points to null (abc is a null pointer) abc = NULL; //abc still points to null abc = k; //abc still points to null abc = p; //abc could be pointing to null abc = i; //abc could be pointing to null


ההצבה הראשונה ל abc תציב בו את הערך המיוחד של null (לא חובה שערך זה הוא 0) מכיוון שהקומפילר מזהה 0 בהקשר של מצביע (abc הוא מצביע) והוא יחליף את ה0 בערך המיוחד.
ההצבה השניה גם כן תציב את הערך המיוחד כפי שנאמר קודם. ההצבה השלישית גם כן תציב את הערך המיוחד מכיוון שהמצביע k גם כן מכיל את הערך המיוחד הזה. ההצבה הרביעית אינה בהכרח תעבוד כמו השאר מכיוון שהערך של null יכול להיות גדול יותר מ255 ולכן הוא לא יכנס במלואו ל p. בעצם ההצבה הרביעית תעבוד רק במקרה שבוא הערך המיוחד הזה קטן מ256 ההצבה האחרונה גם אינה בהכרח תעבוד מכיוון שi הוא לא מצביע, יוצב בו בו הערך 0 ולא הערך של null כי זה לא בהקשר של מצביע ואז הערך (אפס) יוצב ב abc ואם במערכת מצביע לכלום (null) מוגדר כערך שונה מאפס ההצבה לא תעבוד כרצוי.

...

ונגיד שאתה מריץ אותה במערכת שבה הnull הוא לא 0 אלא 190,
הפונקציה מחזירה NULL אשר שווה למצביע לכתובת 190, אשר מומר ל char ולכן הפונקציה תחזיר
190, הקומפילר רואה השוואה ל0 אבל בהקשר של char ולכן הוא לא ממיר את ה0 לערך של null
והקוד לא יפעל כמתוכנן. אך אם נשנה את הפונקציה כך שתחזיר מצביע הכל יפעל כראוי כי הקומפילר
יחליף את הערך 0 לערך של null מכיוון שזה בהקשר של מצביע.

קצת ארוך יצא, אז מקווה שהבנת למרות זה.


אפשר לראות קישורים ומקורות שמדברים על זה שיש יישות שהיא "null pointer" שונה מאפס?
אני מסתכל באתר של סטרוסטרופ ואני רואה את זה:
Should I use NULL or 0?

In C++, the definition of NULL is 0, so there is only an aesthetic difference. I prefer to avoid macros, so I use 0. Another problem with NULL is that people sometimes mistakenly believe that it is different from 0 and/or not an integer. In pre-standard code, NULL was/is sometimes defined to something unsuitable and therefore had/has to be avoided. That's less common these days. If you have to name the null pointer, call it nullptr; that's what it's going to be called in C++0x. Then, "nullptr" will be a keyword.

ואת זה:
NULL - zero. 0. 0 is an integer. 0 can be implicitly converted to every pointer type. See also: nullptr. TC++PL 5.1.1, D&E 11.2.3.

nullptr - C++0x keyword for the null pointer. It is not an integer. It can be assigned only to pointers.

ובקיצור, היום (לפני C++0x), פוינטר-null מיוצג על ידי NULL ששקול ל-0 ששקול לכל ביטוי מהצורה:
(type*)0
בגלל ההמרה האוטומטית של 0 לכל טיפוס פויינטר (כולל פויינטר לפונקציה וכו').

אני אנסה למצוא את TCP++L ואת התקן כדי להציץ גם שם, אבל בינתיים זה נשמע לי מאוד מוזר.




עריכה:
אז בדקתי מה התקן אומר:
...

כעגגכ
ב-TC++PL מצאתי אמירה מוזרה:
Note that using the integer 0 as the terminator would not have been portable: on some implementations, the integer zero and the null pointer do not have the same representation. This illustrates the subtleties and extra work that face the programmer once type checking has been suppressed using the ellipsis.
דגכגד

נערך לאחרונה ע"י rtasjugythh בתאריך 08-10-2008 בשעה 03:17.
תגובה ללא ציטוט תגובה עם ציטוט חזרה לפורום
  #11  
ישן 08-10-2008, 03:28
  rtasjugythh rtasjugythh אינו מחובר  
 
חבר מתאריך: 08.10.08
הודעות: 177
אז מה התקן אומר
בתגובה להודעה מספר 10 שנכתבה על ידי rtasjugythh שמתחילה ב "[QUOTE=maind]זה מכיוון שבשפה..."

התקן אומר:
4.10 Pointer conversions [conv.ptr]

1 A null pointer constant is an integral constant expression (5.19) rvalue of integer type that evaluates to
zero. A null pointer constant can be converted to a pointer type; the result is the null pointer value of that
type and is distinguishable from every other value of pointer to object or pointer to function type. Two null
pointer values of the same type shall compare equal. The conversion of a null pointer constant to a pointer
to cv-qualified type is a single conversion, and not the sequence of a pointer conversion followed by a qual-
ification conversion (4.4).

ומצד שני TC++PL אומר ש:

Note that using the integer 0 as the terminator would not have been portable: on some implementations, the integer zero and the null pointer do not have the same representation. This illustrates the subtleties and extra work that face the programmer once type checking has been suppressed using the ellipsis.

מצד שלישי, הספר היה לפני התקן, מה שמתסדר עם האמירה באתר של סטרוסטרופ עצמו:

In pre-standard code, NULL was/is sometimes defined to something unsuitable and therefore had/has to be avoided. That's less common these days.

אז אולי מתישהו היה קטע שה-"null pointer" היה שונה מאפס, אבל היום כנראה זה לא המצב.
תגובה ללא ציטוט תגובה עם ציטוט חזרה לפורום
  #19  
ישן 10-10-2008, 15:41
  rtasjugythh rtasjugythh אינו מחובר  
 
חבר מתאריך: 08.10.08
הודעות: 177
באמת? אתה בטוח שאין שום בעיה?
בתגובה להודעה מספר 18 שנכתבה על ידי maxim k שמתחילה ב "לא מבין מה אתה מנסה לעשות......"

טוב, אני אחזור על זה לאט.

ב-protected mode על 386 והלאה כתובת מורכבת מ-48 ביט - 16 ביט שמשמשים ב-segment selector ו-32 ביט שמשמשים כ-offset. מהם נוצרת כתובת לוגית באורך 32 ביט שמצביעה ל-PDE, ל-PTE ולבייט ספציפי בתוך ה-page. כל מספר בן 32 ביט עשוי לציין כתובת לגיטימית. כל מספר בין 32 ביט עשוי לציין כתובת לגיטימית. הארכיטקטורה הזו לא שמה הגבלות על כתובות מהבחינה הזו. טווח הזיכרון הוא 4GB ולא 4GB-1.

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

בדרך-כלל, זה לא פועל כל כך טוב. לדוגמה, הפונקציה getch מחזירה int, כדי שתוכל להחזיר כל char אפשרי + EOF. כדי להחזיר כל 32 ביט אפשרי + "כתובת לא ואלידית" צריכים יותר מ-32 ביט, אבל זה לא המצב.

השאלה היא, איך נבחר הערך הזה? איך פשוט מוותרים על כתובת חוקית והופכים אותה למספר שמציין כתובת בלתי-חוקית?
תגובה ללא ציטוט תגובה עם ציטוט חזרה לפורום
  #21  
ישן 13-10-2008, 14:51
  rtasjugythh rtasjugythh אינו מחובר  
 
חבר מתאריך: 08.10.08
הודעות: 177
ובקרנל לא כותבים קוד? לא משתמשים ב-C?
בתגובה להודעה מספר 20 שנכתבה על ידי rlsf שמתחילה ב "אני מניח שאתה מתכוון לכך..."

הפתעה הפתעה כאן, דרייברים ל-NT מקובל לכתוב ב-C וזו ההמלצה של MS, לדוגמה.

בכתובת ם ב-PC-י נמצאת ה-IDT, ולא רק שאני עשוי לרצות לכתוב אליה, אני גם יודע שזה אפשרי, ומשתמשים בזה כל הזמן. לדוגמה - קיומם של TSR-ים אפשרי בין השאר בזכות זה.

העניין איננו מיוחד לאפס. בכל מקרה ייקחו כתובת מסוימת אחת, וישתמשו בה כדי לציין "כתובת בלתי חוקית", ולא ברור לי איך מחליטים את זה. ב-user mode זה בסדר שזה יהיה אפס, כי אין הרשאות לשם בדרך-כלל, ואז חוטפים AV/GPF/segfault וכו' מה שטוב לנו. אבל ב-kernel mode אני דווקא רוצה לכתוב לשם.
אז מה נעשה? נגיד flag בקומפיילר שב-kernel-mode מניח לדוגמה, שכל הגישות לזיכרון חייבות להיות aligned, ואז משתמש בכתובת אי-זוגית כלשהי בשביל זה? זה בסדר, עד השלב שבו נרצה קומפיילר שיעבור גם עם כתובות לא מיושרות.

בכל מקרה, מסתבר שמתכנן הקומפיילר חייב להרשות לעצמו אי-אלו הנחות, ופשוט תהיתי מהן ההנחות האלה.
תגובה ללא ציטוט תגובה עם ציטוט חזרה לפורום
  #23  
ישן 14-10-2008, 23:27
  rtasjugythh rtasjugythh אינו מחובר  
 
חבר מתאריך: 08.10.08
הודעות: 177
רק שזה לא ילך טוב תמיד.
בתגובה להודעה מספר 22 שנכתבה על ידי maind שמתחילה ב "אפשר להשתמש במצביע השווה ל..."

מה אם אני מנשה להעביר את המצביע הזה לפונקציה כלשהי, והיא כמו כל פונקציה טובה בודקת את הפרמטרים שלה בהתחלה:
קוד:
int f(T *p, int i) { if ((p == NULL) || (i < 0)) return INVALID_ARG; ... }

לא נעים...

עוד דוגמה. לפי התקן (C99, כי אין C89 באינטרנט, אבל בקטע הזה כנראה שאין הבדלים רציניים):
An integer constant expression with the value 0, or such an expression cast to type
void *, is called a null pointer constant.55) If a null pointer constant is converted to a
pointer type, the resulting pointer, called a null pointer, is guaranteed to compare
unequal to a pointer to any object or function
.
שוב, לא כל כך טוב. המימוש עלול להיות כזה ש-p מצביע לכתובת ה"לא חוקית", p2 מצביע לאלמנט במערך שנמצא אחד לפני p, וההשוואה הבאה תתפקד לא נכון:
קוד:
if (p == p2+sizeof(T))

לא?
תגובה ללא ציטוט תגובה עם ציטוט חזרה לפורום
  #26  
ישן 08-10-2008, 13:00
  משתמש זכר eXtruct eXtruct אינו מחובר  
 
חבר מתאריך: 27.10.05
הודעות: 1,067
בתגובה להודעה מספר 25 שנכתבה על ידי dorM שמתחילה ב "שאלה נוספת: התייחסות למשתנה רגיל בתור מצביע (עם הסימן * )"

אם אני לא טועה הקוד הבא לא יתקמפל.. או יביא לשגיאת זמן ריצה.
הרעיון הוא שמצביע הוא סוג מיוחד אשר מוגדר בצורה של
type* ptr;
רק זה מצביע לעומת משתנה רגיל שמוגדר כ
type name;
משתנה רגיל הוא משתנה עם כתובת קבוע שלא ניתנת לשינוי (אם אני לא טועה). בשביל לקבל ערך של תשמנה רגיל משתמשים רק בשם שלו:
name = 10;
עכשיו הערך בתא שבו נמצא name יהיה 10. אם תרצה לקבל כתובת של name תצטרך לרשום משהוא כמו
printf("%x", &name); (הערה %X מדפיס מספר בצורה הקסה דצימלית)

מצביע לעומת זאת הוא לא משנה הוא כשמו מצביע, הוא לא יכול להכיל ערך משלו כי אין לו כתובת בזכרון (לא בדיוק נכון.. הוא תופס זכרון [2בתים נראה לי בלי קשר לטיפוס]). בשביל לפנות לכתובת של מבציע כותבים פשוט את השם שלו:
ptr = &name
בשורה הזאתי PTR מצביע על הכתובת שבו יושב name. כעת פניה הבאה:
*ptr = 10;
תשנה את הערך שאליו PTR מצביע, כלומר את name. כמו כן כבר בטח הבנת בשביל להתייחס לערך של מצביע יש להתשמש בכוכבית לפני השם.
זה קצת מסובך..
תגובה ללא ציטוט תגובה עם ציטוט חזרה לפורום
  #27  
ישן 09-10-2008, 18:54
  משתמש זכר dorM dorM אינו מחובר  
מנהל
 
חבר מתאריך: 26.07.08
הודעות: 6,473
בתגובה להודעה מספר 26 שנכתבה על ידי eXtruct שמתחילה ב "אם אני לא טועה הקוד הבא לא..."

ציטוט:
במקור נכתב על ידי eXtruct
מצביע לעומת זאת הוא לא משנה הוא כשמו מצביע, הוא לא יכול להכיל ערך משלו כי אין לו כתובת בזכרון (לא בדיוק נכון.. הוא תופס זכרון [2בתים נראה לי בלי קשר לטיפוס]). בשביל לפנות לכתובת של מבציע כותבים פשוט את השם שלו:
ptr = &name
בשורה הזאתי PTR מצביע על הכתובת שבו יושב name. כעת פניה הבאה:
*ptr = 10;
תשנה את הערך שאליו PTR מצביע, כלומר את name. כמו כן כבר בטח הבנת בשביל להתייחס לערך של מצביע יש להתשמש בכוכבית לפני השם.



אולי התכוונת שהפנייה:
קוד:
*ptr=10;

תשנה את הערך של המשתנה הרגיל name ל-10? (וכמו כן ישתנה הערך של המצביע ל-10, אבל עדיין המצביע והמשתנה name יצביעו לאותה הכתובת שלא הישתנתה בעיקבות הקוד הנ"ל).

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

תודה!
תגובה ללא ציטוט תגובה עם ציטוט חזרה לפורום
  #31  
ישן 08-10-2008, 13:38
צלמית המשתמש של maind
  maind maind אינו מחובר  
 
חבר מתאריך: 08.10.02
הודעות: 827
בתגובה להודעה מספר 25 שנכתבה על ידי dorM שמתחילה ב "שאלה נוספת: התייחסות למשתנה רגיל בתור מצביע (עם הסימן * )"

אתה לא יכול להשתמש באופרטור
* על משתנה שהוא לא מצביע.

אני יכול לחשוב על כמה דרכים להכניס את הערך 0 למצביע, אפשר כך:
קוד:
char *pointer; memset(&pointer, 0, sizeof(char *));


או כך:
קוד:
char *pointer = 1; pointer--;



נגיד ואתה צריך מסיבה מסויימת להכניס לכתובת של הזכרון
300 את הערך
10
ולכתובת
301 את הכתובת
11

תעשה משהו כזה
קוד:
char *ptr = 300; *ptr = 10; *(++ptr) = 11;


אבל מקרים כאלה שבאמת תצטרך לעשות משהו כזה
אני יכול לחשוב רק בתכנות של בקרים וכאלה
שלהם יש כבר קומפיילרים מיוחדים שמרשים
הצהרות כמו xdata:
קוד:
xdata at 0x0300 unsigned char data[2]; data[0] = 10; data[1] = 11;

שאומר המערך יאוכסן פיזית בכתובת
0x0300
אבל זה כבר מחוץ לסטנדרט.
_____________________________________
Error: Keyboard not found
Press F1 to continue

תגובה ללא ציטוט תגובה עם ציטוט חזרה לפורום
  #32  
ישן 09-10-2008, 19:10
  משתמש זכר dorM dorM אינו מחובר  
מנהל
 
חבר מתאריך: 26.07.08
הודעות: 6,473
בתגובה להודעה מספר 31 שנכתבה על ידי maind שמתחילה ב "אתה לא יכול להשתמש באופרטור *..."

ציטוט:
במקור נכתב על ידי maind
נגיד ואתה צריך מסיבה מסויימת להכניס לכתובת של הזכרון
300 את הערך
10
ולכתובת
301 את הכתובת
11

תעשה משהו כזה
קוד:
char *ptr = 300; *ptr = 10; *(++ptr) = 11;




ואי כל פעם משתבשת לי מחדש ההבנה של מצביעים...

במשפט הבא, כפי שהבנתי, מכניסים ערך לתא בזיכרון שהמצביע מצביע עליו:
קוד:
type *p = value;


value תלוי ב-type כמובן. אם ה-type הוא char אז ה-value יכול להיות 'A'.

בהצהרה הנ"ל של מצביע מסוג type, אי אפשר לקבוע את הכתובת שאליה המצביע יצביע. (ככה הבנתי עד לפני תגובתך).
אבל לפי מה שהבנתי מהקוד שלך, ישר בהצהרה של המצביע קבעת לו את כתובתו.
אז אני מבולבל מבחינת התחביר, מה עושה מה...?

ד"א, הגבתי לבחור מעליך והוספתי קישור לאתר c-faq עם דרכים נוספות להגדרת מצביע לכתובת 0 ממש: http://c-faq.com/null/accessloc0.html
(ללא היפוכו האוטומטי ל-Null pointer)

תודה!
תגובה ללא ציטוט תגובה עם ציטוט חזרה לפורום
  #33  
ישן 09-10-2008, 21:47
צלמית המשתמש של maind
  maind maind אינו מחובר  
 
חבר מתאריך: 08.10.02
הודעות: 827
בתגובה להודעה מספר 32 שנכתבה על ידי dorM שמתחילה ב "[QUOTE=maind] נגיד ואתה צריך..."

קוד:
char *a = 300;

מגדיר את המצביע a שמצביע לסוג char
ומאתחל את הכתובת של המבציע ל 300.


כאשר תרצה לשנות את מה שהמצביע מצביע אליו תשתמש באופרטור
* לצד השם של המצביע לדוגמא:
קוד:
*a = 'B';

מה שיציב בזיכרון בכתובת 300 את הערך 'B'

כידי לשנות את הכתובת של המבציע אחרי שהגדרת אותו
אתה עושה זאת על ידי שם המצביע ובלי שימוש ב *
לדוגמא
קוד:
a = 400;

אשר משנה את הכתובת של המצביע ל 400 או
קוד:
a++;

אשר מוסיף לכתובת 1

אני בספק אם פעם תצטרך להשתמש בכתובות קבועות מראש כמו 300
או 400 כבמקרים הקודמים. ולכן אתה יכול ואמור ברוב המיקרים לאתחל או להציב
למצביע כתובת של משתנה אחר, לדוגמא:
קוד:
char b = 'B'; char *p = &b; //returns a "char *" which points to b


עכשיו p מצביע לכתובת בה מאוכסן המשתנה b ולכן:
קוד:
printf("%c", *p);

ידפיס .B

האופרטור & מחזיר מצביע מהסוג שהעברת אליו
והמצביע שהוא מחזיר מצביע אל המשתנה שהעברת.
_____________________________________
Error: Keyboard not found
Press F1 to continue


נערך לאחרונה ע"י maind בתאריך 09-10-2008 בשעה 21:49.
תגובה ללא ציטוט תגובה עם ציטוט חזרה לפורום
  #50  
ישן 12-10-2008, 09:30
  משתמש זכר dorM dorM אינו מחובר  
מנהל
 
חבר מתאריך: 26.07.08
הודעות: 6,473
בתגובה להודעה מספר 49 שנכתבה על ידי rlsf שמתחילה ב "לא הבנת כנראה את המשמעות של..."

ציטוט:
במקור נכתב על ידי rlsf
לא הבנת כנראה את המשמעות של type, הכוונה היא שאת type אתה מחליף בסוג המשתנה הרלוונטי, לכן אתה מחזיר למעשה:
קוד PHP:
 (char *)


דוקא כן הבנתי

כידוע ההגדרה של NULL היא:
קוד:
(type *)0 // "type" may be: char, int, short, long, float, double, struct etc.


וכאשר אני כותב:
קוד:
char *test() { return NULL; }

זה שקול לכתיבת:
קוד:
char *test() { return (char *)0; }

או שקול לכתיבת:
קוד:
char *test() { return (int *)0; }

או באופן כללי יותר, שקול לכתיבת:
קוד:
char *test() { return (type *)0; }


וכפי שאני מבין זאת, הנ"ל שקולים לכתיבת:
קוד:
(char *)((type *)0)

כאשר type יכול להיות אחד מהבאים: int, short, char, long וכו'...

ומה שכתוב בקוד האחרון שהצגתי, זה מצביע מסוג char למצביע null (כאשר מצביע null מצביע על כלום...).
זאת אומרת שאם אני מקבל את הערך הנ"ל, כדי שאקבל את Null אני צריך לכתוב משהו כמו:
קוד:
*(test()) // equals NULL


לפי מה ששניכם אמרתם (אתה ו-maind), הבנתי לא נכון.
אז באיזה שלב טעיתי?

נערך לאחרונה ע"י dorM בתאריך 12-10-2008 בשעה 09:36.
תגובה ללא ציטוט תגובה עם ציטוט חזרה לפורום
  #53  
ישן 11-10-2008, 23:05
  משתמש זכר dorM dorM אינו מחובר  
מנהל
 
חבר מתאריך: 26.07.08
הודעות: 6,473
משהו מעניין שמצאתי...
בתגובה להודעה מספר 1 שנכתבה על ידי dorM שמתחילה ב "[שפת C] הגדרת NULL, וגם מה קורה כאשרים פונקציה מסוג char מחזירה NULL"

ניסיתי לעבוד עם ערכי NULL בצורות שונות.

זה הקוד שכתבתי והרצתי, וקיבלתי תוצאות מענינות:

קוד:
#include "stdafx.h" #include <stdio.h> #include <conio.h> using namespace System; #define myNull (void *)0 int test(int); char my(void); int main(array<System::String ^> ^args) { // Function printf("Checking NULL values via my():\n\n"); if (my()==NULL) printf("We have a null!\n"); else printf("BLAT\n"); if (my() == '\0') printf("We have a terminate string char as null!\n"); else printf("BLAT\n"); if (my()== 0) printf("We have a 0 integer!\n"); else printf("BLAT\n"); if (!my()) printf("We have a false expression!\n"); else printf("BLAT\n"); // Direct printf("\n\nChecking NULL values directly:\n\n"); if (NULL == '\0') printf("We have a terminate string char as null!\n"); else printf("BLAT\n"); if (NULL == 0) printf("We have a 0 integer!\n"); else printf("BLAT\n"); if (NULL == ((void *)0)) printf("We have a pointer to 0 as Null!\n"); else printf("BLAT\n"); if (!NULL) printf("We have a false expression!\n"); else printf("BLAT\n"); printf("\n\n NULL is (with my()):\nString:%s\nDecimal:%d\nFloat:%f\nChar:%c\n Hex:%x\nPointer address:%p", my(), my(), my(), my(), my(), my()); printf("\n\n NULL is (directly):\nString:%s\nDecimal:%d\nFloat:%f\nChar :%c\nHex:%x\nPointer address:%p", NULL, NULL, NULL, NULL, NULL, NULL); printf("\n\n myNull is (via #define):\nString:%s\nDecimal:%d\nFloat:%f\nChar:% c\nHex:%x\nPointer address:%p", myNull, myNull, myNull, myNull, myNull, myNull); _getch(); return 0; } char my(void) { return NULL; }


בכל תנאי ה-if שבקוד יצא פסוק אמת (כלומר, לא היה כתוב "BLAT" אפילו פעם אחת.)

את הקוד כתבתי וקימפלתי עם התוכנה Visual Studio 2005, שזו תוכנה של מייקרוסופט כפי שידוע.
האם הקומפיילר שלה עומד בתקן ANSI C 99 ?

יש לי כמה שאלות על הדברים בקוד:

מה מכיל הקובץ "stdafx.h" ?
-------------------------
האם חובה לכתוב:
קוד:
using namespace System;

?
מה זה עוזר?
-------------------------
בהצהרה על הפרמטרים של הפונקציה main כתוב:
קוד:
array<System::String ^> ^args

הקוד הזה לא מוכר לי בכלל, Visual Studio הוסיף את זה בעצמו.
מה זה עושה בדיוק?
-------------------------
למה הפונקציה getch נחשבת לא-תקינה(deprecated)?
למה דווקא כדאי להשתמש בפיתרון של scripter שבאשכול ה-FAQ ?


תודה!
תגובה ללא ציטוט תגובה עם ציטוט חזרה לפורום
תגובה

כלי אשכול חפש באשכול זה
חפש באשכול זה:

חיפוש מתקדם
מצבי תצוגה דרג אשכול זה
דרג אשכול זה:

מזער את תיבת המידע אפשרויות משלוח הודעות
אתה לא יכול לפתוח אשכולות חדשים
אתה לא יכול להגיב לאשכולות
אתה לא יכול לצרף קבצים
אתה לא יכול לערוך את ההודעות שלך

קוד vB פעיל
קוד [IMG] פעיל
קוד HTML כבוי
מעבר לפורום



כל הזמנים המוצגים בדף זה הם לפי איזור זמן GMT +2. השעה כעת היא 13:46

הדף נוצר ב 0.17 שניות עם 10 שאילתות

הפורום מבוסס על vBulletin, גירסא 3.0.6
כל הזכויות לתוכנת הפורומים שמורות © 2024 - 2000 לחברת Jelsoft Enterprises.
כל הזכויות שמורות ל Fresh.co.il ©

צור קשר | תקנון האתר