Доброе утро/день/вечер.
Только что во время дебага заметил, что написал
bool check(int x, int y){
return 0 <= x && x < n && 0 <= y < m;
}
Программа компилировался, но работала, естественно, не правильно.
Другой подобный баг встречается чаще.
int getAns(...){
int ans = 0;
{
///Вычисление ответа
}
//здесь должен быть return ans; но он забыт.
}
Это тоже компилируется.
Другой более интересный пример, о котором я только слышал от Дмитрия Матова (Nerevar) :
int f = f(x1, y1, z1) + f(x2, y2, z2) + (x3, y3, z3);
Нет, я не забыл f перед третьей скобкой. Это тоже компилиться и работает.
Буквально сегодня из-за другой подобной ошибки мой напарник получал разные ответы при компиляции в g++ и в Visual Studio.
А какие вы знаете подобные вещи в С++?
...
answer = T % period;
...
я за это и люблю с++, что на нём можно скомпилировать всё, что угодно =)
сейчас я делаю одну программу на java и очень раздражаюсь тем, что строка while(true); не компилируется, приходится писать if (true) while(true);
про забытие return ans; вам напомнит гнутый компилятор (в смысле gnu c++) warning'ом, а для предотвращения других ошибок нужно максимально упрощать логические формулы, разбивая их в несколько if'ов, да и просто нужно быть внимательным к своему коду :)
Вот это опасно, да.
То же самое было бы
int newVal = (int)some_map.size() + (rand() & 1);
some_map[some_value] = newVal;
Писал декартво дерево
...
struct node{
...
node(){
...
y=rand();
,,,
}
...
};
vectr<node> tree;
int main(){
...
tree.resize(n);
...
}
RE 7 ловил дня 4.
Из более часто встречающегося
if (a=5) // ну это скорее когда начинал писать
if (j<1<<i) // а вот это обнаружил недавно.
Еще вспомню рссказ Виталия Гольдштейн о написани Фибоначиевой кучи. Проблема закючалась примерно в следующем.
был вектор структурок содержащих списки и указатели на списки лежащие в других структурках того же или другого вектора. Веселье начиналось когда вектор решал перераспределить память и все указатели становились не действительными.
такую тему можно использовать для отбивания желания учить с++)
if (a % 3 == 1) {
...
}
if (a & 3 == 1) {
...
}
Когда я впервые на это наткнулся, мне показалось очень нелогично, что
первый if сработает а второй нет.
я не сразу догадался, что "==" имеет более высокий приоритет, чем "&" =)
А битовые операции - они такие, да.
Кстати, мой вижак(2008) выдает warning проверьте приоритеты, если есть что-то подобнок без скобок.
int main( )
{ ... .
...
return -1;
}
Любая посылка - RE1 :о) Я так однажны на -80 сдал задачу :о)
Если int main и не написать return, не гарантируется, что вернется 0. Может с каким-то компилятором всегда будет 0, но вообще я уверен, что это не всегда так.
Весьма коварный случай:
if(x=='y') x=='1';
1 = = 2 = = 0 по мнению Visual Studio 2008 равно true.
2 = = 2 = = 2 по ее де мнению равно false.
При этом компиляцию конструкции
if (a = = b = = c)
//сдели что-то
не приводит даже к варнингу.
Даже на MinGW с -Wall.
Забавно.
И вообще я если честно не был уверен что это в принципе скомпилируется.
По поводу почему жду варнинга. Ну скорее всего здесь получается не то что имелось ввиду. По моему это отличный повод об этом сказать.
дело в том, что так нельзя делать.
ты используешь одну и ту же переменную v в выражении два раза. лучше такого избегать.
смотри что происходит.
когда ты первый раз пихаешь в вектор строку, то выделяется память под массив длины один.
потом ты пихаешь v[0] в вектор, в функцию push_back()
передаётся этот элемент по ссылке, и находится он в нектором массиве в памяти длины 1, перед тем как добавить второй элемент в функции push_back происходит выделение памяти под новый массив длины 2, элемент v[0] копируется в начало этого нового массива, а память из под массива длины 1 освобождается. Затем она заполняется нулями по видимому, а ссылка которая была передана указывает на эту самую память которая по идее освобождена, и не может тобой использоваться и ты пихаешь этот пустой стринг во второй элемент нового массива.
у меня на контесте как-то такой баг был, причем студия компилировала это в нормальный код, а GNU вылетал с крешем.
было что-то вроде h[Get(x)].cnt++;
а функция Get(x) делала push_back в массив h.
Дополню до кучи, что произойдет это только если произошел resize у вектора. В частности попробуйте запускать несколько раз - увидите от 1 до 3 букв 'a'.
если перед пушбеками вставит v.reserve(100);
то всё толжно сработать так как ожидал автор.
а кто писал scanf( "%d%d%d", n, x, y);?
причём в студии сразу же crash, а вот писали мы как-то в линуксовой аудитории... парень ошибку искал минут 20)
Проверил в Visual C++ 2010 Express Edition.
Выводит 3 "а".
опережу ненавистников C++ которые минусовали юзера alliumnsk за посты про яву и скажу что такие непоняки есть не только в C++
Integer a = 42;
Integer b = 42;
Integer c = 420;
Integer d = 420;
System.out.println(a==b); // true
System.out.println(c<=d); // true
System.out.println(c>=d); // true
System.out.println(c==d); // false
сделайте мне кучу минусов за правду.
Вообще дело в том, что Integer - это класс, и запись Integer a = 42 понимается компилятором как Integer a = Integer.valueOf(42), при этом а - объект на куче
Для всех операторов сравнения (кроме == ) происходит автоматическое преобразование к примитивному типу (т.е. c <= d <=> c.intValue() <= d.intValue())
Оператор == же для объектов имеет другой смысл - true, если они указывают на один объект на куче, false - иначе.
Теперь понятно, почему c==d -> false, но почему a==b -> true ??
Видимо, дело в том, что оператор Integer.valueOf() производит кеширование
Экспериментально проверено, что для отрезка [-128, 127] для одинаковых чисел будут возвращаться одинаковые объекты.
Вот код из класса Integer (jdk1.6):
static final Integer cache[] = new Integer[-(-128) + 127 + 1];
static {
for(int i = 0; i < cache.length; i++)
cache[i] = new Integer(i - 128);
}
}
Если в примере выше заменить Integer на примитивный тип int, то все сравнения дадут true (для примитивов == и equls() равнозначны).
Кстати, такой же результат будет и для строк:
String a = "string";
String b = new String ("string");
System.out.println(a==b); // false
System.out.println(a.equals (b)); // true
String a = "string";
String b = "string";
System.out.println(a==b); //true
А вот если замутить с new... то уже начинаются ссылки.
String a = "string";
String b = new String ("string"); //тут будет ссылка на объект
System.out.println(a==b); // false
System.out.println(a.equals (b)); // true
А с интами, конечно, вообще цирк... кэширование от -127 до 128... :о)
>String b = new String ("string"); //тут будет ссылка >на объект
в любом случае будет ссылка на объект, и в персвой строчке, просто если написать попростому то компилятор видимо оптимизирует и объект у тебя один и тот же получается. т.е. ссылки совпадают.
а с new получаем другой объект, оператор == ссылки сравнивает, а не объекты.
>А вот если замутить с new... то уже
> начинаются ссылки.
основная мысль предыдущего ответа это то что ссылки не начинаются, они всегда ссылки, просто в первом примере у тебя чудом a и b на один и тот же объект указывают.
a^=b^=a^=b;
работает ( меняет a и b местами), а в Java нет.
>> a^=b^=a^=b;
А вот так писать не стоит. Это undefined behavior, т.к. присходит двойное присваивание переменной b без операторов; и т.п..
Разве это не равносильно этому:
a ^= (b ^= (a ^= b)); ?
что, в свою очередь, разве не равносильно этому:
a ^= b;
b ^= a;
a ^= b;
?
Век живи - век учись :)
Век живи - век учись :)