עבור לתוכן

תרגיל בשפת C שאני לא מבין

Featured Replies

פורסם

אוקי זה התרגיל:

יש לכתוב פונקציה myscanf המממשת גירסא פשוטה של scanf, המקבלת שני פרמטרים בלבד:

הפרמטר הראשון - מחרוזת(קבועה) היכולה להכיל אך ורק %d %f %s - כל מחרוזת אחרת שתתקבל תגרום לשגיאה.

הפרמטר השני הוא פוינטר גנרי מסוג void המהווה פרמטר פלט

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

הבעיה היא שאני לא מבין את השאלה

איזה נתונים אני שולח ל myscanf ומה זה פוינטר גנרי מסוג void?

פורסם

הטיפוס *void הוא טיפוס שמציין "מצביע", בלי לומר למה הוא בדיוק מצביע. הוא יכול לקבל כל ערך של מצביע.

ראה דוגמה להלן:

int x = 5;
int* p = &x; // legal, obviously
void* s = &x; // legal - anything can be converted to void*
char* q = &x; // illegal - x is not char

בניגוד למצביעים רגילים, ל-*void אי אפשר לעשות dereference, כי הם לא מצביעים לטיפוס אמיתי. דהיינו:

int x = 5;
void* p = &x;
int y = *p; // illegal - *p has no type

למה זה טוב? בדרך כלל, משתנה יכול להחזיק רק טיפוס אחד - int, char וכד'. שימוש ב-*void מאפשר לך להחזיק משתנה שהטיפוס שלו לא ידוע מראש. אבל מה, בשביל להשתמש בו באופן אקטיבי, תצטרך לבצע המרה - לדוגמה, בשביל שהקוד הנ"ל יעבוד אנחנו צריכים לכתוב ככה:

int x = 5;
void* p = &x;
int y = *((int*)p);

הקוד קצת מבלבל - אנחנו קודם כל ממירים את p מ-*void ל-*int, ואז אנחנו עושים לו dereference.

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

int x = 0;
void* p = &x;
float y = *((float*)p);

מה שיקרה הוא שהערך שיושב בתוך x (כלומר, במקום בזכרון שבו יושב x) יפורש כ-float, למרות שהוא מטיפוס int. התוצאה היא בלתי צפויה (המבנה של int ושל float בזכרון של המחשב שונים לחלוטין).

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

ככה בעצם עובדת scanf - הפונקציה מקבלת פרמטרים מטיפוס *void בלבד. אז איך היא יודעת מהם הטיפוסים המקוריים? לפי המחרוזת שהעברת אליה - אם היא מכילה d% אז המצביע הוא במקור מטיפוס *int, אם היא מכילה f% אז הוא מטיפוס *float, וכן הלאה. שים לב שאם תעביר לה *int יחד עם f% אז הקוד יתקמפל וירוץ, אבל התוצאה תהיה לא צפויה.

פורסם
  • מחבר

אוקי אני חושב שהבנתי אבל רק בזמן כתיבת התוכנית אני אדע אם באמת הבנתי...

ובקשר לשאלה עצמה

מה שהתוכנית צריכה בעצם לעשות זה

1) לקלוט כמות (לא ידועה) של תווים

2) לחפש אחר רצף מתאים של תווים

3) ולהמיר אותם לערך המתאים?

לדוגמא אם כתבו לי "i need to ask you 2 questions"

את האותיות יומרו לchar

והמספר יומר ל int?

התרגיל הזה בילבל אותי קצת...

פורסם

למי איכפת מה כתבו לך? אתה רק צריך לכתוב את myscanf. תן למי שמשתמש ב-myscanf להתחבט איתה.

תתחיל מלכתוב את החתימה של myscanf.

הפואנטה היא שאתה צריך להיות מסוגל להריץ את הקוד הבא:

int x;
float y;
myscanf("%d", &x);
myscanf("%f", &y);
myscanf("blabla", &x); // this should return an error

פורסם
  • מחבר

אוקי הבנתי פחות או יותר, תודה.

כרגע נתקלתי בבעיה

אתה יכול להסביר לי שוב איך אני מחזיר את התוצאה הסופית למשתנה הגנרי void *?

אני מתכוון שאני רוצה לשלוח מהפונקציה החדשה myscanf את הערך של ה-output לפונקציה שקוראת לmyscanf

אבל אני לא מצליח לעשות את זה...

עריכה: הסדרתי... תודה על כל העזרה :-)

פורסם
  • מחבר

יש לי רק בעיה אחת עם התוכנית שבניתי

כאשר אני מנסה להכניס מספר float הפלט שלי יוצא לא כל כך מדוייק

מה הכוונה:

לדוגמא הכנסתי את המספר 123.1111

הפלט שלי בסופו של דבר כאשר אני מדפיס את המספר הבנוי מחדש הוא:

123.111099

    while((c=getchar()) !=EOF && c != '\n' && c!=' ') {
if((!isspace(c) && isdigit(c)) || c=='.') {
if(c=='.') {
f_c++;
f=f_a;
f_a=0;
} else if(isdigit(c)) {
f_a *= 10;
f_a += (c-'0');
if(f_c>0)
i*=10;
}
} else {
puts("Error: Unwanted char has been entered!\n");
return 0;
break;
}
}
f=(float)f+(float)f_a/(float)i;

זה הקוד שנמצא בתוך פונקציה ארוכה

פורסם

float אינו מדוייק. גם double אינו מדוייק אבל float במיוחד אינו מדויק.

לא ניתן לייצג כל מספר בעזרת float (כנ"ל double אבל העיה פחות חריפה שם), ולכן לאורך ההצבות והחישובים מצטברות טעויות.

הכלל הראשון שכעובדים עם נקודה צפה (floating point) זה לזכור שהם לא מדוייקים לגמרי.

פורסם
  • מחבר

אוקי תודה, ואתה צודק

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

ארכיון

דיון זה הועבר לארכיון ולא ניתן להוסיף בו תגובות חדשות.

דיונים חדשים