Динамическое размещение 2-мерного массива в c / linux - PullRequest
1 голос
/ 05 июня 2011

Я просто не могу понять, как сделать malloc. Следующий код просто набирает первые 5 строк, а затем останавливается, любая помощь приветствуется!

// Read query points from query file------------------------------
double **queryPoint;

token=(char*)malloc(40);
int qp_count=0;

i=0;
qp_count=0;
while(fgets(line,sizeof(line),queryFile)!=NULL)
{
    queryPoint=(double*)malloc(sizeof(double**));
    queryPoint[qp_count]=(double*)malloc(sizeof(double*)*2);

    printf("line:%s",line); 

    token = strtok(line," ,\t");        

    queryPoint[qp_count][0]=atof(token);        
    token = strtok(NULL, " ,\t");

    printf("l[%d]=%lf \n",qp_count,queryPoint[qp_count][0]);

    queryPoint[qp_count][1]=atof(token);
    token = strtok(NULL, " ,\t");
    printf("l[%d]=%lf \n",qp_count,queryPoint[qp_count][1]);

    qp_count++;
}

{ Это форма файла запроса

9.85797 5.72533
9.58711 2.09899
2.28203 7.19344
4.49096 5.50094
6.05297 1.60751
6.19901 1.52312

} ... Всего 30 строк

Ответы [ 8 ]

4 голосов
/ 05 июня 2011
queryPoint=(double*)malloc(sizeof(double**));
queryPoint[qp_count]=(double*)malloc(sizeof(double*)*2);

Вы явно запутались в приведении, размерах и других свойствах malloc, поэтому давайте начнем с синтаксиса правильного malloc.

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

Теперь общий синтаксис malloc таков:

TYPE* pointer = malloc(n * sizeof(TYPE));

Где TYPE - некоторый тип.sizeof всегда должен быть на один уровень косвенности меньше указателя, на который вы размещаете.(Так что TYPE** даст вам маллок TYPE*).n - это количество блоков такого размера, которое нужно выделить, поэтому, если вы хотите выделить 100 дублей, это n.

В любом случае вы объявили double** queryPoint;, поэтому ваш первый malloc должен быть:

queryPoint = (double**) malloc(some_size*sizeof(double*));

Это дает нам массив указателей размером some_size.Как и любой другой массив, вы можете realloc сделать это так, как вам нужно, хотя предварительное определение суммы, вероятно, идеально.Затем для каждой строки, которую вы хотите выделить, вы просто выбираете смещение из queryPoint и выделяете массив значений типа double, на которые указывает этот конкретный указатель, например:

queryPoint[i] = (double*) malloc(sizeof_this_array*sizeof(double));

Затем, доступ к определенномуточка в двумерном массиве задается двумя индексами: queryPoint [x] [y];

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

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

|Address      | Contents      | Comments
|-------------|---------------|-------------------------
|0x12345      | 0x20000       | double** queryPointer
| ...         | ...           | ...
|0x20000      | 0x30000       | double* queryPointer[0]
|0x20001      | 0x30016       | double* queryPointer[1]
|0x20002      | 0x30032       | double* queryPointer[2]
| ...         | ...           | ...
|0x30000      | 0183737722122 | These together make up the floating 
|0x30001      | 0183737722122 | point at double queryPointer[0][0]
|0x30002      | 0183737722122 |
| ...         | ...           | ...
|0x30016      | 0183737722122 | These together make up the floating 
|0x30017      | 0183737722122 | point at double queryPointer[0][1]
|0x30018      | 0183737722122 |
| ...         | ...           | ...

Указатель - это просто адрес, содержащий адрес, поэтому 0x12345 просто указывает на начало набора адресов с первого malloc.Это массив указателей, то есть просто набор адресов памяти, содержащих адреса памяти, которые указывают на фактические значения, как показано в диапазоне 0x3***.Обратите внимание, что все размеры адресов, размеры данных и представления значений в значительной степени являются мусором.

Это то, что происходит .

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

3 голосов
/ 05 июня 2011

Инициализировать в начале:

double **queryPoint = 0;
int qp_count = 0;

За каждую линию звонка:

