Как убедиться, что следующая функция не перераспределена? - PullRequest
2 голосов
/ 30 мая 2019

Я пытаюсь сделать функцию, которая получает количество столбцов и строк (ширину и высоту), построить 2D-матрицу, а затем вернуть адрес Matrix [0] [0] обратно на указатель в исходном вызывающем объекте.-функция.

int **allocateMatrix(int width, int height) // function that allocate 
//memory for 2D matrix and check that memory allocation was successful
{
    int **Matrix;
    int row;
    Matrix = (int**)malloc(sizeof(int*)*height); 
    if (!Matrix)
    {
        printf("failed to allocate memory. this program is over.\n");
        exit(1);
    }
    for (row = 0; row < height; row++)    
    {   Matrix[row] = (int*)malloc(sizeof(int)*width);     
      if (!Matrix[row])
      { 
        printf("failed to allocate memory. this program is over.\n");
        exit(1);
      }
    }
    return Matrix;
}

во время распределения я наблюдал все это через отладчик, и он, кажется, создал слишком большую матрицу, чем я предполагал, и неожиданное поведение в целом.например: высота = 5, ширина = 5, хотя матрица [0] [30] - существует и достижима.

более того, я не уверен насчет адреса, который я возвращаю.

Ответы [ 2 ]

2 голосов
/ 31 мая 2019

Нет проблем с вашим размещением. В C, если вы выходите за границы и вам повезло, вы получаете сигнал ошибки сегментации, и программа завершает работу (если вы не установили определенный обработчик сигнала для этого сигнала), но если вы попадете в какую-то действительную память, вы получите доступ к этой памяти и риску испортить что-то.

Как говорили другие в комментариях, C не будет обнаруживать ошибки кодирования, но если вы скомпилируете с флагами -Wall -pedantic -g, компилятор выдаст несколько предупреждений, когда что-то не так, и через некоторое время он даже даст вам подсказку о том, как исправить ошибку. Узнайте также, как использовать valgrind.

1 голос
/ 31 мая 2019

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

Во-первых, нет необходимости разыгрывать возврат malloc, это не нужно. Смотрите: Я разыгрываю результат malloc? .

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

Попробуйте использовать calloc для выделения хранилища для matrix[row]. calloc устанавливает все байты, присвоенные нулю, эффективно инициализируя каждый элемент для каждой строки равным 0, предотвращая неопределенное поведение при непреднамеренном доступе неинициализированного элемента после возврата.

Собрав все части вместе, вы можете сделать что-то похожее на:

/* allocatematrix allocates storage for a width x height matrix of type int.
 * all elements are initialized zero. on success returns a pointer to pointer
 * to type, otherwise all allocations are freed and NULL is returned.
 */
int **allocatematrix (int width, int height)
{
    int **matrix;
    int row;    /* declare row in for loop declaration, unless c89 support needed */

    matrix = malloc (height * sizeof *matrix);  /* allocate pointers */
    if (!matrix) {                  /* validate */
        perror ("malloc-matrix");   /* malloc failure set errno, use it */
        return NULL;                /* evaluate return in caller */
    }

    for (row = 0; row < height; row++) {    /* for each pointer */
        matrix[row] = calloc (width, sizeof *matrix[row]);  /* alloc rows */
        if (!Matrix[row]) {         /* validate */
            perror ("calloc-matrix[row]");  /* ditto for calloc */
            while (row--)           /* loop over previous rows */
                free (matrix[row]); /* free previously allocated rows */
            free (matrix);          /* free pointers */
            return NULL;            /* evaluate return in caller */
        }
    }

    return matrix;  /* return initial pointer address */
}

( примечание: , хотя и не является ошибкой, C обычно избегает использования camelCase или MixedCase имен переменных и функций в пользу всех строчных букв при резервировании заглавные имена для использования с макросами и константами. Это вопрос стиля - так что это полностью ваше дело)

( также обратите внимание: использование perror вместо printf для сообщения об ошибках. Когда функция устанавливает errno при сбое, следует использовать perror. Далее она уже обеспечивает вывод на stderr. Если при сбое, когда errno не установлено, используйте fprintf (если требуется преобразование) или fputs в противном случае и сообщите об ошибке на stderr вместо stdout)

Посмотрите вещи и дайте мне знать, если у вас есть дополнительные вопросы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...