![]() |
|
Модераторы: Daevaorn |
![]()
|
|
| Code Magister |
|
|||
![]() Magister of Code ![]() Профиль Группа: Участник Сообщений: 155 Регистрация: 9.7.2004 Где: Kiev Репутация: 1 Всего: 1 |
Вот она эта функция, написаная мной. С небольшими файлами работает безотказно, НО если в файле (насколько я заметил) больше, чем 32786 строки, то прога сначала дуплится, а потом начинает выводить эту самую 32786 строку ХЗ сколько раз. В чем тут дело? Добавлено @ 02:12 И еще, если файл меньше, то она хоть и правильно, но как-то очень медленно работает. Я пытался откомпилировать это в билдере, так там вобще ошибку на стадии выполнения выдает. Это сообщение отредактировал(а) _Slipknot - 5.6.2005, 02:19 --------------------
|
|||
|
||||
| Mayk |
|
||||
![]() ^аВаТаР^ сообщение>> ![]() ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 2616 Регистрация: 22.5.2005 Где: за границей разум а Репутация: 45 Всего: 134 |
Можно сделать так: перемотать файл в конец, потом считывать с конца в буфер n-ное кол-во байт, строки из буфера в обратном порядке пихать в выходной файл. Только тут надо учитывать то, что на начало буфера выпадает середина строки. Поэтому приходится отматывать вперед, чтобы при следующем заходе прочитать всю строку.
И еще один момент - в DOS'е строка оканчивается не так как в Linux. Это может повлиять на результат. 800 килобайтный Фауст(20427 строк) перевернулся за ~0.1 секунду 3 метровый Эмбер(60895 строк) перевернулся за ~0.66 секунды.
Ну так, посмотри как ты много читаешь: допустим в файле 5 строк. Ты прочитаешь 5 строк, чтобы узнать их кол-во, затем прочитаешь 4 строки, чтобы прочитать и вывести пятую, потом три строки, чтобы вывести четвертую. В общем кол-во чтений строк - сумма арифмитической прогрессии от 1 до n, где n - кол-во строк. И это будет что-то типа S=n*((1+n)/2)=(n^2+n)/2; если я не попутал. В примере S = (25+5) / 2 = 15; да еще +5 = 20 чтений строк. А теперь пусть n=1000=10^3. S=(10^6+10^3) / 2 = 10 * (10^5 + 10^2) / 2 = 5 * 10^ 5 + 5 * 10^2 = 50500 чтений. Это много. -------------------- Здесь был кролик. Но его убили. Человеки < кроликов, йа считаю. |
||||
|
|||||
| Code Magister |
|
|||
![]() Magister of Code ![]() Профиль Группа: Участник Сообщений: 155 Регистрация: 9.7.2004 Где: Kiev Репутация: 1 Всего: 1 |
спасибо конечно за прогу, но я хочу разобратъся со своей.
можно попроще обьяснить? и как это исправить? --------------------
|
|||
|
||||
| Mayk |
|
||||
![]() ^аВаТаР^ сообщение>> ![]() ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 2616 Регистрация: 22.5.2005 Где: за границей разум а Репутация: 45 Всего: 134 |
Я привел пример как это делать быстрее.
[в прошлом посте недоквотил "в чем тут дело?"] По-проще это будет "функция fscanf вызывается СЛИШКОМ много раз, этого можно избежать". Или "алгоритм не годится для решения задачи". Те вычисления показывают что значит слово "СЛИШКОМ" и объясняют почему алгоритм не годится: Большую часть времени программа из первого листинга бегает по файлу туда-сюда, хотя этого можно избежать. Медленная работа вызвана выбором далеко не лучшего алгоритма. Кол-во fscanfов(кстати fgets() подошел бы больше) есть квадратичная функция (это показано в вычислениях). Программа из второго листинга бегает гораздо реже(и там кол-во вызовов fseek() есть линейная функция, которая кстати от кол-ва строк зависит лишь косвенно). Графики функций ax^2 и kx представляешь? -------------------- Здесь был кролик. Но его убили. Человеки < кроликов, йа считаю. |
||||
|
|||||
| __Sergey__ |
|
|||
|
Шустрый ![]() Профиль Группа: Участник Сообщений: 67 Регистрация: 21.1.2005 Репутация: нет Всего: 4 |
||||
|
||||
| Code Magister |
|
|||
![]() Magister of Code ![]() Профиль Группа: Участник Сообщений: 155 Регистрация: 9.7.2004 Где: Kiev Репутация: 1 Всего: 1 |
Mayk а что от того, что она много бегает по файлу,она зависает чтоли?
--------------------
|
|||
|
||||
| Mayk |
|
||||
![]() ^аВаТаР^ сообщение>> ![]() ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 2616 Регистрация: 22.5.2005 Где: за границей разум а Репутация: 45 Всего: 134 |
Она от этого медленно работает. А зависает от... (копаюсь)... Хм, по-моему она не зависает. Просто медленно работает, можно делать printf("%d",c); чтоб не скучно было. Теперь к дупам: Вот в 30 строчке есть
Ну если особо не вдаваться в подробности - вот здесь int заменить на unsigned long int. Кстати, только сейчас заметил, прога переворачивает слова, а не строки, а в комментариях указаны строки... И еще - cin >> way; куда указывает way? Это сообщение отредактировал(а) Mayk - 6.6.2005, 20:45 -------------------- Здесь был кролик. Но его убили. Человеки < кроликов, йа считаю. |
||||
|
|||||
| Code Magister |
|
||||||||
![]() Magister of Code ![]() Профиль Группа: Участник Сообщений: 155 Регистрация: 9.7.2004 Где: Kiev Репутация: 1 Всего: 1 |
Зависает, зацикливается на 32768 строчке. Если б проблема была только в быстродействии - для меня это не была б проблема.
Точно, с long, а i int - ща исправим.
Прога переворачивает строки. 1-я строчка станет последней, а последняя первой. Сами строчки при этом не изменятся
way - это путь файла, который мы будем переворачивать. Добавлено @ 23:38 Mayk да, проблема была именно в типе i. Кажется теперь работает, хоть и медленно. Спасибо за помощь! --------------------
|
||||||||
|
|||||||||
| Code Magister |
|
|||
![]() Magister of Code ![]() Профиль Группа: Участник Сообщений: 155 Регистрация: 9.7.2004 Где: Kiev Репутация: 1 Всего: 1 |
А насчет твоей проги. Так она переворачивает только первые 128 строк.
Как я понял она считывает файл в оперативу. Я увеличил размер
--------------------
|
|||
|
||||
| ManiaK |
|
|||
![]() Homo Sapience ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 1145 Регистрация: 3.8.2004 Где: ИУ5-93 Репутация: 5 Всего: 29 |
Помножте число на двое и вычтете единицу. Получите 0xFFFF. Это значит, что в какой-то функции происходит переполнение двухбайтовой знаковой переменной. |
|||
|
||||
| Mayk |
|
|||
![]() ^аВаТаР^ сообщение>> ![]() ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 2616 Регистрация: 22.5.2005 Где: за границей разум а Репутация: 45 Всего: 134 |
Судя по всему не понял. Приницип я уже пояснял.
Теперь проиллюстрирую работу: входной файл: --- a.txt --- AAAAAA`\n` BBBBBB`\n` CCCCCC`\n` -- eof --- Размер буфера = 10. Теперь посмотрим что прочтется из файла. --- a.txt -- AAAAAA`\n` BBBB[BB`\n` CCCCCC`\n`] --- eof --- в квадратных скобках выделено жирным то, что содержится в буфере. Теперь прочтенные строки пихаем в обратном порядку: 1) \n в конце. Все что справа пихаем в выходной файл и \n. Так как правее нет ничего, то в выходной файл идет только \n (багофича). Заменяем '\n' на 0 2) '\n' после BB. Все что правее пихаем в выходной файл + '\n'. Туда добавляется "CCCCCC\n" '\n' меняем на 0. EOL'ов больше нет. Считываем следующий блок. Так как в буфере есть два байта то теперь мы считываем не 10 байт, а только 8(таким образом мы прочитаем эту строчку полностью) --- a.txt -- AAA[AAA`\n` BBBBBB]`\n` CCCCCC`\n` --- eof --- В выходной файл идет все что правее '\n'. то есть BBBBBB. Плюс перевод строки. (кстати, теперь в выходном файле три строки: пустая, CCCCCC, BBBBBB) В буфере остается 3 байта. Мы не можем полностью заполнить весь буфер, поэтому считываем так: --- a.txt -- [AAAAAA]`\n` BBBBBB`\n` CCCCCC`\n` --- eof --- Выкидываем эту строку в выходной файл. Теперь файл перевернут -------------------- Здесь был кролик. Но его убили. Человеки < кроликов, йа считаю. |
|||
|
||||
| Code Magister |
|
|||
![]() Magister of Code ![]() Профиль Группа: Участник Сообщений: 155 Регистрация: 9.7.2004 Где: Kiev Репутация: 1 Всего: 1 |
Mayk тогда хз че она у меня не работает.
А моя уже 2-й час переворачивает 6-ти метровый файлик. Тише едешь - дальше будешь --------------------
|
|||
|
||||
| ManiaK |
|
|||
![]() Homo Sapience ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 1145 Регистрация: 3.8.2004 Где: ИУ5-93 Репутация: 5 Всего: 29 |
Вот это место. Похоже в вашем компиляторе int - двухбайтовый. Тогда, разумеется, цикл будет вечным. Замените на unsigned long int или, лучше, просто unsigned long (насколько знаю, разницы никакой). |
|||
|
||||
| Mayk |
|
|||
![]() ^аВаТаР^ сообщение>> ![]() ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 2616 Регистрация: 22.5.2005 Где: за границей разум а Репутация: 45 Всего: 134 |
_Slipknot
Какой компилятор используешь? -------------------- Здесь был кролик. Но его убили. Человеки < кроликов, йа считаю. |
|||
|
||||
| Code Magister |
|
|||
![]() Magister of Code ![]() Профиль Группа: Участник Сообщений: 155 Регистрация: 9.7.2004 Где: Kiev Репутация: 1 Всего: 1 |
ManiaK почитай посты выше. Я уже нашел ошибку и исправил ее.
А говорим мы сейчас о программе, которую написал Mayk Добавлено @ 16:04 Mayk BC++ 3.1 --------------------
|
|||
|
||||
| Code Magister |
|
|||
![]() Magister of Code ![]() Профиль Группа: Участник Сообщений: 155 Регистрация: 9.7.2004 Где: Kiev Репутация: 1 Всего: 1 |
Я откомпилил твою прогу на билдере(6-м) - совсем по-другому работает(почти правильно).
--------------------
|
|||
|
||||
| Mayk |
|
|||
![]() ^аВаТаР^ сообщение>> ![]() ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 2616 Регистрация: 22.5.2005 Где: за границей разум а Репутация: 45 Всего: 134 |
Итак, ChangeLog для BC3.1
long pos; заменяем на unsigned long pos; int len заменяем на long len fread(buf, len, 1, fin); заменяем на len=fread(buf,1,len,fin); fseek(fin, -len, SEEK_CUR); на fseek(fin, pos-len, SEEK_SET); printf("%x",pos); на printf("%lx",pos); Это сообщение отредактировал(а) Mayk - 7.6.2005, 16:58 -------------------- Здесь был кролик. Но его убили. Человеки < кроликов, йа считаю. |
|||
|
||||
| Mayk |
|
|||
![]() ^аВаТаР^ сообщение>> ![]() ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 2616 Регистрация: 22.5.2005 Где: за границей разум а Репутация: 45 Всего: 134 |
Так... Теперь функция работает но весьма странно.
Получается интересная бага: fseek(fin,pos-len,SEEK_SET); устанавливает стрим на нужную позицию(то есть если pos=121, len=80, то ftell(fin) дает 41, errno = 0) Зато len=fread(buf,1,len,fin) Возвращает 76 Под VS2003 все работает нормально... Под gcc тоже. Так как у нас есть 2 компилятора под которым это работает и 1 под которым не работает то мы можем сделать вывод о том, что где-то в bc есть бага. -------------------- Здесь был кролик. Но его убили. Человеки < кроликов, йа считаю. |
|||
|
||||
| Mayk |
|
|||
![]() ^аВаТаР^ сообщение>> ![]() ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 2616 Регистрация: 22.5.2005 Где: за границей разум а Репутация: 45 Всего: 134 |
УРА! Все, разобрался в чем дело. Дело оказывается в том, что в DOS строки заканчиваются двумя байтами. Отсюда описанная выше проблема с fseek/fread - fread читает все 80 байт, но возвращает 76 потому что 4 байта - это четыре байта '\r', которых в текстовом файле с точки зрения програмы быть не должно. Для того, чтобы эта священная война CR/LF vs CR оставила нас в покое мы делаем следующее:
1) Входной файл надо открывать КАК БИНАРНЫЙ(fopen("","rb");), а не как текстовой. Таким образом fread не будет пудрить мозги неправильным результатом. 2) Выходной файл по-прежнему открываем как текстовой, чтобы все CR/LFы были в порядке 3) Когда мы находим '\n' мы зануляем его и следующий за ним символ, если он является '\r' и выводим строку в выходной файл со следующего за ним символа. Также мы зануляем предыдущий символ, если он является '\r' (здесь надо не забыть про то, что "\r\n" могут быть разорваны буфером) Теперь это работает даже в Borland C 3.1 Правда не совсем понятно почему под визуалом текстовой файл окончивающийся вроде дуплетом был удачно перевернут, ну да ладно. -------------------- Здесь был кролик. Но его убили. Человеки < кроликов, йа считаю. |
|||
|
||||
| ManiaK |
|
|||
![]() Homo Sapience ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 1145 Регистрация: 3.8.2004 Где: ИУ5-93 Репутация: 5 Всего: 29 |
_Slipknot Что-то я ослеп что ли...
|
|||
|
||||
![]()
|
| Правила форума "С++:Общие вопросы" | |
|
|
Добро пожаловать!
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn |
| 0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
| 0 Пользователей: | |
| « Предыдущая тема | C/C++: Общие вопросы | Следующая тема » |
|
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |