2015-10-08 2 views
0

Я извиняюсь за то, что сожалею, если мои вопросы несколько расплывчаты;Использование realloc в 2D-массиве c

мне нужно использовать перераспределить на 2D массива без потери его предыдущих данных, у меня есть эта функция в моей программе, чтобы сделать это:

void modifyMatrix(int **iMat, int iRow, int iRow2, int iCol) 
{ 
    int i; 
    iMat = (int**)realloc(iMat, (iRow2)*sizeof(int*)); 
    for(i=iRow; i<iRow2; i++) 
    { 
     iMat[i]=NULL; 
    } 
    for(i=0; i<iRow2; i++) 
    { 
     iMat[i]=(int*)realloc(iMat[i], (iCol)*sizeof(int)); 
    } 
} 

Где IRow оригинального размера и IRow 2 & iCol являются новый размер и все они попадают в другое место в программе.

Когда я пытаюсь распечатать матрицу, я получаю ненужные данные или значения памяти в добавляемых строках и столбцах, что я делаю неправильно?

Сообщите мне, если вам нужен полный код или какие-либо другие вопросы для уточнения, спасибо заранее!

Edit: Ниже вы можете увидеть код, я использую для создания Matrix

Мой плохо, я думаю, что я должен был добавить, что матрица уже создана в другом месте в программе, с помощью этой функции я нахожусь просто пытается изменить размеры, спасибо за быстрый ответ кстати !, ниже вы можете найти функцию, с которой я создаю массив

void createMatrix(int ***iMat, int iRow, int iCol) 
{ 
    int **iRow2 = (int**)calloc(iRow, sizeof(int*)); 
    int i; 
    for (i=0; i<iRow; i++) 
    { 
     iRow2[i] = (int*)calloc(iCol, sizeof(int)); 
    } 
    *iMat=iRow2; 
} 

Кроме того, я могу использовать только массив я уже создан, чтобы сделайте это, я не могу создать временный (который, как я знаю, был бы простым способом сделать это)

+1

Вам не нужно использовать '(int **) realloc ...'. –

+0

Почему бы * не * быть ненужными данными в новых строках и столбцах? – immibis

+0

Я заполняю новые пробелы циклом, я изолировал проблему от этой части кода, но я не могу ее найти, как ни странно, если я просто добавлю 1 столбец и 1 строку, это отлично работает или я делаю матрица меньше работает отлично, но когда я пытаюсь добавить более 1 строки или столбца, я получаю ошибку – gabevt

ответ

0

В c переменные передаются по значению, из-за этого iMat внутри modifyMatrix() не изменяет значение в функции вызывающего абонента.

Вам нужно передать адрес iMat вместо

void modifyMatrix(int ***iMat, int iRow, int iRow2, int iCol) 
{ 
    int i; 
    int **safe; 

    safe = realloc(*iMat, iRow2 * sizeof(int *)); 
    if (safe == NULL) 
     return; 
    *iMat = safe; 

    for (i = 0 ; i < iRow ; i++) 
    { 
     int *keep_old_pointer; 
     keep_old_pointer = realloc(safe[i], iCol * sizeof(int)); 
     if (keep_old_pointer == NULL) 
      do_something_allocation_failed(); 
     safe[i] = keep_old_pointer; 
    } 

    for (int i = iRow ; i < iRow2 ; ++i) 
     safe[i] = malloc(iCol * sizeof(int)); 
} 

Кроме того, не следует назначать NULL каждый элемент, а затем попытаться realloc(), потому что если realloc() имеет смысл в этой ситуации, то вы перезаписать указатели с NULL, не освобождая их.

И не переписывайте указатель ed realloc(), прежде чем проверять, было ли выделение успешным, потому что если он не удастся, вы не сможете освободить предыдущий указатель, потому что вы потеряли бы ссылку на него, вызвав утечку памяти.

+0

Плохо, я думаю, я должен был добавить, что Matrix уже создана в другом месте программы, с этой функцией я просто пытаюсь изменить размеры, спасибо за быстрый ответ btw! , Я добавил код, с помощью которого я создаю матрицу – gabevt

+2

, если 'iRow2> iRow', более поздний' safe [i] 'будет неинициализирован и передан' realloc'. Существует утечка памяти, если 'iRow2 mch

