Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Прочее";
Текущий архив: 2007.10.21;
Скачать: [xml.tar.bz2];

Вниз

Массивы переменной длины в Си   Найти похожие ветки 

 
Галинка ©   (2007-09-18 14:27) [0]

У Кернигана и Ричи прочитала, что если объявлять квази-двумерный массив, как одномерный массив указателей заданного типа, то под каждым указателем можно хранить векторы разной длинны.

Все логично. Хочу попробовать прочитать числа из файла в массив. Количество чисел в каждой строке разное. Т.е. условие как бы соблюдается.

Внимание, вопрос: нужно ли (с моей точки зрения несомненно) постоянно перевыделять память под текущий указатель, перед созранением в текущий вектор нового значения?


 
umbra ©   (2007-09-18 14:32) [1]

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


 
Игорь Шевченко ©   (2007-09-18 14:32) [2]

может тебе форум по С поискать ?


 
Rouse_ ©   (2007-09-18 14:57) [3]


> может тебе форум по С поискать ?

array of PDWORD уже относится к Си? :)

> нужно ли (с моей точки зрения несомненно) постоянно перевыделять
> память под текущий указатель

Можно по аналогу TList выделять память сразу с запасом...


 
celades ©   (2007-09-18 14:58) [4]


> нужно ли (с моей точки зрения несомненно) постоянно перевыделять
> память под текущий указатель

да. используя realloc например


 
tesseract ©   (2007-09-18 15:06) [5]


> да. используя realloc например


Это школничество память перераспределять постоянно. Обычно хапаеться с избытком, при превышении лимита выделяеться ещё блок. Как например в Tlist.


 
Галинка ©   (2007-09-18 17:21) [6]

т.е. никто "не экономит на спичках"?


 
tesseract ©   (2007-09-18 17:35) [7]


> т.е. никто "не экономит на спичках"?


Выделение памяти - очень медленный процесс. Поэтому так и поступают.


 
sdubaruhnul   (2007-09-18 18:06) [8]

Постоянный realloc гадит память и постепенно снижает её эффективность, хотя с этим и борются.


 
Галинка ©   (2007-09-18 18:15) [9]

а как расчивается, какой кусок будет с избытком?


 
Kerk ©   (2007-09-18 18:18) [10]

> [9] Галинка ©   (18.09.07 18:15)

Прикинь в среднем сколько обычно нужно, столько и выделяй


 
Галинка ©   (2007-09-18 18:54) [11]

а как потом лишнее обрезать? и нужно ли?

Если мне надо прочитать из файла строки с целыми значениями, но в одной 7, в другой - 27, в третьей - 15 и т.д. То как прикидывать? Можно как то кратно? Или нужно максимальное брать?


 
Zeqfreed ©   (2007-09-18 19:26) [12]

> Галинка ©   (18.09.07 18:54) [11]

Если ты знаешь максимальное кол-во заранее и оно немногим больше среднего, то выделяй сразу максимум. Иначе см. [5].


 
tesseract ©   (2007-09-18 22:28) [13]


> Если мне надо прочитать из файла строки с целыми значениями,
>  но в одной 7, в другой - 27, в третьей - 15 и т.д. То как
> прикидывать? Можно как то кратно? Или нужно максимальное
> брать?


Почитай про алгоритм конечного автомата - про память  вопросы отсохнут как листья.


 
celades ©   (2007-09-18 22:51) [14]


> Это школничество память перераспределять постоянно.

А обучение С это и есть школьничество


 
palva ©   (2007-09-18 22:56) [15]


> Галинка ©   (18.09.07 18:15) [9]
>
> а как расчивается, какой кусок будет с избытком?

Выделять память нужно сразу на весь массив и с избытком.
Первая строка будет располагаться с начала выделенной памяти. Ее адрес, то есть адрес первого элемента заносим в массив указателей. Вторую строку располагаем сразу же за первой и ее адрес снова заносим в массив указателей. И так далее. Никаких realloc в случае переполнения делать нельзя, иначе указатели в массиве поплывут (вообще говоря), т. к. память может выделиться в другом месте. Если памяти все же не хватит, то это очень неприятно. Придется выделить очередной кусок памяти, перенести туда недовведенную строку, скорректировать последний указатель в массиве и продолжить ввод.
После ввода всего массива можно освободить неиспользованную память, для чего сделать realloc с уменьшением размера. Скорее всего (на известных мне компиляторах) память останется на прежнем месте, изменится только размер. Но этого никто не гарантирует, так что может и не стоит этого делать. Если адрес памяти изменится, то это катастрофа. Указатели в массиве окажутся не валидными.


 
Kerk ©   (2007-09-18 22:57) [16]

> [15] palva ©   (18.09.07 22:56)

Кстати да. А размер общего массива легко прикинуть по размеру файла


 
Zeqfreed ©   (2007-09-18 22:59) [17]

> palva ©   (18.09.07 22:56) [15]

В realloc нет смысла, если он перемещает начало участка памяти.


 
Галинка ©   (2007-09-19 10:59) [18]

Спасибо всем. В palva ©   (18.09.07 22:56) [15] вчера убедилась собственноручно. Кроме Access Violution ничего не дает. Пока выбрала такой алгоритм:
1) "максимальную длину" строки в нужных нам юнитах выбираем заранее и определяем через макро. Типа #define MAXVALS 200
2) максимальное число строк так же определяем заранее как #define MAXLINES 25
3) при первичной инициализации массива делаем примерно так:
int *my_arr[MAXLINES];

for(i=0; i<MAXLINES; i++)
  my_arr[i] = (int *)malloc(MAXVALS*sizeof(int));


пока вроде логично. Остается одно НО. Отслеживание реального конца строки, за которым уже идет мусор, так как заранее выделено больше памяти. Вот тут пока проблема. Пока самый простой выход - таскать за собой длину строки. Но тогда как ее хранить? Может в первом элементе. Но если массив не целых, то как тогда быть?

Короче, может кто-то примерно знает как устроены в дельфи array of ... . Там же вроде можно переустанавливать длину с помощью SetLength()? Или там тоже где-то храниться Count и просто он увеличивается?


 
Ricko ©   (2007-09-19 11:29) [19]

В C строки заканчиваются символом "\0"


 
Галинка ©   (2007-09-19 11:32) [20]

Ricko ©   (19.09.07 11:29) [19]

извини, я не корректно выразилась. Я имела в виду строку матрицы конечно.


 
palva ©   (2007-09-19 11:47) [21]

> вчера убедилась собственноручно. Кроме Access Violution ничего не дает.
Вы просто не умеете их готовить (c) Если вам не для трейнинга, а для дела, могу помочь написать правильный код. Можете посмотреть в каких-нибудь книгах по графам. Графы обычно хранят в массивах подобных вашему и при вводе графа возникают те же трудности. С языком си это никак не связано.

> Или там тоже где-то храниться Count
Конечно же где-то хранится. При реализации на си это тоже нужно где-то хранить. Можно не хранить, если само содержимое массива позволяет судить о размере. Например параметры функции main информируют о параметрах командной строки. Первый параметр - количество слов, второй параметр - как раз и есть подобный нашему "ломаный" массив символов(терминология C#). Количество символов в слове здесь не хранится, поскольку достаточно хранить в конце слова нуль-терминатор.


 
evvcom ©   (2007-09-19 11:57) [22]

Так ты в какой среде пишешь? В Си или все-таки в Delphi? Если среда от борланда, то можешь смело использовать array of array of type. Если даже возникнет необходимость увеличения размерности в какой-то строке, все корректно перевыделится, скопируется, если надо и т.п.

> определяем через макро. Типа #define MAXVALS 200

если это значение по умолчанию, так и пиши DEFVALS или DEFAULT_VALS, иначе первое, что придет в голову незнакомому с твоими идеями, твоим стилем, что это действительно максимальное значение.


 
palva ©   (2007-09-19 12:05) [23]

palva ©   (19.09.07 11:47) [21]
Про графы я там зря написал. Я посмотрел сейчас. Там везде перед вводом очередной строки (содержащей номера вершин, смежных данной) идет количество вершин, что снимает вопросы с тем, какого размера память выделять.


 
Галинка ©   (2007-09-19 12:25) [24]

palva ©   (19.09.07 11:47) [21]

можно на Ты. Это во-первых. Пока я только тренируюсь. И постараюсь таки "научиться их готовить" ))

А вот второй пункт можно подробнее. Массив вроде не класс, и не структура. тогда как можно хранить в одном месте разнотипные данные? Например, в дельфи насколько мне помнится было что-то подобное:

var
koeff_ty : array of float;
max_k, i : integer;
basis_koeff: float;

begin
write("Введите длину массива: "); readln(max_k);
i=0;
while(i<max_k)
begin
 SetLength(koeff_ty, i+1);
 koeff_ty[i] = basis_koeff + .0025;
  i++;
end;
end;


или для матрицы

var
myFile : TextFile;
koeff_ty : array of array of float;
i, j : integer;
c_str, str_chis: string;

begin
i=0; j=0;
AssignFile(myFile, "koeef_ty.dat");
while(not EOF(myFile))
begin
  readln(myFile, c_str);
  SetLength(koeff_ty, i+1);
  while(pos(" ", c_str) <> 0)
    begin
       SetLength(koeff_ty[i], j+1);
       str_chis = copy(c_str, 0, pos(" ", c_str) - 1);
       koeff_ty[i, j] = StrToFloat(str_chis);
       c_str = copy(c_str, pos(" ", c_str) + 1, length(c_str) - pos(" ", c_str));
       j++;
    end;
  i++;
end;
end;



(за правильность кода не ручаюсь, на дельфи уже года четыре не пишу).

Так вот как это может быть реализовано?


 
Галинка ©   (2007-09-19 12:27) [25]

я пишу на Си в Eclipse.


 
palva ©   (2007-09-19 13:33) [26]

Галинка ©   (19.09.07 12:25) [24]
Массив должен хранить однотипные данные. На то он и массив. Для хранения разнотипных данных предназначены структуры в си и записи в делфи. Для хранения твоей строки можно использовать такую структуру:

struct {int n; float *f;}
Здесь n будет хранить количество чисел в строке, f - указатель на первое число.

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

Как это реализовать - это я сейчас попробую набросать пример на Borland c.


 
Галинка ©   (2007-09-19 14:03) [27]

Спасибо тебе большое.

Я так поняла, мне надо будет еще некоторое время привыкать, что записи:

int y[5];

&

int *y = malloc(5*sizeof(int));

отражают один и тот же процесс. И в результате в обоих случаях допустимо потом обращение y[index] при index<5.


 
Галинка ©   (2007-09-19 14:05) [28]

И кстати, насколько критично долго идет перераспределение памяти на современном железе?


 
palva ©   (2007-09-19 14:39) [29]

palva ©   (19.09.07 13:33) [26]

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

int main() {
 struct zeile {int n; double *r;} *mat;
 int i, k, n, ii, jj;
 char buf[200], *pch;
 printf("Input number of string: ");
 gets(buf);
 n = atoi(buf);
 mat = malloc(n * sizeof(*mat));
 printf("Now input strings.\n");
 for(ii = 0; ii < n; ii++) {
   gets(buf);
   k = 0; /* count of numbers in string */
   for(i = 0; buf[i]; i++)
     if(buf[i]!=" " && (i==0 || buf[i-1]==" ")) k++;
   if(!k) break;
   mat[ii].n = k;
   mat[ii].r = malloc(k*sizeof(double));
   pch = strtok (buf," ");
   jj = 0;
   while (pch != 0) {
     mat[ii].r[jj++] = atof(pch);
     pch = strtok(NULL, " ");
   }
 } /* end of input */
 /* test of input (may be another) */
 printf("%lf\n", mat[0].r[0]);
 printf("%lf\n", mat[1].r[1]);
 /* free memory */
 for(i=0; i<n; i++) free(mat[i].r);
 free(mat);
 return 0;
}


 
evvcom ©   (2007-09-19 14:52) [30]


> И кстати, насколько критично долго идет перераспределение
> памяти на современном железе?

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


 
palva ©   (2007-09-19 14:52) [31]

> отражают один и тот же процесс. И в результате в обоих случаях допустимо потом обращение y[index] при index<5.

Обращение такое допустимо в том и другом случае. Но процессы это разные. В первом случае память под массив выделяется в стеке. Во втором случае в стеке выделяется память под указатель на массив, а память под массив выделяется в куче. В первом случае память автоматически освободится при выходе из функции. Во втором случае необходимо позаботиться об освобождение памяти, которая взята из кучи, то есть явно написать free(y);

> И кстати, насколько критично долго идет перераспределение памяти на современном железе?
Не думаю, что надо обращать внимание на время этого действия, если это происходит вместе с такой медленной операцией как ввод. Другое дело, что может возникнуть сильная фрагментация кучи, но это зависит от того, как реализован менеджер кучи.


 
Галинка ©   (2007-09-19 18:53) [32]

А как делать дефрагментацию? И можно ли? Пока нашла, что за это под виндой в большей степени отвечает менеджер кучи компилятора. А где найти, как с этой проблемой справляется gcc? Потому как пишу под ним, в теории под Линухом.


 
Галинка ©   (2007-09-19 18:56) [33]

И все же в варианте нахождения подстроки, например, мне видится только перераспределение памяти. Например вот так:
char *substrcpy(char *src, int start, int count){
char *new_line = NULL;
int cc = start;
int i = 1;
while(src[cc] != "\n" && src[cc] != 0 && cc<start+count){
 new_line = realloc(new_line, i*sizeof(char));
 if(!new_line) exit(1);
 new_line[i-1]= src[cc];
 cc++;
 i++;
}
new_line[i-1] = "\0";

return new_line;
}


Кажется очень правильным такое решение. Поругайте, если что не так ))


 
palva ©   (2007-09-19 20:01) [34]


palva ©   (19.09.07 14:39) [29]
> mat[ii].r = malloc(k*sizeof(double));

У меня здесь ошибка. Надо так.
mat[ii].r = malloc(k*sizeof(struct zeile));

> А как делать дефрагментацию? И можно ли?
Нельзя, не предусмотрено. Не изменять же после дефрагментации все полученные указатели на память и все, что вычислялось с их помощью. Всякие искусственные приемы применяются, и даже функции есть, которые помогают уменьшить дефрагментацию. Но эти функции не стандартизованы.

> Кажется очень правильным такое решение.
Мне тоже кажется правильным. Большинство менеджеров кучи пытается сделать realloc на том же месте. Но все же стоит по возможности избегать realloc, и если есть возможность предварительно вычислить размер, то вычислить, даже если алгоритм такого вычисления будет нетривиальным.


 
Zeqfreed ©   (2007-09-19 21:21) [35]

> Галинка ©   (19.09.07 18:56) [33]

Гм. Как я понимаю, ф-ция возвращает подстроку не более count символов начиная со start до первого перевода строки?

#define _GNU_SOURCE

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

char *substr(char *src, int offset, int count)
{
   char *start = src + offset;
   char *p = start;

   while (p - start < count && *p != "\n" && *p != 0) p++;
   return strndup(start, p - start);
}


 
Галинка ©   (2007-09-19 23:13) [36]


> Zeqfreed ©   (19.09.07 21:21) [35]
>
> > Галинка ©   (19.09.07 18:56) [33]
>
> Гм. Как я понимаю, ф-ция возвращает подстроку не более count
> символов начиная со start до первого перевода строки?
>


ну не совсем. Просто если встречается символ перевода строки или ноль, то не нужно считать дальше count, так как строка все равно кончилась. Т.е. если из строки длинной в 10 скажем символов, хотят вырезать пять, начиная с 7, то вырежут только 4. Чтобы мусор не таскать за собой. Потому что строки из файла пока читала через fgets. А там нужна фиксированная длина. Ну в смысле с запасом на самую длинную строку.


 
Галинка ©   (2007-09-19 23:34) [37]

Вот что нашла в королевстве:

http://www.delphikingdom.com/asp/viewitem.asp?catalogid=1011

Это полезно? Стоит поковыряться и разобраться?


 
Галинка ©   (2007-09-19 23:44) [38]

Если еще кто что встретит, то киньте ссылкой. Почитать и понять хочется. пока пошла читать исходник на дельфи?

ПыСы:
- На каких иностранных языках говорите?
- Си, Паскаль, Ява...

:-))))


 
Zeqfreed ©   (2007-09-20 06:18) [39]

> Галинка ©   (19.09.07 23:13) [36]

Подход из [35] отбраковала? Ну-ну, пиши тогда менеджер памяти :)

А для твоей задачи совсем не нужно его писать. По двум причинам: 1) готовый лучше 2) он достаточно неплох.

Приведи полностью твою задачу. Я вечерком хоть пальцы разомну :)


 
имя   (2007-09-20 09:58) [40]

Удалено модератором



Страницы: 1 2 вся ветка

Форум: "Прочее";
Текущий архив: 2007.10.21;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.57 MB
Время: 0.057 c
6-1172175913
NikOracul
2007-02-22 23:25
2007.10.21
Как программно создать модемное соединение с интернетом?


2-1190796642
F@T@L_Err0r
2007-09-26 12:50
2007.10.21
TColor


15-1190375811
sTEPler
2007-09-21 15:56
2007.10.21
юникс


2-1190627331
АндрейК
2007-09-24 13:48
2007.10.21
множественный выбор в DBGrid


15-1189280424
Kostafey
2007-09-08 23:40
2007.10.21
Авотматизация конфигурации





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский