الخطأ الذي يعطيه Valgrind حول “invalid write” يحدث عندما تحاول تغيير محتوى غير صالح لمنطقة الذاكرة. في هذه الحالة، يبدو أن المشكلة تكمن في كيفية استخدامك للدالة realloc
. دعني أشرح لك السبب وكيفية إصلاحه.
دالة realloc
تستخدم لتغيير حجم منطقة الذاكرة المخصصة سابقًا. عند استخدامها، يجب أن تحتفظ بعنوان الذاكرة الجديد الذي تعيده وتحدث المؤشر ليشير إليه. في حالتك، أنت تستدعي realloc
لكن لا تحتفظ بالعنوان الجديد، مما يؤدي إلى تسرب الذاكرة وظهور رسائل Valgrind.
-
رسم شرائط الثقة في ggplot215/03/2024
-
تأخير عرض الخطوات في C# Windows Form14/04/2024
لحل هذه المشكلة، يجب حفظ العنوان الجديد المُرجَع من realloc
في متغير مؤقت، ثم تحديث المؤشر على buffer
ليشير إلى العنوان الجديد. هناك أيضًا بعض النقاط التي يجب أن تأخذها بعين الاعتبار في الكود:
- تحقق من عودة قيمة
realloc
بالقيمةNULL
، مما يشير إلى فشل عملية إعادة التخصيص. - قم بتحديث حجم
size
بعد كل عمليةrealloc
.
إليك الكود المُصحَح:
cbool load(FILE* file, BYTE** content, size_t* length) {
*content = NULL;
*length = 0;
int size = 512;
BYTE* buffer = (BYTE*) malloc(sizeof(BYTE) * size);
if(buffer == NULL)
return false;
int bytes_read = 0;
int total_bytes_read = 0;
while((bytes_read = fread(buffer + total_bytes_read, 1, 512, file)) == 512) {
total_bytes_read += bytes_read;
size += 512;
BYTE* temp = realloc(buffer, size);
if(temp == NULL) {
free(buffer);
return false;
}
buffer = temp;
}
size = total_bytes_read;
if(size > 0) {
BYTE* minimal_buffer = malloc(size + 1);
memcpy(minimal_buffer, buffer, size);
minimal_buffer[size] = '\0';
free(buffer);
*content = minimal_buffer;
*length = size;
return true;
}
free(buffer);
return false;
}
بعد هذه التعديلات، يجب أن يعمل الكود بدون أخطاء Valgrind ويتجنب تسرب الذاكرة.
المزيد من المعلومات
بالطبع! بعض المعلومات الإضافية التي يمكن أن تكون مفيدة:
-
يُفضل استخدام
fseek
للانتقال إلى بداية الملف بعد قراءته بدلاً من استخدامrewind
، حيث يمكن أن يؤديrewind
إلى إعادة تعيين العلامات الداخلية للملف. -
لاحظ أنه يمكنك استخدام
realloc
مباشرة علىbuffer
دون الحاجة إلى تحرير الذاكرة وإعادة تخصيصها في كل دورة من دورات القراءة. -
يُفضل تحرير الذاكرة المُخصصة في حالة فشل القراءة من الملف لتجنب تسرب الذاكرة.
-
يُوصى بتحرير المساحة المُخصصة في نهاية الدالة حتى في حالة عدم وجود بيانات لتفادي تسرب الذاكرة.
-
يُفضل تحرير
buffer
بعد نسخ البيانات إلىminimal_buffer
لتجنب استهلاك زائد للذاكرة. -
تأكد من إغلاق الملف بعد الانتهاء من استخدامه باستخدام
fclose
.
هذه الإضافات تهدف إلى تحسين أداء الكود وضمان عدم حدوث تسرب للذاكرة أو أخطاء أخرى.