![]() |
Модераторы: bsa |
![]() ![]() ![]() |
|
Compositum |
|
||||||||||||||||||||
![]() Senior developer ![]() ![]() Профиль Группа: Awaiting Authorisation Сообщений: 430 Регистрация: 6.1.2008 Где: Санкт-Петербург Репутация: нет Всего: 1 |
Язык программирования: C (не C++).
Книга: "Язык программирования C"; авторы: Брайан Керниган, Деннис Ритчи (второе издание). Потихоньку, не торопясь, последовательно, на совесть выполняю все упражнения книги... Сейчас выполняю упражнение 1.16 из раздела 1.9. (хотя прочитал намного дальше...).
Мои размышления идут по такому пути: строка представляет собой массив объектов char, т.о., теоретически, самый простой вариант отведения необходимого объёма памяти - изначально создать массив char, имеющий максимально допустимую длину - тогда в неё поместится любая возможная строка. Это, конечно, неправильный подход, поскольку получается, что под какую-то единственную строку я могу запросить столько памяти, сколько на моей машине даже физически нет... Но, всё таки любопытно посмотреть, что из этого получится... В разделе 1.6 "Массивы" обозначенной мною книги есть такая фраза:
Из этого текста я делаю вывод, что в качестве размера массива я смогу задать значения таких типов как int, unsigned int, long int, unsigned long int. Проверяю предположение:
Результат:
Как видим - компиляция проходит успешно, а значит - перехожу к следующей стадии своей страшной затеи и сразу же беру быка за рога:
Результат:
Слишком большое... Хорошо, понижаю планку:
Результат:
Как видим, сообщение несколько изменилось, однако результат по прежнему отрицательный... Снова понижаю планку:
Результат:
Как видим - в этот раз компиляция прошла успешно, однако в процессе выполнения получаю ошибку. Из краткого сообщения, делаю предположение, что размер строки не может быть больше размера сегмента. Т.о. мои опасения на тему того, что теоретически я могу отдать под массив char памяти больше, чем у меня есть физически - не оправдались (и слава Богу ![]() У меня 64-х разрядная операционная система (Ubuntu 11.04). Как можно программно (на C) получить размер сегмента (я так понимаю, что речь о сегменте памяти)? Правильно ли я понимаю, что под условие задачи (насчёт строки любой длины) я должен задавать размер массива char, равный размеру сегмента памяти (видимо разделение одной строки по нескольким сегментам не допустимо)? Спасибо. |
||||||||||||||||||||
|
|||||||||||||||||||||
volatile |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2107 Регистрация: 7.1.2011 Репутация: 16 Всего: 85 |
Скорей всего там вообще не надо отводить память. Если это входной поток, возможно нужно просто считать на лету. Покажите о каком главном модуле, идет речь. |
|||
|
||||
Compositum |
|
|||
![]() Senior developer ![]() ![]() Профиль Группа: Awaiting Authorisation Сообщений: 430 Регистрация: 6.1.2008 Где: Санкт-Петербург Репутация: нет Всего: 1 |
На данный момент мне быстрее показать скрин, чем набирать исходники (иначе на работу опоздаю) - выложил его здесь. Да, это входной поток, но в примере, прежде чем читать его, создаётся переменная longest (массив char, размером 1000). Я так понял, что вместо 1000 нужно подставить др. число, максимально допустимое для длины строки в потоке - вот я и пытался сделать это в первом сообщении топика... |
|||
|
||||
bsa |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 9185 Регистрация: 6.4.2006 Где: Москва, Россия Репутация: 85 Всего: 196 |
Compositum, ты пытаешься найти решение несуществующей проблемы.
Допустим, у тебя есть строка какого-то размера (он заранее не известен), тебе гарантированно нужно сделать ее копию. Для этого достаточно воспользоваться циклом, realloc и методом выделения памяти, используемом в std::vector - размер выделенной памяти должен быть в 2 раза больше, чем было до этого. Таким образом, если по умолчанию ты будешь делать буфер размером 128 байт, то тебе понадобится всего 3 перевыделения, чтобы получить размер 1024 (128->256->512->1024). |
|||
|
||||
Compositum |
|
|||
![]() Senior developer ![]() ![]() Профиль Группа: Awaiting Authorisation Сообщений: 430 Регистрация: 6.1.2008 Где: Санкт-Петербург Репутация: нет Всего: 1 |
Я всего лишь последовательно выполняю упражнения. На той стадии, на которой находится обозначенная задача, авторами книги ещё не были обозначены никакие realloc и std::vector (повторюсь - это C, а не C++). Исходя из этого, я предполагаю, что авторы книги (они же и авторы языка C), подразумевают какой-то др. способ, доступный читателю на основе ранее изложенного материала... |
|||
|
||||
bsa |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 9185 Регистрация: 6.4.2006 Где: Москва, Россия Репутация: 85 Всего: 196 |
Compositum, сделай так, чтобы если getline достигла лимита буфера, то она не ставила конец строки. Таким образом ты сможешь отследить этот момент и корректно вывести и строку, и ее размер. Хранить всю строку в памяти смысла нет никакого.
|
|||
|
||||
Compositum |
|
|||
![]() Senior developer ![]() ![]() Профиль Группа: Awaiting Authorisation Сообщений: 430 Регистрация: 6.1.2008 Где: Санкт-Петербург Репутация: нет Всего: 1 |
Но если строка выйдет за границы буфера (т.е. по сути - стека), то она начнёт писать данные поверх кода, стирая его... Или я ошибаюсь? |
|||
|
||||
bsa |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 9185 Регистрация: 6.4.2006 Где: Москва, Россия Репутация: 85 Всего: 196 |
Compositum, читать надо кусочками. Прочитал кусок строки размером в MAXLEN, вывел, прочитал другой, тоже вывел, ... прочитал конец, вывел, вывел размер.
Это по сути тоже самое, что читать посимвольно и сразу выводить на экран. |
|||
|
||||
Compositum |
|
|||
![]() Senior developer ![]() ![]() Профиль Группа: Awaiting Authorisation Сообщений: 430 Регистрация: 6.1.2008 Где: Санкт-Петербург Репутация: нет Всего: 1 |
Стоп. Хорошо, вот начну я выводить, и вдруг окажется, что следующее слово будет ещё длиннее, а я уже "навыводил"... Тогда как? Я ведь смотрю в разрезе задачи, код которой показан мною на скрине, а в ней требуется из массива строк, поступающего на входе, выбрать самую большую... Это сообщение отредактировал(а) Compositum - 31.5.2011, 06:32 |
|||
|
||||
bsa |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 9185 Регистрация: 6.4.2006 Где: Москва, Россия Репутация: 85 Всего: 196 |
||||
|
||||
Compositum |
|
|||
![]() Senior developer ![]() ![]() Профиль Группа: Awaiting Authorisation Сообщений: 430 Регистрация: 6.1.2008 Где: Санкт-Петербург Репутация: нет Всего: 1 |
Я так понял, что показанный мною выше скрин ты не смотрел... ![]() На нём в комментарии, перед main() озвучена решаемая задача: вывод самой длинной строки в потоке. На том же скрине, в самом низу след. страницы видно задание (упр. 1.16), о котором я собственно и пишу ![]() ![]() Вот я и думаю, как зная только массивы, суметь обработать входной поток любого размера и вывести строку любой длины, насколько это позволяет текст (главный модуль - это код, показанный на стр. 42 моего скрина). Я не понял фразы "насколько это позволяет текст"... Ведь текст - это массив символов. Массиву можно назначить далеко не каждый размер (это я показал в первом сообщении топика). Как правильно определить максимально возможный размер массива для того или иного типа данных? |
|||
|
||||
bsa |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 9185 Регистрация: 6.4.2006 Где: Москва, Россия Репутация: 85 Всего: 196 |
скрин я смотрел, но не читал все.
Перечитал все. Я не знаю решения задачи, без использования динамических массивов. Если бы речь шла о чтении файла, то можно было бы решить путем сохранения позиции максимальной строки в файле. Возможно, в книге ошибка. |
|||
|
||||
Compositum |
|
|||
![]() Senior developer ![]() ![]() Профиль Группа: Awaiting Authorisation Сообщений: 430 Регистрация: 6.1.2008 Где: Санкт-Петербург Репутация: нет Всего: 1 |
а я уж было подумал, что это я такой тупой, не могу простую задачку решить (сложную авторы вряд ли выложили бы на этой стадии)... ![]() Это сообщение отредактировал(а) Compositum - 31.5.2011, 18:53 |
|||
|
||||
xvr |
|
|||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 7046 Регистрация: 28.8.2007 Где: Дублин, Ирландия Репутация: 35 Всего: 223 |
Неправильный вывод (пока оставим за бортом вопрос о существовании сегментов вообще). Твой массив расположен в стеке, вот именно он и переполнился. Сделай массив глобальным (объяви перед main) |
|||
|
||||
Dov |
|
|||
![]() аСинизатор ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1721 Регистрация: 10.5.2003 Где: Эрец-Исраэль Репутация: 11 Всего: 88 |
В оригинале задача выглядит так: Revise the main routine of the longest-line program so it will correctly print the length of arbitrarily long input lines, and as much as possible of the text.
В моём (не совершенном) переводе это может звучать так: Исправьте функцию main программы так, что бы она корректно выводила длину(т.е. количество символов) самой длинной строки и, как можно большее количество текста(ограниченное, как мы помним, значением MAXLINE). Это сообщение отредактировал(а) Dov - 1.6.2011, 17:46 -------------------- Тут вечности запах томительный, И свежие фрукты дешевые, А климат у нас – изумительный, И только соседи – #уевые. Игорь Губерман. |
|||
|
||||
Compositum |
|
||||||||||||||||
![]() Senior developer ![]() ![]() Профиль Группа: Awaiting Authorisation Сообщений: 430 Регистрация: 6.1.2008 Где: Санкт-Петербург Репутация: нет Всего: 1 |
Попробовал с глобальными...
Результат
Результат:
Не понял... процесс был "убит" операционной системой? Если да, то почему?
Результат:
Как видим, в последнем случае откомпилировалось и отработало без ошибок, но на компиляцию ушло секунд 7... Почему в случае с локальной переменной это не сработало, а с глобальной - получилось? |
||||||||||||||||
|
|||||||||||||||||
xvr |
|
|||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 7046 Регистрация: 28.8.2007 Где: Дублин, Ирландия Репутация: 35 Всего: 223 |
Локальная переменная располагается в стеке, а его размер ограничен. Глобальная - в обычной виртуальной памяти. Ее размер ограничен только доступной виртуальной памятью (кстати, на 64х битной машине размер виртуальной память меньше - 48 бит) Так что long туда не влез (он занимает 63-64 бита адреса), а int влез (он занимает 31-32 бита) Но учти, что система может иметь свои взгляды на размер памяти, и прибить процесс, который попытается реально обратится к слишком большому объему памяти. Когда кончится своп файл процесс получит sigfault |
|||
|
||||
Compositum |
|
||||||||
![]() Senior developer ![]() ![]() Профиль Группа: Awaiting Authorisation Сообщений: 430 Регистрация: 6.1.2008 Где: Санкт-Петербург Репутация: нет Всего: 1 |
Спасибо за ответы. Ты пишешь, что размер стека ограничен, а чем обуславливаются размеры/ограничения стека? Я думал, что размер стека вычисляется компилятором на основе размеров переменных, используемых в программе. Я ошибся? Ещё я ведь могу объявить переменную как
В этом случае она будет видна только в рамках этого си-файла - такая переменная так же будет размещаться в обычной виртуальной памяти или в стеке (компилируется и работает без сообщений об ошибке)? Насчёт размера виртуальной памяти не понял - ты имеешь в виду размер указателя на ячейку памяти?
получаю: 8. Т.е. размер указателя - 64 бита. Это сообщение отредактировал(а) Compositum - 1.6.2011, 21:26 |
||||||||
|
|||||||||
bsa |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 9185 Регистрация: 6.4.2006 Где: Москва, Россия Репутация: 85 Всего: 196 |
Добавлено через 2 минуты и 51 секунду ты не путай размер указателя и разрядность виртуальной памяти. У указателя много места занимает выравнивание, которое необходимо, чтобы процессор быстрее считывал из памяти (т.е. считывание 8 байт с адреса, выравненного по 8 (addr % 8 == 0) займет 1 машинную операцию, а считывание с невыравненного - 2). |
|||
|
||||
xvr |
|
|||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 7046 Регистрация: 28.8.2007 Где: Дублин, Ирландия Репутация: 35 Всего: 223 |
Указатель действительно 64 бита, но могут быть нюансы. Например для x86 64х битной архитектуры обычно только младшие 48 битов (точное количество зависит от процессора) значимые. А оставшиеся старшие биты (64-48=16) должны совпадать друг с другом и с последним значащим битом (47м). В противном случае при попытке что либо прочесть/записать по такому указателю получите ошибку сегментации. Т.е. виртуальное адресное пространство действительно 64х битное, но в его середине есть дыра весьма приличного размера ![]() |
|||
|
||||
![]() ![]() ![]() |
Правила форума "C/C++: Для новичков" | |
|
Запрещается! 1. Публиковать ссылки на вскрытые компоненты 2. Обсуждать взлом компонентов и делиться вскрытыми компонентами
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, JackYF, bsa. |
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | C/C++: Для новичков | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |