שאלה ב"מבנים"

שאלה ב"מבנים"

אני מנסה לקלוט שם של מישהו והכנים את זה למבנה ולא מצליח למה? במה טעיתי? הנה הקוד שלי
#include <stdio.h> #include <conio.h> #include <stdlib.h> #include <ctype.h> #include <string.h> struct Product { char *Name; }; void main() { struct Product *d; printf("Name: "); scanf("%s", &d->Name); printf("%s",d->Name); } תודה​
 

giladznaor

New member
תשובה

קודם כל, אתה צריך להגדיר את d לא כמצביע למבנה, אלא כמבנה עצמו, או לחילופין כמצביע למבנה ולהקצות לו זיכרון בגודל של המבנה:
d = (struct Product *) malloc(sizeof(struct Product));​
בנוסף, בscanf, אתה צריך להוריד את ה'&', כי name זה מחרוזת, כלומר שזה כבר שולח לscanf את הכתובת. דוגמא לתוכנית שאומרה לפעול:
#include <stdio.h> #include <conio.h> #include <stdlib.h> #include <ctype.h> #include <string.h> #define MAXLEN 80 struct Product { char Name[MAXLEN]; // Just a pointer without allocating memory // is an error which might crash your // program. }; void main() { struct Product d; // NOTE: This is not a pointer printf("Name: "); scanf("%s", d.Name); printf("%s",d.Name); }​
 

zagzagzag

New member
למדת על malloc ו-realloc ?

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

giladznaor

New member
הקצאת זיכרון דינמי

כמו שכבר נאמר, בד"כ במקרים כאלה עדיף לוותר על כמה ביטים של זיכרון. אם אתה רוצה בכל זאת:
typedef struct _SOMETHING { char *name; } SOMETHING; void Something_Init ( SOMETHING *s ) { s = (SOMETHING *) malloc(sizeof(SOMETHING)); if ( s == NULL ) error(1); } void Something_Kill ( SOMETHING *s ) { if ( s ) free(s); } int main() { SOMETHING s; Something_Init(&s); strcpy(s.name, "John Doe"); printf("s.name = \"%s\"\n", s.name); Something_Kill(&s); }​
כמו שאתה רואה, זה מוסיף הרבה עבודה, וסיכון של זליגות זיכרון וקריסות מערכת אם לא נזהרים. אם אתה משתמש ב++C אפשר לעשות את זה בהרבה יותר אלגנטיות בעזרת עצמים, אבל ככה זה בC.
 

giladznaor

New member
תיקון

הם, די התעלמתי מהעצות של עצמי. ככה זה צריך להיות:
typedef struct _SOMETHING { char *name; } SOMETHING; void Something_Init ( SOMETHING *s ) { s = (SOMETHING *) malloc(sizeof(SOMETHING)); if ( s == NULL ) error(1); s->name = (char *) NULL; } void Something_Kill ( SOMETHING *s ) { if ( s->temp ) free(s->temp); if ( s ) free(s); } void Something_Input ( SOMETHING *s ) { char temp[80]; if ( s == NULL ) Something_Init(s); if ( s->temp ) free(s->temp); scanf("%s", temp); s->name = (char *) malloc(sizeof(char) * (strlen(temp)+1)); strcpy(s->name, temp); } int main() { SOMETHING s; Something_Init(&s); printf("Enter name: "); Something_Input(&s); Something_Kill(&s); }​
ושוב אנו רואים כמה עבודה צריכים להשקיע בהקצאת זיכרון דינמי כדי לוודא שלא נפיל את המערכת. לדוגמא, מצביע עם ערך NULL מצביע לתחילת הזיכרון, ושם בחלק ממערכות ההפעלה יש את הכתובות של כל הinterrupts, כך ששמשחק איתם יכול ממש לדפוק את המחשב. ובגלל שחייבים לעשות את זה, אז עדיף כבר לעשות את זה עם סטייל, כלומר ב++C.
 

זהיר

New member
מינוס ומינוס זה מינוס גדול

הסיבות שציינו נכונות - אבל לא הפתרונות (יש פשפשים
. 1. גם אם אתה משתמש ב scanf אתה חייב להגביל את קריאת המחרוזת. 2. גם אם אתה מקצה דינאמית אתה צריך לוודא שלא גלשת מהמערך (אפילו אם הודעת למשתמש שהוא מוגבל - ייתכן שהוא פורץ ויתכן שהוא אדיוט). אין ארוחות חינם תכנתו בזהירות
 

giladznaor

New member
נכון

זה למה אני אישית אף לא משתמש בפונקציות הסטנדרטיות לקליטת מחרוזות, אלא בפונקציות משלי. סתם עבר לי כרגע בראש שאפשר לנסות fgets, שדורש הגבלה של אורך, עם stdin כמצביע קובץ.
 
למעלה