Используйте LWP:: UserAgent вместо этого:
use strict;
use warnings;
use LWP::UserAgent;
my %query_hash = (spam => 'eggs', foo => 'bar baz');
my $ua = LWP::UserAgent->new();
my $resp = $ua->get("http://www.foobar.com", %query_hash);
print $resp->content;
Это заботится о кодировании для Вас.
, Если Вы хотите более универсальное решение для кодирования, см. HTML:: Объекты .
РЕДАКТИРОВАНИЕ: URI:: Escape является лучшим выбором.
Добро пожаловать в лучший друг каждого программиста C / C ++: Undefined Behavior .
Есть много вещей, которые не указаны в языковом стандарте по разным причинам. Это один из них.
В общем, всякий раз, когда вы сталкиваетесь с неопределенным поведением, может произойти что угодно . Приложение может дать сбой, оно может зависнуть, оно может выбросить ваш привод CD-ROM или заставить демонов вылезти из вашего носа. Он может отформатировать ваш жесткий диск или по электронной почте всех ваших порно к своей бабушке.
Это, возможно, даже, если вы действительно повезли, появляется , чтобы работать правильно.
Язык просто говорит о том, что должно произойти, если вы доступ к элементам в границах массива. Неизвестно, что произойдет, если вы выйдете за пределы поля. Может показаться, что сегодня работает на вашем компиляторе, но это не законный C или C ++, и нет никакой гарантии, что он по-прежнему будет работать при следующем запуске программы. Или что он не перезаписал важные данные даже сейчас, и вы просто не столкнулись с проблемами, которые он вызовет - пока.
Что касается , почему там. Это не проверка границ, есть пара аспектов ответа:
std :: vector
шаблон класса, который позволяет и то, и другое. Оператор []
разработан, чтобы быть эффективным. Стандарт языка не требует, чтобы он выполнял проверку границ (хотя и не запрещает этого). Вектор также имеет функцию-член at ()
, которая гарантированно выполняет проверку границ. Итак, в C ++ вы получаете лучшее из обоих миров, если используете вектор. Вы получаете производительность, подобную массиву, без проверки границ, и вы получаете возможность использовать доступ с проверкой границ, когда захотите. при объявлении массива int [2]; вы резервируете 2 области памяти по 4 байта каждая (32-битная программа). если вы наберете в коде array [4], он по-прежнему будет соответствовать допустимому вызову, но только во время выполнения он вызовет необработанное исключение. C ++ использует ручное управление памятью. На самом деле это недостаток безопасности, который использовался для взлома программ
. Это может помочь понять:
int * somepointer;
somepointer [0] = somepointer [5];
Когда вы инициализируете массив с помощью int array [2]
, выделяется место для 2 целых чисел; но массив идентификаторов
просто указывает на начало этого пространства. Когда вы затем обращаетесь к массиву [3]
и массиву [4]
, компилятор просто увеличивает этот адрес на единицу, чтобы указать, где эти значения были бы, если бы массив был достаточно длинным; попробуйте получить доступ к чему-то вроде array [42]
без его предварительной инициализации, вы получите любое значение, которое уже было в памяти в этом месте.
Изменить:
Подробнее об указателях / массивы: http://home.netcom.com/~tjensen/ptr/pointers.htm
Запустите это через Valgrind , и вы можете увидеть ошибку.
Как указала Фалаина, valgrind не обнаруживает многих случаев повреждения стека. Я только что попробовал образец под valgrind, и он действительно не сообщает об ошибках. Тем не менее, Valgrind может помочь в поиске многих других типов проблем с памятью, но в этом случае он не особенно полезен, если вы не измените свой Bulid, включив параметр --stack-check. Если вы соберете и запустите образец как
g++ --stack-check -W -Wall errorRange.cpp -o errorRange
valgrind ./errorRange
valgrind , сообщит об ошибке.
C или C ++ не будут проверять границы доступа к массиву.
Вы размещаете массив в стеке. Индексирование массива через array [3]
эквивалентно * (array + 3)
, где array является указателем на & array [0]. Это приведет к неопределенному поведению.
Один из способов поймать это иногда в C - использовать статическую проверку, такую как splint . Если вы запустите:
splint +bounds array.c
on,
int main(void)
{
int array[1];
array[1] = 1;
return 0;
}
, вы получите предупреждение:
array.c: (в функции main) Индексирование массива через
array [3]
эквивалентно *(array + 3)
, где array является указателем на & array [0]. Это приведет к неопределенному поведению.Один из способов поймать это иногда в C - использовать статическую проверку, такую как splint . Если вы запустите:
splint +bounds array.c
on,
int main(void) { int array[1]; array[1] = 1; return 0; }
, вы получите предупреждение:
array.c: (в функции main) Индексирование массива через
array [3]
эквивалентно *(array + 3)
, где array является указателем на & array [0]. Это приведет к неопределенному поведению.Один из способов поймать это иногда в C - использовать статическую проверку, такую как splint . Если вы запустите:
splint +bounds array.c
on,
int main(void) { int array[1]; array[1] = 1; return 0; }
, вы получите предупреждение:
array.c: (в функции main) array.c: 5: 9: Вероятно, за пределами поля магазин: массив [1] Невозможно разрешить ограничение: требуется 0> = 1 необходимо для выполнения предварительного условия: требует maxSet (array @ array.c: 5: 9)> = 1 Запись в память может напишите по адресу за пределами выделенный буфер.
Вы определенно перезаписываете свой стек, но программа достаточно проста, поэтому последствия этого остаются незамеченными.
Если вы хотите иметь быстрые массивы ограничения размера с проверкой ошибок диапазона, попробуйте использовать boost :: array , (также std :: tr1 :: array из
это будет стандартный контейнер в следующей спецификации C ++). Это намного быстрее, чем std :: vector. Он резервирует память в куче или внутри экземпляра класса, как int array [].
Это простой пример кода:
#include <iostream>
#include <boost/array.hpp>
int main()
{
boost::array<int,2> array;
array.at(0) = 1; // checking index is inside range
array[1] = 2; // no error check, as fast as int array[2];
try
{
// index is inside range
std::cout << "array.at(0) = " << array.at(0) << std::endl;
// index is outside range, throwing exception
std::cout << "array.at(2) = " << array.at(2) << std::endl;
// never comes here
std::cout << "array.at(1) = " << array.at(1) << std::endl;
}
catch(const std::out_of_range& r)
{
std::cout << "Something goes wrong: " << r.what() << std::endl;
}
return 0;
}
Эта программа напечатает:
array.at(0) = 1
Something goes wrong: array<>: index out of range
Насколько я знаю, это неопределенное поведение. Запустите большую программу с этим, и она выйдет из строя где-нибудь по пути. Проверка границ не является частью необработанных массивов (или даже std :: vector).
Используйте std :: vector с std :: vector :: iterator
вместо этого, чтобы вам не приходилось беспокоиться об этом.
Edit:
Просто ради удовольствия, запустите это и посмотрите, сколько времени до сбоя:
int main()
{
int array[1];
for (int i = 0; i != 100000; i++)
{
array[i] = i;
}
return 0; //will be lucky to ever reach this
}
Edit2:
Не запускайте это.
Edit3:
Хорошо, вот краткий урок о массивах и их отношениях с указателями:
Когда вы используете индексацию массива, вы действительно используете замаскированный указатель (называемый «ссылкой»), который автоматически разыменовывается. Вот почему вместо * (array [1]) array [1] автоматически возвращает значение с этим значением.
Если у вас есть указатель на массив, например:
int array[5];
int *ptr = array;
Затем "
int main()
{
int array[1];
int *ptr = array;
for (int i = 0; i != 100000; i++, ptr++)
{
*ptr++ = i;
}
return 0; //will be lucky to ever reach this
}
Компилятор не будет жаловаться, потому что при программировании вам часто приходится взаимодействовать с другими программами, особенно с операционной системой. Это довольно часто делается с помощью указателей.
int main()
{
int array[1];
int *ptr = array;
for (int i = 0; i != 100000; i++, ptr++)
{
*ptr++ = i;
}
return 0; //will be lucky to ever reach this
}
Компилятор не будет жаловаться, потому что при программировании вам часто приходится взаимодействовать с другими программами, особенно с операционной системой. Это довольно часто делается с помощью указателей.
g ++ не проверяет границы массива, и вы можете перезаписать что-то с 3,4, но ничего особо важного, если вы попробуете с более высокими числами, вы получите сбой.
Вы просто перезаписывают части стека, которые не используются, вы можете продолжать, пока не дойдете до конца выделенного пространства для стека, и в конечном итоге произойдет сбой
EDIT: У вас нет способа справиться с этим, возможно, статический анализатор кода сможет выявить эти сбои, но это слишком просто, у вас могут быть похожие (но более сложные) сбои, не обнаруженные даже для статических анализаторов
Используя g ++, вы можете добавить параметр командной строки: -fstack-protector-all
.
В вашем примере это привело к следующему:
> g++ -o t -fstack-protector-all t.cc
> ./t
3
4
/bin/bash: line 1: 15450 Segmentation fault ./t
Это на самом деле не поможет вам найти или решить проблему, но по крайней мере segfault сообщит вам, что что-то не так.
Неопределенное поведение работает в вашу пользу. Какое бы воспоминание вы ни забили, очевидно, ничего важного не содержится. Обратите внимание, что C и C ++ не проверяют границы массивов, поэтому подобные вещи не будут обнаружены во время компиляции или выполнения.
Насколько я понимаю, локальные переменные выделяются в стеке, поэтому выход за пределы вашего собственного стека может перезаписать только некоторые другие локальные переменные, если вы не перейдете слишком далеко и не превысите размер своего стека. Поскольку у вас нет других переменных, объявленных в вашей функции - это не вызывает никаких побочных эффектов. Попробуйте объявить другую переменную / массив сразу после первой и посмотрите, что с ней произойдет.
Когда вы пишете 'array [index]' на C, он переводит его в машинные инструкции.
Перевод выглядит примерно так:
Результат относится к чему-то, что может быть, а может и не быть частью массива. В обмен на молниеносную скорость машинных инструкций вы теряете страховочную сетку компьютера, проверяющего все за вас. Если вы дотошны и осторожны, это не проблема. Если вы неаккуратны или ошибетесь, вы получите ожог. Иногда может генерироваться недопустимая инструкция, вызывающая исключение, иногда нет.