Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
Форум программистов > C/C++: Общие вопросы > Считывание файла неизвестного размера в массив |
Автор: StealtH 18.5.2007, 18:53 | ||||||
Задача одновременно проста, но оказалась сложной, суть ее такова: Есть файл(ы) который нужно прочитать построчно в массив, а потом работать уже с массивом, количество строк в файле - неизвестно. Соответственно массив должен быть динамическим и колчиство его элементов должно меняться при чтении файла. Перерыл весь гугл(и этот форум в том числе) в поисках работающего примера(даже некоторую его зарубежную часть) но ничего толком работающего не нашел, почитал маны и написал сам(код приведен ниже). но программа не работает, на выходе массива нет, мои подозрения падают на realloc и выделение памяти под массив, но где именно и что я делаю не так не могу понять. Народ, помогите найти багу, ибо сил моих уже боротся с ней нету. Я закомментировал код, так как я думаю, что там происходит, если у меня ход мысле не правильный ткните носом в ошибку, в понимании чего именно я ошибаюсь. Компилятор:
команда компиляции
Сразу замечу, что код желательно напистаь на C(не С++), и под *NIX системы.
ЗЫ: Просьба не посылать к манам, ибо уже они мне сняться. ![]() |
Автор: Anikmar 18.5.2007, 18:59 | ||
Не проще ли воспользоваться вектором? Для таких целей - самое то. Упс.. Не заметил Сразу замечу, что код желательно напистаь на C(не С++), и под *NIX системы. Добавлено через 9 минут и 49 секунд Этот участок мне не понятен:
Получается что весь массив заполнен одним и тем же указателем на str Чтобы записать строку в массив ее надо посимвольно скопировать, тем же strcpy Добавлено через 14 минут и 25 секунд Если использовать чистый Си приходят в голову следующие варианты решения: 1. Считать весь файл целиком, а потом уже считать в считанном куске количество строк, выделять массив указателей на строки, заполнять его построчно. Подходит, если точно известно, что файл разумного размера. 2. Считывать построчно, задавая максимально возможный размер строки (как это сделано), но для хранения использовать связанный список 3. Написать что-то вроде STL-овского вектора (если нужен именно Си) |
Автор: Anikmar 18.5.2007, 19:39 | ||
Посмотрел я код внимательнее и увидел там не один, а несколько багов Скидываю подправленный вариант:
Какие баги в вашем коде я увидел (и исправил): 1. array = ( char**)realloc(array, sizeof(char*)); Данная функция, на сколько я помню, увеличивает массив не на указанную величину, а до указанной величины - т.е. надо задавать новый размер массива 2. array[i] = ( char*)malloc(strlen(str)+1); У нас первое значение i будет 1 - потеряется нулевой элемент - так как i инкрементируется до этого 3. array[i] = str; Так строки не копируется - этим вы копируете указатель на ваш статический массив 4. for(j=0; i<=j; j++){ Посмотрите внимательно на условие цикла. Вы перепутали переменые. |
Автор: Fazil6 18.5.2007, 19:41 | ||
здесь не растягивание. Память может выделяться каждый раз в новом месте и для помимо realloc нужно еще копировать содержимое в новое место. Прочитай файл вхолостую чтобы узнать количество строк , выдели array и потом пройди заново считывая в него строки |
Автор: Fazil6 18.5.2007, 19:49 | ||
ну да... погорячился. |
Автор: StealtH 18.5.2007, 23:57 | ||||
![]() Громадное спасибо, код реально поправил положение дел, я кстати грешил на инкрементную переменную и связанные с ней моменты , даже делал в цикле проверку на наличие в array(i-1) данных - они там там были в период прохождения цикла по файлу array(i-2) - вызывали Segmentation fial, а по поводу переменных в последнем цикле - это даже от себя такой баги не ожидал, если честно долго смеялся сам над собой когда понял. Цитируемый код заработал сразу, но это по сути небольшая верхушка айсберга, приведенный мною пример - это код одной из функции программы, по-этому если не трудно, господа, подскажите каким образом, вернее сказать как более правильно будет организовать функцию которой передается в качестве аргумента массив и указатель на файл а возращаемым агрументом был бы массив, который содержит строки файла, без "\n". Спасибо огромное всем кто ответил! ЗЫ: Извиняюсь возможно за некоторое незнание некоторых моментов в С, о я последнюю строчку на С, написал в 99 году, по-этому сейчас спустя 8 лет достаточно сложно восстановить знания, прошу отнестись с пониманием ![]() |
Автор: Anikmar 19.5.2007, 08:16 | ||||
Я обратил внимание, что функция gets оставляет в конце строки символ \n. Если речь идет о нем - то наиболее быстрым решением я вижу простая замена его на нулевой символ. Например, в вышеприведенном коде, можно его сразу отсечь последний символ, если он '\n'
А вот на счет передачи массива в функцию: Если мы не знаем заренее сколько строк в файле, то какой массив мы должны передать? Наоборот - это функция должна возвратить считанный массив. |
Автор: Dov 19.5.2007, 10:50 | ||||
Согласен с Anikmar`ом. И указатель на файл можно не передавать. Достаточно передать только имя файла. И потом уже работать с файлом непосредственно в самой ф-ции. Можно ещё передать в ф-цию переменную, которая бы сохраняла количество строк в файле для дальнейшей работы с ними. Ну, что-нибудь такое...
|
Автор: Dov 19.5.2007, 11:20 | ||
Хотя, имхо, можно и по-другому. Например, передавать в ф-цию имя файла и адрес двумерного динамического массива, который будет формироваться в ф-ции, а возвращать количество строк этого массива. Например...
|
Автор: Syberex 23.8.2007, 10:03 | ||
//открытие текстового файла в массив
|
Автор: MAKCim 23.8.2007, 10:47 |
Syberex, нашел же тему ![]() по вопросу тут нужен mmap() |
Автор: bsa 23.8.2007, 10:50 |
Syberex, функция filelength() нестандартна. Надо пользоваться комбинацией методов класса istream: seekg(0, std::ios_base::end).tellg(). |
Автор: akizelokro 24.8.2007, 15:42 |
Пойдем по другому пути. Гонять каждый раз при обращению к диску malloc'и я бы посчитал неэкономичным. И fgets вроде бы "мылит" в массив [any] байтов не any, а до до первого '\n'. Предположим, что размер файла не важен (< размера оперативки +вирт.память). Ну, 10 Мег, которые можно выделить в памяти единым блоком. Предположим, что (как видно из обсуждения) скорость работы проги всем до фени, но пишем все равно на С. Но при этом я буду делать вид, что скорость работы важна и памяти отжирать хотелось бы поменьше. Поэтому я сведу к минимуму обращений к диску и С++ примочкам, которые удобней, но в ..ого!.. число раз медленней. тогда я бы воткнул такой алгоритм: выделил памяти(с размер файла). привел бы ее к общему знаменателю (char * s) и зачтил бы туда файл. заменил бы там '\n' на '\0', заодно подсчитав число n замен выделил бы памяти на указатели строк [n*sizeof(char *)] еще бы раз проперся по общему знаменателю и заполнил бы массив указателей строк. А лет 7 назад я не мог себе позволить выделить памяти 10 Мег под файл и усложнял подобные задачи введением буфера длиной всего 64 Кила. Потому что в DOS памяти 10 Мег не было (ехидно ухмыльнулся)/ ![]() Пятница. Машину на прикол. Всем хороших выходных = с пьянством и развратом! ![]() |
Автор: StealtH 15.9.2007, 20:29 |
akizelokro, конечно алгоритм замечательный, за тем маленьким исключением, что размер файла изначально не известен, и он может быть от 2Мб, до 2Гб, если выделять область памяти = размер файла+N байт, то реально можно положить любую машину на лопатки при встрече с громадным файлом. Язык С выбран был не случайно, т.к. подобная задача уже реализована на Perl, но нужно реальное быстродействие и наименьшее потребление ресурсов, путь по которому ты предлагаешь идти - ресурсоемкий, соответственно не подходит :(. Но все равно - спасибо за совет ![]() |
Автор: Skladnoy 16.9.2007, 00:59 | ||||
Так при работе нужно держать в памяти весь файл и работать со _всем_ его содержимым? Или хватит построчной обработки? Если файл в память не помещается - придется его читать по кускам. В лучшем случае хватит построчной обработки, в худшем придется изощрятся. Что надо с файлом делать? У меня есть подозрение, что надо не прочесть файл, а что-то более другое. P.S. может быть уже помянутый mmap спасет смертельно раненого кота? |