مصفوفة int مع مؤشرات في لغة C - ارتباك في تخصيص الذاكرة

StackOverflow https://stackoverflow.com/questions/105653

سؤال

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

int**       first_matrix;
int**       second_matrix;
int**       result_matrix;

int** read_matrix(int size_x, int size_y)
{
    int** matrix;
    matrix = calloc(size_x, sizeof(int*));
    for(int i = 0;i<size_x;i++) {
        matrix[i] = calloc(size_y, sizeof(int));
    }
    for(int i = 0;i<size_x;i++) {
        for(int j = 0;j<size_y;j++) {
            matrix[i][j] = i*10+j;
        }
    }
    return matrix;
}

int main(int stackc, char** stack)
{
    first_matrix = read_matrix(10,10);
    printf("9:3 %d - 4:6 %d \n", first_matrix[9][3], first_matrix[4][6]);
    free(*first_matrix);
    free(first_matrix);
    printf("9:3 %d - 4:6 %d \n", first_matrix[9][3], first_matrix[4][6]);
}
هل كانت مفيدة؟

المحلول

فقط لأنه تم تحرير الذاكرة لا يعني أنه لا يمكنك الوصول إليها!بالطبع، انها أ سيئ جدا فكرة الوصول إليه بعد أن يتم تحريره، ولكن هذا هو السبب في أنه يعمل في المثال الخاص بك.

لاحظ أن free( *first_matrix ) فقط مجانا first_matrix[0], ، وليس المصفوفات الأخرى.ربما تريد نوعًا من العلامة للإشارة إلى المصفوفة الأخيرة (إلا إذا كنت ستعرف دائمًا عند تحرير المصفوفة الخارجية عدد المصفوفات الداخلية التي خصصتها).شيء مثل:

int** read_matrix(int size_x, int size_y)
{
    int** matrix;
    matrix = calloc(size_x, 1+sizeof(int*)); // alloc one extra ptr
    for(int i = 0;i<size_x;i++) {
        matrix[i] = calloc(size_y, sizeof(int));
    }
    matrix[size_x] = NULL; // set the extra ptr to NULL
    for(int i = 0;i<size_x;i++) {
        for(int j = 0;j<size_y;j++) {
            matrix[i][j] = i*10+j;
        }
    }
    return matrix;
}

ثم عندما تحررهم:

// keep looping until you find the NULL one
for( int i=0; first_matrix[i] != NULL; i++ ) {
    free( first_matrix[i] );
}
free( first_matrix );

نصائح أخرى

تحتاج إلى تحرير كل صف على حدة:


void free_matrix(int **matrix, int size_x)
{
    for(int i = 0; i < size_x; i++)
        free(matrix[i]);
    free(matrix);
}

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

كما أنك لا تحرر كل ما خصصته.أنت تقوم فقط بتحرير مجموعة المؤشرات والصف الأول.ولكن حتى لو قمت بتحرير كل شيء بشكل صحيح، فسيظل لديك نفس التأثير.

إذا كنت تريد إنشاء "خطأ في الناقل"، فأنت بحاجة إلى الإشارة إلى الذاكرة التي لا تنتمي إلى عمليتك.لماذا تريد أن تفعل ذلك على أي حال؟

لقد قمت فقط بتحرير الصف الأول (أو العمود) من first_matrix.اكتب دالة أخرى مثل هذا:

void free_matrix(int **matrix, int rows)
{
    int i;
    for(i=0; i<rows; i++)
    {
        free(matrix[i]);
    }
    free(matrix);
}

قد ترغب في تحويل المصفوفة إلى بنية لتخزين عدد الصفوف والأعمدة الخاصة بها.

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

سام

تحصل على تسرب في الذاكرة لأنك تحرر الصف الأول من المصفوفة وقائمة الصفوف، ولكن لا شيء من الصفوف من 1 إلى n.تحتاج إلى الاتصال مجانًا في حلقة.

ومع ذلك، هناك بضعة بدائل:- تخصيص حجم (int *)صفوف + صفوفcols*sizeof(int) بايت واستخدم البايتات الأولى لمؤشرات الصف.وبهذه الطريقة ، ليس لديك سوى جزء واحد من الذاكرة لتحريره (وأسهل على المخصص ، أيضًا) - استخدم هيكلًا يحتوي على عدد الصفوف.ثم يمكنك تجنب قائمة الصفوف تمامًا (حفظ الذاكرة).الجانب السلبي الوحيد هو أنه يتعين عليك استخدام دالة أو ماكرو أو بعض الرموز الفوضوية لمعالجة المصفوفة.

إذا اخترت الخيار الثاني، يمكنك استخدام بنية مثل هذه في أي مترجم C99، ومرة ​​أخرى عليك فقط تخصيص كتلة واحدة من الذاكرة (من الحجم numints*sizeof(int)+sizeof(int)):

struct matrix {
    int rows;
    int data[0];
}

المفهوم الذي تفتقده هنا هو أنه لكل calloc، يجب أن يكون هناك free.ويجب تطبيق ذلك مجانًا على المؤشر الذي تم تمريره من calloc.

أوصيك بإنشاء وظيفة (اسمه delete_matrix) تستخدم حلقة لتحرير جميع المؤشرات التي تخصصها هنا

لـ (int i = 0 ؛ i <size_x ؛ i ++) {matrix [i] = calloc (size_y ، sizeof (int)) ؛}

ثم، بمجرد الانتهاء من ذلك، قم بتحرير المؤشر المخصص لذلك.

مصفوفة = calloc(size_x, sizeof(int*));

بالطريقة التي تفعل بها الآن،

free(*first_matrix);free(first_matrix);

لن تفعل ما تريد أن تفعله.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top