Индекс массива из связанного в C

В matplotlib lingo вы ищете способ установки пользовательских тиков.

Кажется, вы не можете достичь этого с помощью ярлыка pyplot.hist. Вам нужно будет создать свое изображение шаг за шагом. На Stack Overflow уже есть ответ на вопрос, который очень похож на ваш, и вы должны начать: Matplotlib - пометить каждый бит

44
задан TryinHard 20 August 2015 в 07:49
поделиться

9 ответов

Проблема состоит в том, что C/C++ на самом деле не делает никакой граничной проверки относительно массивов. Это зависит от ОС, чтобы гарантировать доступ к допустимой памяти.

В данном случае, Вы объявляете основанный на стеке массив. В зависимости от конкретной реализации, получая доступ вне границ измерения массива просто получит доступ к другой части уже выделенного стекового пространства (большая часть ОС, и потоки резервируют определенную часть памяти для стека). Пока Вы просто, оказывается, играете вокруг в предварительно выделенном стековом пространстве, все не откажет (обратите внимание, что я не сказал что работа).

то, Что происходит на последней строке, - то, что Вы теперь получили доступ вне части памяти, которая выделяется для стека. В результате Вы индексируете в часть памяти, которая не выделяется Вашему процессу или выделяется способом только для чтения. ОС видит это и отправляет отказ seg в процесс.

Это - одна из причин, что C/C++ так опасен когда дело доходит до граничной проверки.

68
ответ дан JaredPar 20 August 2015 в 17:49
поделиться

C не делает этого. Виртуальная memeory подсистема ОС.

В случае, где Вы незначительно из-связанного, Вы обращаетесь к memeory, который является выделен для Вашей программы (на стеке вызовов стека в этом случае). В случае, где Вы далеки за пределы, Вы обращаетесь к памяти, которой не предаются, Ваша программа и ОС бросают отказ сегментации.

В некоторых системах существует также осуществленное понятие ОС "writeable" памяти, и Вы могли бы пытаться записать в memeory, что Вы владеете, но отмечен unwriteable.

3
ответ дан dmckee 20 August 2015 в 17:49
поделиться

segfault не является намеченным действием Вашей программы C, которая сказала бы Вам, что индекс выходит за пределы. Скорее это - непреднамеренное последствие неопределенного поведения.

В C и C++, если Вы объявляете массив как

type name[size];

, Вам только разрешают получить доступ к элементам с индексами от 0 [до 113]. Что-либо за пределами того диапазона вызывает неопределенное поведение. Если индекс был около диапазона, по всей вероятности Вы читаете память своей собственной программы. Если индекс был в основном вне диапазона, по всей вероятности Ваша программа будет закрыта операционной системой. Но Вы не можете знать, что-либо может произойти.

, Почему C позволяет это? Ну, основная суть C и C++ не должна обеспечивать функции, если они стоят производительности. C и C++ использовался целую вечность для высоко производительности критические системы. C использовался в качестве языка реализации для ядер и программ, где доступ из границ массива может быть полезным для получения быстрого доступа к объектам, которые лежат смежные в памяти. Наличие компилятора запрещает, это было бы ни для чего.

, Почему это не предупреждает об этом? Ну, можно поместить предупреждение уровней высоко и надеяться на милосердие компилятора. Это называют качество реализации (QoI). Если некоторый компилятор использует открытое поведение (как, неопределенное поведение) для выполнения чего-то хорошего, это имеет хорошее качество реализации в том отношении.

[js@HOST2 cpp]$ gcc -Wall -O2 main.c
main.c: In function 'main':
main.c:3: warning: array subscript is above array bounds
[js@HOST2 cpp]$

, Если бы это вместо этого отформатировало бы Ваш жесткий диск после наблюдения массива, получил доступ за пределы - который был бы законен для него - качество реализации будет довольно плохо. Я наслаждался для чтения о том материале в ANSI C документ Объяснения .

21
ответ дан mr_eclair 20 August 2015 в 17:49
поделиться