0

При успехе realloc освобождает указатель, который вы передаете ему, и возвращает указатель на вновь выделенную память. Вы получаете «нежелательные значения», потому что разыменование указателя на освобожденную память - это неопределенное поведение.

Это некрасиво, но способ исправить это (как указывал другой ответ) - передать тройной указатель (int***). Таким образом, функция может изменить исходное значение указателя. Вот как вы имитируете ссылочную семантику в C, которая является строго языком «pass by value».

void modifyMatrix(int ***iMat, int iRow, int iRow2, int iCol) 
{ 
    int i; 
    int **newMatrix = realloc(*iMat, iRow2 * sizeof(int*)); 
    if (newMatrix == NULL) { 
      /* handle realloc error here */ 
    } 
    else { 
      *iMat = newMatrix; /* assign pointer to the new memory */ 
    } 

    for(i=iRow; i<iRow2; i++) 
    { 
     (*iMat)[i]=NULL; 
    } 

    for(i = 0; i < iRow2; i++) 
    { 
     int* newRow = realloc((*iMat)[i], (iCol)*sizeof(int)); 
     if (newRow == NULL) { 
       /* handle realloc error here */ 
     } 
     else { 
       (*iMat)[i] = newRow; 
     } 
    } 
} 

Вы также должны добавить некоторые проверки ошибок. Если realloc не работает и возвращает указатель NULL, вы только что создали утечку памяти: у вас больше нет прежнего значения указателя.

Обратите внимание, что я удалил все ваши приведения. Это плохая практика to cast the return of malloc and friends в C.

+0

каждый 'iMat [i]' должен быть '(* iMat) [i]'. закомментированный цикл имеет одну цель: он инициализирует указатель, который будет передан 'realloc', иначе вы передадите ему неинициализированный указатель. – mch

+0

@mch Спасибо. Я скорректировал код. –

+0

Должен ли я вызвать функцию как modifyMatrix (& iMat, iRow, iRow2, iCol); ? На самом деле не использовали тройной указатель, который много – gabevt

0

Когда вы передаете массив указателей на функцию до realloc, у вас в основном есть 2 варианта; (1) передают адрес массива функции (то есть &array) в качестве параметра, то есть определение функции будет reallocfoo (int ***array, size_t* size) или (2) назначить возврат функции в вызывающей процедуре. (например, array = reallocfoo (array, &size);)

Поскольку вам уже даны ответы на (1), давайте посмотрим, как вы будете реализовывать и использовать (2). Примечание: нет необходимости делать вашу функцию type из массива, он просто возвращает адрес памяти, поэтому использование указателя общего назначения void в порядке. Например:

void *xrealloc2 (void **memptr, size_t *n) 
{ 
    void *tmp = realloc (memptr, *n * 2 * sizeof tmp); 
    if (!tmp) { 
     fprintf (stderr, "%s() error: virtual memory exhausted.\n", __func__); 
     return NULL; 
    } 
    memptr = tmp; 
    memset (memptr + *n, 0, *n * sizeof tmp); 
    *n *= 2; 

    return memptr; 
} 

Также примечания поскольку вы перераспределить массив указателей, нет необходимости передавать размер шрифта (указатель указатель является указатель - во всех случаях мы заботимся о Вот). Положив это на работу, поскольку вы не передаете адрес своего массива, вам нужно будет назначить возврат для завершения перераспределения. (Много, как вы делали в коде выше) например .:

if (ridx == rmax) /* if realloc is needed */ 
    ia = xrealloc2 ((void **)ia, &rmax); 

Примечание: текущее количество указателей (rmax) передается как указатель, поэтому его значение может обновляться в два раза тока в функции перераспределения. (поэтому, когда вы закончите в следующий раз, вы можете перераспределить на основе правильного обновленного текущего номера). Соединяя все части вместе, вы получите короткий пример, который просто заставляет перераспределять два раза. Кроме того, исходное распределение также помещается в функцию, чтобы сохранить основную часть кода в порядке, а возврат проверяет распределение в функции. (Вы можете решить, как вы справляетесь исчерпание памяти - NULL возврата или exit, примеры и показаны в двух функциях)

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

#define RMAX 2 
#define COLS 5 