// call realloc to make the space for points larger by one element
queryPoint = realloc(queryPoint, sizeof(double*)*(qp_count+1));

// allocate space for the new point
queryPoint[qp_count] = malloc(sizeof(double)*2);

// increase the point count
qp_count++;

Обратите внимание, что вы можете использовать realloc, чтобы изменить размер пространства для строк. Также обратите внимание, что вы должны добавить обработку ошибок.

Для освобождения памяти необходимо позвонить:

for(int i=0;i<qp_count;i++)
    free(queryPoint[i]);

free(queryPoint);
0 голосов
/ 05 июня 2011

Сколько байтов вы ожидаете выделить для этого вызова?

queryPoint=(double*)malloc(sizeof(double**));

Сколько на самом деле вам дал malloc ()?

Это дало вам сколько угодно байтов в void *, вероятно, восемь на 32-битной машине.

Что здесь происходит?

queryPoint[qp_count]=(double*)malloc(sizeof(double*)*2);

Вы сохраняете прямо в queryPoint, накладывая указатель, который malloc () дал вам в предыдущей строке. Это то, что вы намерены?

0 голосов
/ 05 июня 2011

Вы должны сначала определить более точно, что вы пытаетесь сделать.

Вы не знаете, сколько строк в файле, поэтому вы изначально не знаете, сколько строк должно иметь двухмерный массив. Начальная проблема / вопрос швы поддельные. Двумерный массив не подходит для таких условий.

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

0 голосов
/ 05 июня 2011

Утечка пространства, выделенного линией token = malloc(40);;это нехорошо.

Вы не показываете определение line.

Каждый раз при цикле вы теряете пространство, ранее выделенное для queryPoint.

Ваш кастинг на queryPoint=(double*)malloc(sizeof(double**)); неправильный;double **queryPoint; не следует присваивать double *.Мнение разделено (не обязательно равномерно) относительно того, является ли приведение хорошей идеей вообще.

Каждый раз, когда цикл проходит после первого, вы получаете доступ к пространству из области, выделенной для queryPoint.

Вы инициализируете int qp_count = 0;, а затем снова устанавливаете его на ноль с помощью qp_count = 0;, когда достаточно одного из двух назначений.

Ваш второй strtok() в цикле также может искать новую строку.

Вы не проверяете, чтобы strtok() нашел токен, либо в любое время.Вы не проверяете, что atof() прошло успешно.(На самом деле, невозможно проверить atof(); вам, вероятно, придется использовать strtod().)

0 голосов
/ 05 июня 2011

Вот как вы malloc двумерный массив:

double (*two_dim_array)[ncols] = malloc(nrows * sizeof *two_dim_array);
0 голосов
/ 05 июня 2011

Вы на правильном пути. queryPoint - это в основном массив массивов. Однако каждый раз в цикле вы заменяете предыдущий указатель queryPoint новым на один double*. На самом деле вы хотите увеличить queryPoint на один указатель:

queryPoint = (double**)realloc(queryPoint, sizeof(double*)*(qp_count+1));

(Обратите внимание, что для этого queryPoint следует инициализировать как NULL.)

Кроме того, ваше второе распределение должно быть sizeof(double)*2, а не sizeof(double*)*2.

Обратите внимание на шаблон: внутри malloc (или realloc) у нас есть sizeof(TYPE). Возвращаемое значение затем приводится к TYPE*. Например:

p = (double*)malloc(sizeof(double)*n);
pp = (double**)malloc(sizeof(double*)*n);
0 голосов
/ 05 июня 2011

Переменная queryPoint - это каждый раз выделенная комната для одного указателя, которая доступна по индексу 0 (queryPoint[0]). Вы пытаетесь адресовать память на queryPoint[qp_count]. В этом индексе нет памяти. Чтобы исправить, выделите queryPoint с таким количеством указателей, которое необходимо для чтения вашего файла.

int MAX_POINTER_COUNT = 10000 // whatever you choose
double** queryPoint=(double**)malloc(MAX_POINTER_COUNT * sizeof(double**));

Не пишите за концом массива! Это может привести к потенциальной ошибке переполнения буфера. (особенно если вы читаете данные, предоставленные извне).

...