2d массив в C с отрицательными индексами - PullRequest
0 голосов
/ 09 августа 2011

Я пишу C-программу, где мне нужны 2D-массивы (динамически распределяемые) с отрицательными индексами или где индекс не начинается с нуля. Таким образом, для массива [i] [j] индекс строки i должен принимать значения, например, из 1-3, и индекс столбца j должен принимать значения, например, от -1 до 9.

Для этой цели я создал следующую программу, здесь переменная columns_start установлена ​​на ноль, поэтому просто смещается индекс строки, и это работает очень хорошо.

Но когда я присваиваю переменные columns_start другие значения, кроме нуля, я получаю сообщение (от valgrind), что команда "free (array [i]);" является недействительным. Итак, мои вопросы:

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

Спасибо за вашу помощь.

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

main()
{

int **array, **array2;
int rows_end, rows_start, columns_end, columns_start, i, j;

rows_start = 1;
rows_end = 3;

columns_start = 0;
columns_end = 9;

  array = malloc((rows_end-rows_start+1) * sizeof(int *));

  for(i = 0; i <= (rows_end-rows_start); i++) {
    array[i] = malloc((columns_end-columns_start+1) * sizeof(int));
  }

  array2 = array-rows_start;                          //shifting row-index

  for(i = rows_start; i <= rows_end; i++) {
    array2[i] = array[i-rows_start]-columns_start;    //shifting column-index
  }

  for(i = rows_start; i <= rows_end; i++) {
    for(j = columns_start; j <= columns_end; j++) {
      array2[i][j] = i+j;                             //writing stuff into array
      printf("%i %i %d\n",i, j, array2[i][j]);
    }
  }

  for(i = 0; i <= (rows_end-rows_start); i++) {
    free(array[i]);
  }

  free(array);

}

Ответы [ 4 ]

5 голосов
/ 09 августа 2011

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

array2[i] = array[i-rows_start]-columns_start;

array2 [i] и array [i = row_start] - это та же ячейка памяти, что и для array2, которая инициализируется массивом row_start.

Таким образом, освобождение памяти требует обратного сдвига. Попробуйте следующее:

free(array[i] + columns_start);

ИМХО, такая модификация индексов массива не дает никаких преимуществ, усложняя логику программы и приводя к ошибкам. Попробуйте изменить индексы на лету в одном цикле.

2 голосов
/ 09 августа 2011
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    int a[] = { -1, 41, 42, 43 };
    int *b;//you will always read the data via this pointer
    b = &a[1];// 1 is becoming the "zero pivot"
    printf("zero: %d\n", b[0]);
    printf("-1: %d\n", b[-1]);
    return EXIT_SUCCESS;
}

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

1 голос
/ 09 августа 2011

Насколько я вижу, ваш бесплатный и malloc выглядит хорошо.Но твое смещение не имеет смысла.Почему бы вам просто не добавить смещение в array вместо использования array2:

int maxNegValue = 10;
int myNegValue = -6;

array[x][myNegValue+maxNegValue] = ...;

таким образом, вы всегда находитесь в положительном диапазоне.

Для malloc: вы приобретаете (maxNegValue + maxPosValue) * sizeof(...)


Хорошо, теперь я понимаю, что вам нужно free(array.. + offset); даже при использовании ваших движущихся вещей ... это, вероятно, не то, что вы хотите.Если вам не нужна очень быстрая реализация, я бы предложил использовать структуру, содержащую смещение и массив.Затем создайте функцию с этой структурой и аргументами x / y, чтобы разрешить доступ к массиву.

0 голосов
/ 09 августа 2011

Я не знаю, почему valgrind будет жаловаться на это утверждение free, но, похоже, происходит много манипуляций с указателями, поэтому меня не удивляет, что вы впервые столкнулись с этой проблемой.Например, одна вещь, которая попалась на глаза, это:

array2 = array-rows_start; 

Это сделает массив2 [0] разыменовываемой памятью, которую вы не выделяли.Боюсь, это просто вопрос времени, пока вы не ошибетесь в вычислениях смещений и не столкнетесь с этой проблемой.

Один комментарий, который вы написали

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

Я думаю, что я скрыл бы все это в вспомогательной структуре matrix(+ функции), чтобы вам не приходилось загромождать код всеми смещениями.Учтите это в каком-то заголовке matrix.h:

struct matrix; /* opaque type */

/* Allocates a matrix with the given dimensions, sample invocation might be:
 *
 *    struct matrix *m;
 *    matrix_alloc( &m, -2, 14, -9, 33 );
 */
void matrix_alloc( struct matrix **m, int minRow, int maxRow, int minCol, int maxCol );

/* Releases resources allocated by the given matrix, e.g.:
 *
 *    struct matrix *m;
 *    ...
 *    matrix_free( m );
 */
void matrix_free( struct matrix *m );

/* Get/Set the value of some elment in the matrix; takes logicaly (potentially negative)
 * coordinates and translates them to zero-based coordinates internally, e.g.:
 *
 *    struct matrix *m;
 *    ...
 *    int val = matrix_get( m, 9, -7 );
 */
int matrix_get( struct matrix *m, int row, int col );
void matrix_set( struct matrix *m, int row, int col, int val );

А вот как может выглядеть реализация (это будет matrix.c):

struct matrix {
  int minRow, maxRow, minCol, maxCol;
  int **elem;
};

void matrix_alloc( struct matrix **m, int minCol, int maxCol, int minRow, int maxRow ) {
  int numRows = maxRow - minRow;
  int numCols = maxCol - minCol;

  *m = malloc( sizeof( struct matrix ) );
  *elem = malloc( numRows * sizeof( *elem ) );
  for ( int i = 0; i < numRows; ++i )
    *elem = malloc( numCols * sizeof( int ) );

  /* setting other fields of the matrix omitted for brevity */
}

void matrix_free( struct matrix *m ) {
  /* omitted for brevity */
}

int matrix_get( struct matrix *m, int col, int row ) {
   return m->elem[row - m->minRow][col - m->minCol];
}

void matrix_set( struct matrix *m, int col, int row, int val ) {
   m->elem[row - m->minRow][col - m->minCol] = val;
}

Таким образом, вам нужно толькоПолучите этот материал сразу, в центральном месте.Остальная часть вашей программы имеет дело не с необработанными массивами, а с типом struct matrix.

...