void *xcalloc (size_t n, size_t s); 
void *xrealloc2 (void **memptr, size_t *n); 

int main (void) { 

    int **ia = NULL; 
    size_t rmax = RMAX; 
    size_t rows = 0; 
    size_t ridx = 0, cidx = 0; 

    srand (2275311); /* arbitrary repeatable seed */ 

    ia = xcalloc (RMAX, sizeof *ia); 

    /* intentionally force reallocation */ 
    while (ridx < 3 * RMAX) { 
     ia[ridx] = xcalloc (COLS, sizeof **ia); 

     for (cidx = 0; cidx < COLS; cidx++) 
      ia[ridx][cidx] = rand() % 1000 + 1; 

     ridx++; 
     if (ridx == rmax) 
      ia = xrealloc2 ((void **)ia, &rmax); 
    } 
    rows = ridx; 

    printf ("\n the reallocated 2D array elements are:\n\n"); 
    for (ridx = 0; ridx < rows; ridx++) { 
     for (cidx = 0; cidx < COLS; cidx++) 
      printf (" %4d", ia[ridx][cidx]); 
     putchar ('\n'); 
    } 
    putchar ('\n'); 

    for (ridx = 0; ridx < rows; ridx++) 
     free (ia[ridx]); 
    free (ia); 

    return 0; 
} 

/** xcalloc allocates memory using calloc and validates the return. 
* xcalloc allocates memory and reports an error if the value is 
* null, returning a memory address only if the value is nonzero 
* freeing the caller of validating within the body of code. 
*/ 
void *xcalloc (size_t n, size_t s) 
{ 
    register void *memptr = calloc (n, s); 
    if (memptr == 0) 
    { 
     fprintf (stderr, "%s() error: virtual memory exhausted.\n", __func__); 
     exit (EXIT_FAILURE); 
    } 

    return memptr; 
} 

/* realloc array of pointers ('memptr') to twice current 
* number of pointer ('*nptrs'). Note: 'nptrs' is a pointer 
* to the current number so that its updated value is preserved. 
* no pointer size is required as it is known (simply the size 
* of a pointer 
*/ 
void *xrealloc2 (void **memptr, size_t *n) 
{ 
    void *tmp = realloc (memptr, *n * 2 * sizeof tmp); 
#ifdef DEBUG 
    printf ("\n reallocating %zu to %zu\n", *n, *n * 2); 
#endif 
    if (!tmp) { 
     fprintf (stderr, "%s() error: virtual memory exhausted.\n", __func__); 
     return NULL; 
    } 
    memptr = tmp; 
    memset (memptr + *n, 0, *n * sizeof tmp); 
    *n *= 2; 

    return memptr; 
} 

После компиляции кода и запустить его, он подтвердит, что вместо того, чтобы просто максимальные 2 строк (указатели), первоначально выделенные, перераспределение происходит в два раза увеличивая их число до 8 (например 2->4->8), так что все 6 рядов чисел, присвоенных правильно выделяются:

the reallocated 2D array elements are: 

    155 573 760 410 956 
    553 271 624 625 934 
    259 291 811 161 185 
    756 211 16  6 449 
    124 869 353 210 317 
    310 181 897 866 831 

Если у вас есть какие-либо вопросы, дайте мне знать. Не забывайте, что всегда запускайте любой код, который выделяет или перераспределяет через valgrind (или аналогичную программу проверки памяти), чтобы обеспечить правильное использование вашей памяти и освободить всю память, которую вы выделяете.

==29608== Memcheck, a memory error detector 
==29608== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al. 
==29608== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info 
==29608== Command: ./bin/realloc2d 
==29608== 

the reallocated 2D array elements are: 

<snip> 

==29608== 
==29608== HEAP SUMMARY: 
==29608==  in use at exit: 0 bytes in 0 blocks 
==29608== total heap usage: 9 allocs, 9 frees, 232 bytes allocated 
==29608== 
==29608== All heap blocks were freed -- no leaks are possible 
==29608== 
==29608== For counts of detected and suppressed errors, rerun with: -v 
==29608== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) 

Вы можете скомпилировать код выше с -DDEBUG флагом, чтобы распечатать на stdout каждый раз, когда он перераспределяет и обеспечить текущее количество указателей, выделенных. Удачи.

Смежные вопросы