![]() |
Модераторы: Daevaorn |
![]() ![]() ![]() |
|
StealtH |
|
||||||
![]() Шустрый ![]() Профиль Группа: Участник Сообщений: 124 Регистрация: 16.9.2004 Репутация: нет Всего: нет |
Задача одновременно проста, но оказалась сложной, суть ее такова:
Есть файл(ы) который нужно прочитать построчно в массив, а потом работать уже с массивом, количество строк в файле - неизвестно. Соответственно массив должен быть динамическим и колчиство его элементов должно меняться при чтении файла. Перерыл весь гугл(и этот форум в том числе) в поисках работающего примера(даже некоторую его зарубежную часть) но ничего толком работающего не нашел, почитал маны и написал сам(код приведен ниже). но программа не работает, на выходе массива нет, мои подозрения падают на realloc и выделение памяти под массив, но где именно и что я делаю не так не могу понять. Народ, помогите найти багу, ибо сил моих уже боротся с ней нету. Я закомментировал код, так как я думаю, что там происходит, если у меня ход мысле не правильный ткните носом в ошибку, в понимании чего именно я ошибаюсь. Компилятор:
команда компиляции
Сразу замечу, что код желательно напистаь на C(не С++), и под *NIX системы.
ЗЫ: Просьба не посылать к манам, ибо уже они мне сняться. ![]() |
||||||
|
|||||||
Anikmar |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2513 Регистрация: 26.11.2006 Где: Санкт-Петербург Репутация: 9 Всего: 59 |
Не проще ли воспользоваться вектором? Для таких целей - самое то.
Упс.. Не заметил Сразу замечу, что код желательно напистаь на C(не С++), и под *NIX системы. Добавлено через 9 минут и 49 секунд Этот участок мне не понятен:
Получается что весь массив заполнен одним и тем же указателем на str Чтобы записать строку в массив ее надо посимвольно скопировать, тем же strcpy Добавлено через 14 минут и 25 секунд Если использовать чистый Си приходят в голову следующие варианты решения: 1. Считать весь файл целиком, а потом уже считать в считанном куске количество строк, выделять массив указателей на строки, заполнять его построчно. Подходит, если точно известно, что файл разумного размера. 2. Считывать построчно, задавая максимально возможный размер строки (как это сделано), но для хранения использовать связанный список 3. Написать что-то вроде STL-овского вектора (если нужен именно Си) Это сообщение отредактировал(а) Anikmar - 18.5.2007, 19:02 |
|||
|
||||
Anikmar |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2513 Регистрация: 26.11.2006 Где: Санкт-Петербург Репутация: 9 Всего: 59 |
Посмотрел я код внимательнее и увидел там не один, а несколько багов
Скидываю подправленный вариант:
Какие баги в вашем коде я увидел (и исправил): 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 |
|
|||
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1653 Регистрация: 3.5.2006 Где: Минск Репутация: 35 Всего: 60 |
здесь не растягивание. Память может выделяться каждый раз в новом месте и для помимо realloc нужно еще копировать содержимое в новое место. Прочитай файл вхолостую чтобы узнать количество строк , выдели array и потом пройди заново считывая в него строки |
|||
|
||||
Anikmar |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2513 Регистрация: 26.11.2006 Где: Санкт-Петербург Репутация: 9 Всего: 59 |
А разве realloc автоматически не копирует блок, если он помещается на новое место? |
|||
|
||||
Fazil6 |
|
|||
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1653 Регистрация: 3.5.2006 Где: Минск Репутация: 35 Всего: 60 |
||||
|
||||
StealtH |
|
||||
![]() Шустрый ![]() Профиль Группа: Участник Сообщений: 124 Регистрация: 16.9.2004 Репутация: нет Всего: нет |
![]() Громадное спасибо, код реально поправил положение дел, я кстати грешил на инкрементную переменную и связанные с ней моменты , даже делал в цикле проверку на наличие в array(i-1) данных - они там там были в период прохождения цикла по файлу array(i-2) - вызывали Segmentation fial, а по поводу переменных в последнем цикле - это даже от себя такой баги не ожидал, если честно долго смеялся сам над собой когда понял. Цитируемый код заработал сразу, но это по сути небольшая верхушка айсберга, приведенный мною пример - это код одной из функции программы, по-этому если не трудно, господа, подскажите каким образом, вернее сказать как более правильно будет организовать функцию которой передается в качестве аргумента массив и указатель на файл а возращаемым агрументом был бы массив, который содержит строки файла, без "\n". Спасибо огромное всем кто ответил! ЗЫ: Извиняюсь возможно за некоторое незнание некоторых моментов в С, о я последнюю строчку на С, написал в 99 году, по-этому сейчас спустя 8 лет достаточно сложно восстановить знания, прошу отнестись с пониманием ![]() |
||||
|
|||||
Anikmar |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2513 Регистрация: 26.11.2006 Где: Санкт-Петербург Репутация: 9 Всего: 59 |
Я обратил внимание, что функция gets оставляет в конце строки символ \n. Если речь идет о нем - то наиболее быстрым решением я вижу простая замена его на нулевой символ. Например, в вышеприведенном коде, можно его сразу отсечь последний символ, если он '\n'
А вот на счет передачи массива в функцию: Если мы не знаем заренее сколько строк в файле, то какой массив мы должны передать? Наоборот - это функция должна возвратить считанный массив. Это сообщение отредактировал(а) Anikmar - 19.5.2007, 08:18 |
|||
|
||||
Dov |
|
|||
![]() аСинизатор ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1721 Регистрация: 10.5.2003 Где: Эрец-Исраэль Репутация: 15 Всего: 88 |
Согласен с Anikmar`ом. И указатель на файл можно не передавать. Достаточно передать только имя файла. И потом уже работать с файлом непосредственно в самой ф-ции. Можно ещё передать в ф-цию переменную, которая бы сохраняла количество строк в файле для дальнейшей работы с ними. Ну, что-нибудь такое...
-------------------- Тут вечности запах томительный, И свежие фрукты дешевые, А климат у нас – изумительный, И только соседи – #уевые. Игорь Губерман. |
|||
|
||||
Dov |
|
|||
![]() аСинизатор ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1721 Регистрация: 10.5.2003 Где: Эрец-Исраэль Репутация: 15 Всего: 88 |
Хотя, имхо, можно и по-другому. Например, передавать в ф-цию имя файла и адрес двумерного динамического массива, который будет формироваться в ф-ции, а возвращать количество строк этого массива.
Например...
-------------------- Тут вечности запах томительный, И свежие фрукты дешевые, А климат у нас – изумительный, И только соседи – #уевые. Игорь Губерман. |
|||
|
||||
Syberex |
|
|||
![]() Бывалый ![]() Профиль Группа: Участник Сообщений: 208 Регистрация: 15.9.2006 Где: Украина Репутация: нет Всего: нет |
//открытие текстового файла в массив
--------------------
whole power in artificial intelligences |
|||
|
||||
MAKCim |
|
|||
![]() Воін дZэна ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 5644 Регистрация: 10.12.2005 Где: Менск, РБ Репутация: 52 Всего: 207 |
Syberex,
нашел же тему ![]() по вопросу тут нужен mmap() -------------------- Ах, у елі, ах, у ёлкі, ах, у елі злыя волкі © |
|||
|
||||
bsa |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 9185 Регистрация: 6.4.2006 Где: Москва, Россия Репутация: 63 Всего: 196 |
Syberex, функция filelength() нестандартна. Надо пользоваться комбинацией методов класса istream: seekg(0, std::ios_base::end).tellg().
|
|||
|
||||
akizelokro |
|
|||
![]() Крокодил ![]() ![]() Профиль Группа: Участник Сообщений: 761 Регистрация: 30.7.2007 Репутация: 1 Всего: 5 |
Пойдем по другому пути. Гонять каждый раз при обращению к диску malloc'и я бы посчитал неэкономичным. И fgets вроде бы "мылит" в массив [any] байтов не any, а до до первого '\n'.
Предположим, что размер файла не важен (< размера оперативки +вирт.память). Ну, 10 Мег, которые можно выделить в памяти единым блоком. Предположим, что (как видно из обсуждения) скорость работы проги всем до фени, но пишем все равно на С. Но при этом я буду делать вид, что скорость работы важна и памяти отжирать хотелось бы поменьше. Поэтому я сведу к минимуму обращений к диску и С++ примочкам, которые удобней, но в ..ого!.. число раз медленней. тогда я бы воткнул такой алгоритм: выделил памяти(с размер файла). привел бы ее к общему знаменателю (char * s) и зачтил бы туда файл. заменил бы там '\n' на '\0', заодно подсчитав число n замен выделил бы памяти на указатели строк [n*sizeof(char *)] еще бы раз проперся по общему знаменателю и заполнил бы массив указателей строк. А лет 7 назад я не мог себе позволить выделить памяти 10 Мег под файл и усложнял подобные задачи введением буфера длиной всего 64 Кила. Потому что в DOS памяти 10 Мег не было (ехидно ухмыльнулся)/ ![]() Пятница. Машину на прикол. Всем хороших выходных = с пьянством и развратом! ![]() Это сообщение отредактировал(а) akizelokro - 24.8.2007, 15:50 -------------------- a = a + b; b = a - b; a = a - b; |
|||
|
||||
StealtH |
|
|||
![]() Шустрый ![]() Профиль Группа: Участник Сообщений: 124 Регистрация: 16.9.2004 Репутация: нет Всего: нет |
akizelokro, конечно алгоритм замечательный, за тем маленьким исключением, что размер файла изначально не известен, и он может быть от 2Мб, до 2Гб, если выделять область памяти = размер файла+N байт, то реально можно положить любую машину на лопатки при встрече с громадным файлом. Язык С выбран был не случайно, т.к. подобная задача уже реализована на Perl, но нужно реальное быстродействие и наименьшее потребление ресурсов, путь по которому ты предлагаешь идти - ресурсоемкий, соответственно не подходит :(. Но все равно - спасибо за совет
![]() |
|||
|
||||
![]() ![]() ![]() |
Правила форума "С++:Общие вопросы" | |
|
Добро пожаловать!
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn |
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |