בעיות כתיבה/קריאה מקבצים ב-C - תכנות - HWzone פורומים
עבור לתוכן
  • צור חשבון

בעיות כתיבה/קריאה מקבצים ב-C


slimshady21

Recommended Posts

שלום.

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

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

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

הנה הקוד- רק הורדתי את כל הפונקציות הלא חשובות:



#define filename "binary.bin"

typedef struct
{
long code;
char *des;
float price;
}store;



int LoadFile(store ***a,int n)
{
int counter,check=0,size=0;
FILE *file=fopen(filename,"rb");
if(file==NULL)
{
clrscr();
printf("Can't open file");
return n;
}

check=fread(&size,sizeof(int),1,file);
if(size==0 || check==0)
{
printf("No data on file");
return n;
}

// Begining to free all the array:::

for(counter=0;counter<size;counter++)
free((*a)[counter]->des);

for(counter=0;counter<size;counter++)
free((*a)[counter]);

free(*a);
// END free

(*a)=(store**)calloc(size,sizeof(store*));

for(counter=0;counter<size;counter++)
(*a)[counter]=(store*)calloc(1,sizeof(store));

for(counter=0;counter<size;counter++)
fread((*a)[counter],sizeof(store),1,file);

printf("\n\nAll data have been loaded from the file\n\n");
return size;
}







void SaveFile(store **a,int size)
{
int counter,check=0;

FILE *file=fopen(filename,"wb");
if(file==NULL)
{
printf("cant open file");
getch();
exit(1);
}

fwrite(&size,sizeof(int),1,file);

for(counter=0;counter<size;counter++)
check+=fwrite(a[counter],sizeof(store),1,file);

if(check!=size)
{
printf("Error writing to file");
getch();
fclose(file);
exit(1);
}
fclose(file);
printf("\n\nData have been saved to the file successfully\n\n");
}






void PrintList(store **a,int size)
{
int counter;
printf("\n\n# Code Description Price\n");
printf("------------------------------------------------------------------\n");

for(counter=0;counter<size;counter++)
printf("%d.%-13ld%-20s %-4f\n",counter+1,a[counter]->code,a[counter]->des,a[counter]->price);
putchar('\n');
}





int main()
{
store **a=NULL;
char ch;
int size=0,counter;

printf("-----SlimShady's program for store managment-----\n\n");
do
{
ch=Menu();

switch(ch)
{
case 'p':
{
PrintList(a,size);
break;
}
case 's':
{
SaveFile(a,size);
break;
}
case 'l':
{
size=LoadFile(&a,size);
break;
}
case 'q':
continue;
}
}while(ch!='q');


return 0;
}


קישור לתוכן
שתף באתרים אחרים

  • תגובות 44
  • נוצר
  • תגובה אחרונה

זה בגלל שלא שמרת את המחרוזות לקובץ אלא את המצביעים אל המחרוזות.

יש לך בגדול שתי אופציות:

1) לשנות את מבנה store כך שיכיל לא מצביע למחרוזת אלא מערך של char-ים כלומר מחרוזת באורך קבוע: char description[DESC_SIZE]

2) לשמור כמו שצריך את המחרוזות לקובץ. אל תשכח לטעון אותן כמו שצריך (הקצאת למחרוזת, ואז טעינת).

בכל מקרה תזכור כמה דברים:

אם str הוא char* אז sizeof(str) הוא תמיד גודל של מצביע ל-char, ללא קשר לאורך המחרוזת.

אם str הוא char[20] אז sizeof(str) הוא תמיד 20 ללא קשר לאורך המחרוזת.

אם אורך המחרוזת ב-str הוא 15, אז אל תשכח שהגודל שלא הוא 16 כלומר strlen(str) +1. תזכור את זה כשתקצה , תשמור ותטען מקובץ.

קישור לתוכן
שתף באתרים אחרים

וואלה אחי תודהההה. איך שכחתי שצריך להקצות גם למחרוזות יאללה :kopfpatsch:.

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

אז אני ישאיר אותם דינמיים, אבל השמירה של המחרוזות לקובץ עשיתי טוב לא? הרי אם למשל *str זה מצביע למחרוזת, אז אתה פשוט שומר אותו ואז כל המחרוזת נשמרת לא? אחרת אז איך?

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

חשבתי למשל, להכניס לקובץ את אורך המחרוזת שנמצאת במבנה שאני עומד לשמור עליו. הכוונה- לשמור את אורך מחרוזת מספר 1, ואז את מבנה מספר 1. אחר כך לשמור את אורך מחרוזת מספר 2, ואז את מבנה מספר 2. ואז בקריאה לקובץ אני יוכל להתאים כבר את האורך של המחרוזות. מה אתה אומר זה יעבוד?

