الشبكة العربية لمطوري الألعاب

خبير مدير همام البهنسي مشاركة 1

السلام عليكم...


هذه أحد التمارين البسيطة التي أحاول التعلم من خلالها البرمجة باللغة MSX-C على جهاز الصخر. المثال يفترض أن يقوم بحفظ بيانات في ملف binary واسترجاعها.
#include<stdio.h>

int SaveFile(istream,fname)
char *istream;
char *fname;
{
  FILE *fp;
  fp=fopen(fname,"wb");
  fwrite(istream,sizeof(char),sizeof(istream),fp);
  fclose(fp);
  return 0;
}

int ReadFile(fname,ostream)
char *fname;
char *ostream;
{
  FILE *fp;
  fp=fopen(fname,"rb");
  fread(ostream,sizeof(char),sizeof(ostream),fp);
  printf("%d",(char)ostream[0]);
  fclose(fp);
  return 0;
}

int main()
{
  char xo[2];
  char xi[2];

  xi[0]=8;
  xi[1]=16;

  SaveFile("d.bin",xi);
  ReadFile(xo,"d.bin");
}

الكود السابق يترجم بنجاح ولكن عند محاولة طباعة نتيجة القراءة أحصل على زبالة من ذاكرة الجهاز. الأمر الذي يدل على خطأ في التعامل مع الذاكرة :(


أرجوا المساعدة من خبراء السي :)
شكراً

خبير مدير همام البهنسي مشاركة 2

قمت بتعديل الكود كالتالي:
#include<stdio.h>

int SaveFile(stream,len,fname)
char *stream;
TINY len;
char *fname;
{
  FILE *fp;

  fp=fopen(fname,"wb");
  fwrite(stream,sizeof(char),len,fp);
  fclose(fp);
  return 0;
}

int ReadFile(len,fname)
TINY len;
char *fname;
{
  FILE *fp;
  char stream[len];

  fp=fopen(fname,"rb");
  fread(stream,sizeof(char),len,fp);
  printf("%d",(int)stream[0]);
  fclose(fp);
  return 0;
}

int main()
{
  char* fn;
  char x[2];

  fn="d.bin";
  x[0]=8;
  x[1]=16;

  SaveFile(x,(TINY)sizeof(x),fn);
  ReadFile((TINY)sizeof(x),fn);
}

ولكن بعد هذا التعديل المترجم أصبح يعطي خطأ (bad static expression) في السطر التالي:
char stream[len];

أظن الجواب هو استخدام malloc لحجز الذاكرة بشكل ديناميكي وقت التشغيل (run-time). ولكن هل هذا هو الحل الأفضل؟

خبير مدير وسام البهنسي مشاركة 3

الخطأ الظاهر مبدئياً هو عكس البارامترات عند نداء ReadFile، حيث يتم تمرير اسم الملف بدلاً من مخزن النص، ومخزن النص بدلاً من اسم الملف.
بصراحة الكود غريب بعض الشيء علي، فأنا لم أكتب كود سي غير قياسي، ويبدو أن هذه اللهجة من لغة سي سبقت ظهور معايير أيزو الموحدة للغة.
بالنسبة لموضوع القدرة على التعامل مع نص من أي طول بدلاً من طول ثابت، فيجب أن نعرف أولاً أن المترجم لا يسمح باستخدام قيمة متغير عند الإعلان عن مصفوفة بحجم ما.
مثلاً:

char MyString[10]; /* مسموح */
int len=10;
char MyString2[len]; /* غير مسموح */

المصفوفة المعلنة بهذا الشكل تسمى مصفوفة ستاتيكية (ثابتة) وذلك لكون عدد عناصرها ثابت من وقت الإعلان عنها.
الحل في هذه الحالة هو حجز المصفوفة ديناميكياً. وذلك يتم عن طريق استخدام الإجراء malloc. الذاكرة التي يحجزها malloc تأتي من خارج ذاكرة المكدس (stack) ولذلك هي غير محكومة بحجم المكدس وإنما بذاكرة البرنامج المتاحة ككل، وهذا أفضل من حيث المقايسة (scalability)، فذاكرة المكدس لها حجم ثابت مهما كبرت ذاكرة الجهاز.
الأمر الآخر المهم عند استخدام malloc هو عدم نسيان مقابلته بنداء للإجراء free بعد اكتمال حاجتك للذاكرة المحجوزة. حيث أن هذه الذاكرة لا يتم تحريرها تلقائياً كما يحدث في المصفوفات الثابتة، والتي تتحرر بمجرد مغادرة الإجراء الذي يحويها.
عند نسيان نداء free يحدث ما يُعرف بتسريب الذاكرة (memory leak) وذلك لأنك شغلت مقداراً من الذاكرة ثم نسيت أو فقدت القدرة على تحريره، ولن تستطيع الاستفادة منه لاحقاً.
المثال كالآتي:

int len = 10; /* أو أي حسبة تحتاجها */
char *text=malloc(len*sizeof(char));
strcpy(text,"Hi");
free(text);
أرجو أن تكون قد وضحت الفكرة لتحسين برنامجك 🙂

وسام البهنسي
مبرمج في إنفيديا وإنفريمز