Только для добавления, что говорят другие люди Вы не можете полагаться на программу, просто отказывающую в этих случаях, нет никакого gurantee того, что произойдет, при попытке получить доступ к ячейке памяти вне "границ измерения массива". Это все равно, как будто Вы сделали что-то как:

int *p;
p = 135;

*p = 14;

, Который просто случаен; это могло бы работать. Это не могло бы. Не делайте этого. Код для предотвращения этих видов проблем.

2
ответ дан BobbyShaftoe 20 August 2015 в 17:49
поделиться

Как litb упомянутый, некоторые компиляторы могут обнаружить некоторых за пределы доступы к массиву во время компиляции. Но границы, проверяющие во время компиляции, не поймают все:

int a[10];
int i = some_complicated_function();
printf("%d\n", a[i]);

Для обнаружения этого проверки на этапе выполнения должны были бы использоваться, и их избегают в C из-за их влияния производительности. Даже со знанием размера массива a во время компиляции, т.е. sizeof (a), это не может защитить от этого, не вставляя проверку на этапе выполнения.

2
ответ дан Tung Nguyen 20 August 2015 в 17:49
поделиться

Поскольку я понимаю вопрос и комментарии, Вы понимаете, почему плохие вещи могут происходить, когда Вы получаете доступ к памяти за пределы, но Вы задаетесь вопросом, почему Ваш конкретный компилятор не предупредил Вас.

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

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

, Но Вы не полностью отсутствуете в холоде здесь. Если Ваш компилятор не предупреждает Вас, Линт может. Кроме того, существует много инструментов для обнаружения таких проблем (во время выполнения) для массивов на "куче", одном из более известных, являющихся Электрическим Забором (или ДУМА ). Но даже Электрический Забор не гарантирует, что поймает все ошибки переполнения.

2
ответ дан Max Lybbert 20 August 2015 в 17:49
поделиться

Вы обычно только получаете отказ сегментации, при попытке получить доступ к памяти, Ваш процесс не владеет.

В случае чего Вы видите a[11]a[10] между прочим), память, которой Ваш процесс владеет, но не принадлежит a[] массив. a[25000] так далеко от a[], это, вероятно, вне Вашей памяти в целом.

Изменение a[11] намного более коварно, поскольку это тихо влияет на другую переменную (или стековый фрейм, который может вызвать другой отказ сегментации, когда Ваша функция возвращается).

6
ответ дан Spikatrix 20 August 2015 в 17:49
поделиться

Это не проблема C проблема операционной системы. Вы - программа, был предоставлен определенное пространство памяти и что-либо, что Вы делаете в этом, прекрасен. Отказ сегментации только происходит при доступе к памяти за пределами пространства процесса.

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

1
ответ дан zimbu668 20 August 2015 в 17:49
поделиться

Как JaredPar заявил, C/C++ не всегда выполняет проверку диапазона. Если Ваша программа получает доступ к ячейке памяти вне Вашего выделенного массива, Ваша программа может отказать, или это может, не потому что это получает доступ к некоторой другой переменной на стеке.

Для ответа на вопрос о sizeof операторе в C: можно надежно использовать sizeof (массив) / размер (массив [0]) для определения размера массива, но использование его не означает, что компилятор выполнит любую проверку диапазона.

Мое исследование показало, что разработчики C/C++ полагают, что Вы не должны платить за что-то, что Вы не используете, и они доверяют программистам для знания то, что они делают. (см. принятый ответ на это: Доступ к массиву за пределы не дает ошибки, почему? )

, Если можно использовать C++ вместо C, возможно, используйте вектор? Можно использовать вектор [] при необходимости в производительности (но никакая проверка диапазона) или, более предпочтительно, используйте vector.at () (который имеет проверку диапазона за счет производительности). Обратите внимание, что вектор автоматически не увеличивает способность, если это полно: для сейфа используйте push_back (), который автоматически увеличивает способность при необходимости.

[еще 116] информация о векторе: http://www.cplusplus.com/reference/vector/vector/

0
ответ дан 26 November 2019 в 21:52
поделиться