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

מקביל לrealloc ב++C


Sikamikanico

Recommended Posts

אחרי שקראתי קצת בספר של ++C, החלטתי לעבור לתכנת רק בה (במקום C).

כחלק מהמעבר, אני משדרג את משחק הסנייק שבניתי בC.

אני משתמש במשחק בפקודה realloc, שזה נותן להגדיל\להקטין את הזכרון הדינמי שמוקצה כבר.

רציתי לדעת אם יש מקביל לפקודה זו ב++C.

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

כמובן שזה לא יעיל, כי אני משתמש בשתי פקודות new ושתי delete, במקום realloc אחת.

בלי קשר:

++C ממש שפה אדירה!

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

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

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

מה ש realloc עושה זה פשוט הקצאת חדש (ע"י malloc), העתקת הזכרון הישן למקום החדש (ע"י memcpy או), ושחרור הזכרון הישן (ע"י free). לפיכך, ההבדל היחיד בין הביצועים של realloc לבין פונק' העזר שאתה כתבת הוא פשוט ההבדל בביצועים בין פקודות ה malloc ו ה new, ה free וה delete, ה memcpy והפקודה שבה התשמשת כדי להעתיק את הזכרון (אני לא זוכר שיש פונק' שעושה משהו מקביל ל memcpy ב C++, תקן אותי אם אני טועה), וכמובן, אם תחשוב על זה קצת, תראה שהעתקת הזכרון לזכרון זמני היא פשוט מיותרת. ;)

למיטב ידיעתי, אין פקודה מקבילה ל realloc ב C++, וממה שאמרתי, זה גם לא ממש משנה..

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

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

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

מה הכוונה?

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

ככה נראה מה שיש לי עכשיו:

void snake::realloc()

{

int *tmpx,*tmpy,i;

tmpx=new int[length+1];

tmpy=new int[length+1];

for(i=0;i<=length-2;i++)

{

*(tmpx+i)=*(x+i);

*(tmpy+i)=*(y+i);

}

delete []x;

delete []y;

x=new int[length+1];

y=new int[length+1];

for(i=0;i<=length-2;i++)

{

*(x+i)=*(tmpx+i);

*(y+i)=*(tmpy+i);

}

delete []tmpx;

delete []tmpy;

}

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

הכוונה היא שX וY שומרים את הקואורדינטות של הנחש, וכשהנחש אוכל נקודה - צריך להגדיל את הגוף באחד, אבל לשמור על הערכים הקודמים - פעולה ש realloc עשתה מצוין.

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

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

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

זה אמור להיות משהו כזה:

void snake::realloc()

{

int * tmpx = new int[length+1];

int * tmpy = new int[length+1];

for(int i = 0 ; i < length ; i++)

{

tmpx = x;

tmpy = y;

}

delete [] x;

delete [] y;

x = tmpx;

y = tmpy;

}

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

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

מצד שני, מכיוןן שהגודל של המערך לעולם יהיה די קטן זה לא כ"כ משנה.

אבל, אם אתה כבר כותב תוכנה בשביל ללמוד שפה חדשה וכו', אז כדאי שגם תלמד כמה אלגוריתמים ומבני נתונים בדרך. ;)

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

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

מה שהצעת באמת יותר הגיוני.

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

יש לי רק כמה שאלות:

לפי מה שראיתי, להוסיף איבר אחד בסוף זה ממש קל (במיוחד שמוסיפים בסוף ולא צריך לסדר לפי א"ב או משהו).

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

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

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

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

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

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

אין שום בעיה לעשות את מה שאמרת.

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

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

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

טוב נראה לי שאני אנסה את זה, ברגע שאני אפתור את הבעיה הבאה:

המשחק, באופן כללי, עובד בצורה של - פעולה (תזוזה), Delay, פעולה, Delay...

עכשיו כל פעם שמגיעים לפעולה, יכולים להיות מספר מקרים (אני מדבר על משחק בשני שחקנים):

אף כפתור לא נלחץ - שני הנחשים ממשיכים בכיוונם.

שחקן 1 לחץ על כפתור - הנחש שלו זז לכיוון הרצוי, השני ממשיך בכיוונו.

שחקן 2 לחץ על כפתור - הנחש שלו זז לכיוון הרצוי, השני ממשיך בכיוונו.

שני השחקנים לחצו על כפתורים - שני הנחשים זזים לכיוון הרצוי.

הבעיה שלי היא איך לקלוט את מה שכל שחקן ביקש ולהגיב בהתאם.

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

אבל בגלל שהשחקנים יכולים גם לא להגיב, אני חייב להשתמש ב (()if(kbhit לכל שחקן.

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

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

אז הוספתי משתנה made_move לכל נחש, ואז כשהגעתי לgetch בדקתי אם הוא כבר זז או לא.

...

בקיצור הסתבכתי. זה לא עובד כמו שצריך.

אני צריך פתרון יותר טוב.

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

void get_move()

{

char ch;

if(kbhit())

{

ch=getch();

if(ch==0)

{

ch=getch();

if(ch==75 && s1.move!='r' && s1.move!='l'){s1.move='l';s1.made_move=1;}

else if(ch==77 && s1.move!='l' && s1.move!='r'){s1.move='r';}

else if(ch==72 && s1.move!='d' && s1.move!='u'){s1.move='u';}

else if(ch==80 && s1.move!='u' && s1.move!='d'){s1.move='d';}

}

else if(twoplayers){

if(ch=='a' && s2.move!='r' && s2.move!='l'){s2.move='l';s2.made_move=1;}

else if(ch=='d' && s2.move!='l' && s2.move!='r'){s2.move='r';}

else if(ch=='w' && s2.move!='d' && s2.move!='u'){s2.move='u';}

else if(ch=='s' && s2.move!='u' && s2.move!='d'){s2.move='d';}}

}

if(twoplayers)

if(kbhit())

{

ch=getch();

if(ch==0 && s1.made_move==0)

{

ch=getch();

if(ch==75 && s1.move!='r' && s1.move!='l'){s1.move='l';s1.made_move=1;}

else if(ch==77 && s1.move!='l' && s1.move!='r'){s1.move='r';}

else if(ch==72 && s1.move!='d' && s1.move!='u'){s1.move='u';}

else if(ch==80 && s1.move!='u' && s1.move!='d'){s1.move='d';}

}

else if(s2.made_move==0){

if(ch=='a' && s2.move!='r' && s2.move!='l'){s2.move='l';s2.made_move=1;}

else if(ch=='d' && s2.move!='l' && s2.move!='r'){s2.move='r';}

else if(ch=='w' && s2.move!='d' && s2.move!='u'){s2.move='u';}

else if(ch=='s' && s2.move!='u' && s2.move!='d'){s2.move='d';}}

}

}

קצת הסבר:

s1 - נחש 1.

s2 - נחש 2.

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

s1/2.move - בעקרון, אם באמת נלחץ מקש עם כיוון רלוונטי, אז המשתנה הזה ישמור את הכיוון החדש וזה אחר כך ישלח לפונקציה שעושה את התזוזה עצמה.

s1/2.made_move - דגל ששומר אם לנחש כבר נקבע כיוון חדש או עוד לא. זה מתאפס אחרי כל Delay (תור).

twoplayers - זה דגל ששמור בו אם משחקים שני שחקנים או אחד. במקרה הזה הוא שווה 1.

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

טוב, עצה ראשונה - תגדיר enum שישמור את הערכים של המקשים (72,77,'a' וכו'), ככה הקוד יהיה הרבה יותר קריא.

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

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

התבלבלתי קצת במה שכתבתי.

לא התכוונתי לשני getch בשני kbhit.

אלא לשני kbhit, שבכל אחד יש getch אחד, אבל אני בודק אותו לשני השחקנים.

אם יהיה רק kbhit אחד, אז בכל תור, רק שחקן אחד יוכל לזוז.

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

כשאתה אומר אסמבלי, אתה מתכוון ל Interuptions ?

אם כן, זה מסובך?

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

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

בעניין אסמבלי, כן, הכוונה היא לעבוד עם interupts.. אבל ת'אמת, אין לי שמץ של מושג בזה..

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

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

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

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

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

יש סיכוי שאפשר לעשות את זה בעזרת Interuptions?

אם כן, איפה אני יכול ללמוד איך להשתמש בזה?

ניסיתי לחפש בגוגל ++C ן Interuptions, מצאתי סתם דברים לא קשורים.

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

קודם כל בקשר לאסמבלי, אתה לא מחפש interuptions אלא interrupts או בעברית: פסיקות.

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

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

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

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

נכון.. לא שמתי לב לכל העניין של ה delay...

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

אז זהו שלא! באמצעות פסיקות אפשר לזהות את המצב המדויק של המקשים...

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

טוב, עשיתי קצת מחקר:

חיפשתי מידע על תכנות משחקין, ובכל האתרים שראיתי משתמשים בפסיקות ועושים Install New Handler כדי לטפל בהקשות מקלדת.

השימוש בפסיקות הוא הרבה יותר מהיר מאשר לקרוא את מה שהוכנס למקלדת מבאפר, בכל פעם.

אפילו מצאתי קוד בC שדי קל להבין ולהשתמש בו.

אבל אז נתקלתי בפיסת המידע הבאה:

The following DOS games try to install a new keyboard interrupt to handle key presses. This works great in DOS or Win 3.1/95/98, but NT and 2000 don't allow it. This means that unfortunately the keyboard doesn't work at all in these games for those operating systems.

אני משתמש בXP.

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

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

ארכיון

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


×
  • צור חדש...