ולגבי מה שאמרת בסוף- אני לא שומר ככה בכלל, נגיד אני רוצה לכתוב את המחרוזת str לקובץ אני עושה:

fwrite(str,sizeof(char),strlen(str)+1,file) a

לא טוב?

קישור לתוכן
שתף באתרים אחרים

ראשית אם אתה שומר את הערך של str אז לא שמרת את המחרוזת, שמרת מצביע.

הדרך לשמור את המחרוזת היא בדיוק כמו שהצעת: fwrite(str,sizeof(char),strlen(str)+1,file)

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

שימוש ב-fprintf לא מומלץ בקבצים בינריים.

קישור לתוכן
שתף באתרים אחרים

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

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

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

הנה הקוד עכשיו:

#define filename "binary.log"

typedef struct
{
long code;
char *des;
float price;
}store;



int LoadFile(store ***a,int n)
{
int counter,check=0,size=0,lenght=0;
FILE *file=fopen(filename,"rb");
if(file==NULL)
{
clrscr();
printf("Can't open file");
getch();
exit(1);
}

check=fread(&size,sizeof(int),1,file);
if(size==0 || check==0)
{
printf("No data on file");
return n;
}


for(counter=0;counter<size;counter++)
free((*a)[counter]->des);

for(counter=0;counter<size;counter++)
free((*a)[counter]);

free(*a);


(*a)=(store**)calloc(size,sizeof(store*));

for(counter=0;counter<size;counter++)
(*a)[counter]=(store*)calloc(1,sizeof(store));

for(counter=0;counter<size;counter++)
{
fread(&lenght,sizeof(int),1,file);
(*a)[counter]->des=(char*)calloc(lenght,sizeof(char));
fread((*a)[counter],sizeof(store),1,file);
}

printf("\n\nAll data have been loaded from the file\n\n");
return size;
}




void SaveFile(store **a,int size)
{
int counter,check=0,check2=0,lenght=0;

FILE *file=fopen(filename,"wb");


fwrite(&size,sizeof(int),1,file);

for(counter=0;counter<size;counter++)
{
lenght=strlen(a[counter]->des)+1;
printf("%d,",lenght);
check+=fwrite(&lenght,sizeof(int),1,file);
check2+=fwrite(a[counter],sizeof(store),1,file);
}

if(check!=size || check2!=size || check!=check2)
{
printf("Error writing to file");
getch();
fclose(file);
exit(1);
}

fclose(file);
printf("\n\nData have been saved to the file successfully\n\n");
}




int main()
{
store **a=NULL;
char ch;
int size=0,counter;

do
{
ch=Menu();

switch(ch)
{
case 'S':
case 's':
{
SaveFile(a,size);
break;
}
case 'L':
case 'l':
{
size=LoadFile(&a,size);
break;
}
case 'q':
continue;
}
}while(ch!='q');


return 0;
}

קישור לתוכן
שתף באתרים אחרים

אם אתה כותב INT לתוך הקובץ, אז תצפה לקרוא INT ממנו.

אם תראה INT, אין שום סיבה שגם כל שאר הטקסט שרשמת יכנס לתוך המשתנה.

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

קישור לתוכן
שתף באתרים אחרים

נו זה בדיוק מה שעשיתי. אני קורא קודם את המספר INT -שהוא אורך המחרוזת ששמרתי מקודם. אני מכניס אותו למשתנה זמני lenght , מקצה למחרוזת בהתאם, ואז קולט את הנתונים למבנה. סתכל על פונקציה LoadFile . אבל זה לא עובד טוב. לפעמים זה בסדר, אבל לפעמים יש חירבושים, לפעמים התוכנית משתגעת, ולפעמים היא פשוט קורסת. וזה גם שונה עם סוגי קבצים שונים (log, bin,db). אז מה אני אמור לעשות?

קישור לתוכן
שתף באתרים אחרים

ת'אמת, אני עובד בC כבר הרבה זמן ואין לי מושג מה זה DEBUG. אני חשבתי שכל ההודעות שגיאה שאני מקבל למטה זה הDEBUG ...

בכל מקרה, נכנסתי עכשיו לתוכנה וראיתי תפריט DEBUG , אבל אז מה אני עושה שם? לחצתי סתם על INSPECT אבל הוא ביקש שאני ארשום משהו.

אז מה לעשות?

יש לי borland turbo C++ 3.1 for DOS

קישור לתוכן
שתף באתרים אחרים


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct store {
long code;
float price;
char* desc;
} store;

store* loadStore(const char* file, int* size) {
FILE* in;
store* s;
int i, len;
if( (in=fopen(file, "rb")) == NULL ) {
printf("Error opening");
return NULL;
}
if( fread(size, sizeof(int), 1, in) != 1 ) {
printf("Error getting length!");
return NULL;
}
if( (s=calloc(*size, sizeof(store))) == NULL ) {
printf("Error getting space!");
return NULL;
}
for(i=0;i<(*size);++i) {
/* Add tests to make sure getting data corretly!! */
fread(&s[i].code, sizeof(long), 1, in);
fread(&s[i].price, sizeof(float), 1, in);
fread(&len, sizeof(int), 1, in);
s[i].desc = calloc(len, sizeof(char));
fread(s[i].desc, sizeof(char), len, in);
}
fclose(in);
return s;
}

void saveStore(const char* file, store* s, int size) {
FILE* out;
int i, len;
/* Add tests to make sure setting data corretly!! */
if( (out=fopen(file, "wb")) == NULL ) {
printf("Error opening");
return;
}
fwrite(&size, sizeof(int), 1, out);
for(i=0;i<size;++i) {
fwrite(&s[i].code, sizeof(long), 1, out);
fwrite(&s[i].price, sizeof(float), 1, out);
len = strlen(s[i].desc)+1;
fwrite(&len, sizeof(int), 1, out);
fwrite(s[i].desc, sizeof(char), len, out);
}
fclose(out);
}

void freeStore(store** s, int size) {
int i;
store* ss = *s;
for(i=0;i<size;++i) {
free(ss[i].desc);
}
free(*s);
}

int main() {
store* s = calloc(25, sizeof(store));
int i, size;
for(i=0;i<25;++i) {
s[i].code=i;
s[i].price=i*0.5;
s[i].desc=strdup("Test");
}
saveStore("C:\\Test.txt", s, 25);
freeStore(&s, 25);
s = loadStore("C:\\Test.txt", &size);
printf("%d\n",size);
for(i=0;i<size;++i) {
printf("%d %f %s\n",s[i].code,s[i].price,s[i].desc);
}
freeStore(&s, size);
system("PAUSE");
return 0;
}

הקוד לא מושלם וצריך לעשות בדיקות תקינות

קישור לתוכן
שתף באתרים אחרים

כן תודה אחי, אבל בדיוק כרגע, אחרי שעבדתי איזה שעה על הקוד- הצלחתי! עשיתי בדיוק מה שאתה עשית- במקום לכתוב ולקרוא את הנתונים כמבנה שלם (בפעולת קריאה/כתיבה אחת) , פיצלתי את זה לכל המשתנים במבנה - code , desc, price וזה עבד טוב!

אבל זה לא אמור להיות ככה, אני לא מבין מה הבעיה שלו בלקרוא/לכתוב מבנה שלם כמו שצריך.....

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

בכל אופן, אשמח גם אם תגידו לי מה זה בדיוק הDEBUGGER הזה ואיך להשתמש בו

קישור לתוכן
שתף באתרים אחרים

כן תודה אחי, אבל בדיוק כרגע, אחרי שעבדתי איזה שעה על הקוד- הצלחתי! עשיתי בדיוק מה שאתה עשית- במקום לכתוב ולקרוא את הנתונים כמבנה שלם (בפעולת קריאה/כתיבה אחת) , פיצלתי את זה לכל המשתנים במבנה - code , desc, price וזה עבד טוב!

אבל זה לא אמור להיות ככה, אני לא מבין מה הבעיה שלו בלקרוא/לכתוב מבנה שלם כמו שצריך.....

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

בכל אופן, אשמח גם אם תגידו לי מה זה בדיוק הDEBUGGER הזה ואיך להשתמש בו

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

מדובר ב-tradeoff. הרבה דברים בתוכנה (ובהנדסה) הם ככה.

קישור לתוכן
שתף באתרים אחרים

טוב תודה.

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

וחשבתי עכשיו- יכול להיות שהבעיה בקריאה/כתיבה של כל המבנה לקובץ, כמו שניסיתי בהתחלה, הייתה כי לא השתמשתי כלל בפונקציה fflush ? פתאום נזכרתי בפונקציה הזאת שקשורה לקבצים, וחשבתי אולי זה בגללה

קישור לתוכן
שתף באתרים אחרים

ארכיון

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


×
  • צור חדש...