LinuxForum.Fans
Тема

Ошибка сегментирования

Автор: Drayzer 45 сообщений 6026 просмотров
#230164
voral написал:
Ну вы взгляните в букварь. В какой последовательности обычно обучают.... Динамическое выделение памяти идет позже.

да. потому там и нет таких задач. они позже появляются. А до того int x[]={1,2,3,4,5};

UPD и ранее #define SIZE (sizeof(x)/sizeof(x[0]))

причём макрос SIZE нельзя использовать в сортировке, там именно для этого ТС очень грамотно применил len.

#230166
drBatty написал:
Теперь объясняйте ТСу разницу между инициализацией и присваиванием.

Пожалуй да.... Глянул K&R там действительно по началу все с клавы вводится.

#230174
voral написал:
Глянул K&R там действительно по началу все с клавы вводится.

конструкцию char x[5]="xyzt"; новичку ОЧЕНЬ трудно распарсить. Это я точно знаю. Я её вообще не применяю, ибо считаю нелогичной. Потому и удивился... Трудность тут не только в том, КАК это работает, но и почему не работает x="abcd"; и почему нельзя узнать размер x вне данного контекста. Вообще, массивов в С нет в принципе, то, что есть, является недоделанным костылём, который невозможно доделать, ибо весь старый код сломается. Так и живём...

#230182

Всегда инициализировал так

text
char arr[<n>]="xxxx";

и не знаю, что в этом сложного. Лишь бы символов было меньше n.

Пётр.

#230201
Peter написал:
Лишь бы символов было меньше n.

Мда...... Точно для новичков такое - зло.
Мало того, что свободное выкидывание на помойку лишней памяти - т.е. путь к быдло коду.
Так еще и ошибка есть. т.к "правильнее" было бы: "Лишь бы символов было меньше n-1." Да и то есть некоторые нюансы (которыми, в прочем, пренебрежено и в обсуждаемом коде)

#230255
voral написал:
[quote=Peter]Лишь бы символов было меньше n.

Мда...... Точно для новичков такое - зло.
Мало того, что свободное выкидывание на помойку лишней памяти - т.е. путь к быдло коду.
Так еще и ошибка есть. т.к "правильнее" было бы: "Лишь бы символов было меньше n-1." Да и то есть некоторые нюансы (которыми, в прочем, пренебрежено и в обсуждаемом коде)[/quote]
Тогда уж лучше "меньше n/2-1". Несколько десятков или сотен байтов - не такая потеря,
из-за которой надо беспокоиться.
И почему правильнее "меньше n-1", я как-то с ходу не понимаю.

Пётр.

#230314
Peter написал:
Тогда уж лучше "меньше n/2-1".

Вау...... Интересно почему вы решили разделить на 2?

Peter написал:
Несколько десятков или сотен байтов - не такая потеря, из-за которой надо беспокоиться.

Хех... Даже трудно что то сказать... Нормальное мнение для "индусов". Без обид. Объяснение дальше.

Peter написал:
И почему правильнее "меньше n-1", я как-то с ходу не понимаю.

А я понял, что вы того не понимаете. Именно по этому я и согласился с drBatty, что новичкам такие примеры писать вредно. Очевидно вы упустили, что то при изучении самых азов. Отчасти буду рад если я не прав и у вашего "непонимания" есть другое объяснение. Но давайте на примере. Исходя из того, что n-размер массива. Пусть n = 4;

text

ar[4]="abcd"; // здесь ошибка т.к. м пытаемся в массив из 4 чаров засунуть 5 байт
ar2[4]="abc"; // а здесь все верно. Т.к. мы "засовываем" четко 4 байта

а все потому, что на самом деле в обеих строках последний символ одинаковый его код 0x00.

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

#230367

Всё равно я не понимаю, почему правильнее было бы "меньше n-1".
То, что вы привели, показывает, что достаточно "меньше n".

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

Не меьнше n/2-1 требуется, чтобы хватило для русского текста в UTF-8.

Пётр.

#230390
Peter написал:
То, что вы привели, показывает, что достаточно "меньше n".

А ну да.. Я просто посчитал включительно :) Я вчера вообще целый день перлы выдавал.

Peter написал:
Не меньше n/2-1 требуется, чтобы хватило для русского текста в UTF-8.

Ну, а почему рассчет только на русский? :)

#230402

Я не знаю, вводят ли в программах на C текст на китайском и ему подобных,
но если и вводят, то они уже знают, сколько для этого требуется байтов на символ.

Пётр.

#230423
Peter написал:
Всегда инициализировал так
char arr[<n>]="xxxx";
и не знаю, что в этом сложного. Лишь бы символов было меньше n.

сложность в поддержке, если вы задаёте n и уж тем более, если задаёте n в виде макроса. Очень легко забыть изменить это n. Лучше вообще не задавать. А для новичков лучше вообще не пользоваться этой мутной и нелогичной фичей.

voral написал:
Мало того, что свободное выкидывание на помойку лишней памяти - т.е. путь к быдло коду.

не только. Так делает не только уважаемый Пётр, но и почти все кодеры. Да и компилятор выравнивает, добавляя много байт. Такие дыры очень удобны для злоумышленников, что-бы встраивать туда вредоносный код.

Peter написал:
Не меьнше n/2-1 требуется, чтобы хватило для русского текста в UTF-8.

вообще-то в UTF-8 допустимы символы размером 6 байт. Злоумышленник может вам заслать ЛЮБЫЕ символы. Как вы думаете, к чему это приведёт? Правильно, к переполнению буфера, ибо в С/С++ в рантайме никаких границ никогда не проверяется.

Peter написал:
Я не знаю, вводят ли в программах на C текст на китайском и ему подобных,
но если и вводят, то они уже знают, сколько для этого требуется байтов на символ.

6 штук максимум. Т.е. если вы выделили в стеке для 20 букв 50 байтов (41 + 9 запаса), то у вас - дыра. Даже если вы проверили, символ это или не символ. Злоумышленнику достаточно всего 5и неучтённых байт, что-бы поменять адрес возврата. И ваша функция вернёт управление не обратно, а туда, куда надо (тому, кто это ввёл).

ЗЫЖ про статические переменные в С - это ЗЛО.

#230424
drBatty написал:
лучше вообще не пользоваться этой мутной и нелогичной фичей.

почему "мутная"? да потому, что "xyz" это константный указатель на константный байт. А вот char[] это массив. Ну или константный указатель на байт (после передачи внутрь функции). А оператор "равно" в С обязан копировать один указатель в другой. А у нас тут копируются байты, что идёт вразрез всем правилам и стандартам. Не, я понимаю, что это "удобно", но если подумать, то нам вовсе не нужна такая инициализация, и можно отказаться от этого костыля, для более удобной поддержки и развития проекта. Хотя для хэлловорлда это не важно.

#230432

Инициализация символьного массива символьной строкой при его объявлении -
законая операция, она допускается только про объявлении. Это уж дело програмиста
обеспечить достаточный рамер буфера.

Рассуждение насчёт переполнения буфера не понял. Сам я этим никогда не занимался
и не интересовался, а как я понял из того, что мне попадалось, переполнение надо
понимать в буквальном смысле - злоумышленник передал в подпрограммму строку
длиной больше, чем размер буфера, отведённый в ней для её приёма, поэтому
вызываемая продпрограмма должна проверять размер передаваемой ей строки.

Так что, наоборот, чем больше размер буфера, тем труднее умышленно вызвать
его переполнение.

Пётр.

#230436
drBatty написал:
не только. Так делает не только уважаемый Пётр, но и почти все кодеры. Да и компилятор выравнивает, добавляя много байт. Такие дыры очень удобны для злоумышленников, что-бы встраивать туда вредоносный код.

Думаю такой (как у Петра) запас не отменит ни какое выравнивание..... Т.е. все равно это лишняя память.... А я как привык в стародавние времена беречь каждый байт, так и стараюсь.... Хотя, если это сурыто от меня, стороннимим классами не парюсь

#230439
voral написал:
[quote=drBatty]не только. Так делает не только уважаемый Пётр, но и почти все кодеры. Да и компилятор выравнивает, добавляя много байт. Такие дыры очень удобны для злоумышленников, что-бы встраивать туда вредоносный код.

Думаю такой (как у Петра) запас не отменит ни какое выравнивание..... Т.е. все равно это лишняя память.... А я как привык в стародавние времена беречь каждый байт, так и стараюсь.... Хотя, если это сурыто от меня, стороннимим классами не парюсь[/quote]
Это уж очень древние времена, когда ЭВМ были на лампах и программе выделялось
2048 байтов. Конечно, и в DOS я старался не тратить память зря.
Сейчас надо больше заботиться о быстродействии. Например, обращение к элементу
массива через разименование и круглые скобки немного быстрее, чем по индексу в угловых.

Пётр.

#230474
Peter написал:
Так что, наоборот, чем больше размер буфера, тем труднее умышленно вызвать
его переполнение.

да.

Peter написал:
поэтому вызываемая продпрограмма должна проверять размер передаваемой ей строки.

вы проверяете размер символов, исходя из неверного предположения, что 1 символ это 1 или 2 байта. Более удачная мысль - озаботить этим компилятор. А то знаете...

Peter написал:
Инициализация символьного массива символьной строкой при его объявлении -
законая операция

да. законная. только мутная и не логичная. В УК РФ таких правил тоже полно.

voral написал:
А я как привык в стародавние времена беречь каждый байт, так и стараюсь....

правильно.

Peter написал:
Это уж очень древние времена, когда ЭВМ были на лампах
Peter написал:
Сейчас надо больше заботиться о быстродействии.

вот и заботьтесь:
hint массив в два раза меньше обрабатывается в два раза быстрее. Хоть на лампах, хоть на кубитах.

Peter написал:
Например, обращение к элементу массива через разименование и круглые скобки немного быстрее, чем по индексу в угловых.

пример можно?

#230557

Сам принер у меня есть, но проверить ещё раз смогу завтра, а результата точно не помню.
Различие было несколько процентов, не более 5, в пользу варианта с круглыми скобками.

У какой именно обработки массива скорость линейно зависит от его размера?
Если только его заполнение специальной командой типа memset, или, например,
QImage:fill() в Qt, но массивы для работы обычно объявляют в точности того размера,
который нужен.
Что же, чем больше размер массива, тем дольше выполняется доступ к его элементу по индексу?

Пётр.

#230577
Peter написал:
Сам принер у меня есть, но проверить ещё раз смогу завтра, а результата точно не помню.
Различие было несколько процентов, не более 5, в пользу варианта с круглыми скобками.

ничего не понял... :o

Массив в С объявляется например так:

text
int a[]={11,22,33};

Доступ к массиву

text
int y = a[1]; // y будет равно 22

запись a[1] эквивалентна записи *(a + 1); (по определению)
В силу того, что сложение коммутативно, то a[1] === *(a + 1) === 1[a]
Это один и тот же код!
Ускорения здесь в принципе не может быть. А где вы увидели "угловые скобки", мне непонятно.

Peter написал:
У какой именно обработки массива скорость линейно зависит от его размера?

поиск эл-та с нужным значением в не сортированном массиве. например есть массив 2 1 2 8 5 0 6, требуется найти 5. Математическое ожидание числа проб равно N/2.
Ещё создание/удаление/изменение размера, но в C это с обычными массивами невозможно. Можно с динамическими (т.е. теми, которые созданы alloc()).
Ещё есть разные...

Peter написал:
Если только его заполнение специальной командой типа memset

очевидно, скорость memset (как и скорость memchr, memcpy, memcmp и т.д.) зависит линейно от размера.

Peter написал:
Что же, чем больше размер массива, тем дольше выполняется доступ к его элементу по индексу?

нет. *(a + 1) выполняется столько же, сколько *(a + 100500).
Если вам нужны более "умные" массивы, используйте STL. (правда это уже ++)

#230613

Я и сам считал, что обращение через разименование и круглые скобки эквивалентно
обращению по индексу в [], но всё же хотел в этом убедиться. Сейчас сравнил время
работы тестовой программы с многократным вызовом подпрограммы, в которой я использовал
() либо [] и разницы абсолютно не оказалось. Это в Debian Wheezy, CPU AMD Athlon X2 64.

А разницу в несколько процентов я заметил в тестовой программе на Intel Core 2 Quad,
Ubuntu 11.04 32-р.
Но, наверное, это ничего не значит, т.к., когда там запускается рабочая программа с
четырьмя потоками, в каждом из которых вызвывается эта подпрограмма, то результаты
по четырём ядрам могут отличаться на величину в 2 - 4 раза больше той, на которую
в тестовой отличаются результаты при использовании () и []. Но завтра всё же ещё раз
проверю результат для тестовой программы.

Пётр.

#230618
Peter написал:
Я и сам считал, что обращение через разименование и круглые скобки эквивалентно
обращению по индексу в [], но всё же хотел в этом убедиться.

так а смысл убеждаться, если это одно и то-же? Просто разная запись.
Хотя конечно возможны ньюансы, если там написать (void*), или прибавить дробь... Не знаю. На самом деле, происходит следующее, для a[j]:
1. сначала мы преобразуем j в тип ptr_diff
2. затем умножаем j на sizeof(a[0]), последняя - предопределённая константа.
3. затем прибавляем к a j*sizeof(a[0]), т.е. сдвигаем указатель вперёд на j эл-тов.
4. и наконец получаем содержимое нужного эл-та по найденному указателю.
Если вы догадались все элементы сделать независимыми переменными, то компилятор для x86 свернёт всё это (в большинстве случаев) в одну команду. Возможные варианты - наличие ещё каких-то вычислений, которые могут оказать влияние на ход компиляции.

Ну или С++, где скобки[] раскрываются иначе.

Войдите или зарегистрируйтесь, чтобы ответить.