Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > C/C++ программирование > Общие вопросы C/C++
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 19.06.2015, 13:10   #1
ACE Valery
Сама себе режиссер
Старожил
 
Аватар для ACE Valery
 
Регистрация: 27.04.2007
Сообщений: 3,365
По умолчанию Странности компилятора?

Всем привет. Помогите разобраться, пожалуйста.
Есть код:
Код:
char * name;
name = new char(9);
//далее вводим в переменную str с клавиатуры слово в 8 символов.
strcpy(name, str);
cout<<name;
delete[] name;
На строке с delete программа выдает ошибку. Это понятно, скобочки, выделенные красным, должны быть квадратными. Объясните, пожалуйста, почему компилятор пропускает круглые скобки и не говорит об ошибке, а также нормально копирует одну строку в другую, нормально выводит строку, и падает только на удалении.

UPD: компилятор из Microsoft Visual Studio 12
Если я вас напрягаю или раздражаю, вы всегда можете забиться в угол и поплакать
ACE Valery вне форума Ответить с цитированием
Старый 19.06.2015, 13:38   #2
Stilet
Белик Виталий :)
Старожил
 
Аватар для Stilet
 
Регистрация: 23.07.2007
Сообщений: 57,097
По умолчанию

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

P.S. Я если ее найду, я тебе скину ссыль.
I'm learning to live...
Stilet вне форума Ответить с цитированием
Старый 19.06.2015, 13:43   #3
miss twin
Пользователь
 
Регистрация: 19.06.2015
Сообщений: 15
По умолчанию

Цитата:
Объясните, пожалуйста, почему компилятор пропускает круглые скобки и не говорит об ошибке
Потому что это инициализация и так правильно, и так можно. Компилятор не может угадать массив вам нужен или все-таки один символ с таким кодом.

Цитата:
а также нормально копирует одну строку в другую
Потому что старые функции, типа strcpy, писали гики и для скорости. Там нет проверки на размер. Скопировалось, т.к. у вашей программы был доступ к участку памяти и просто повезло.

Цитата:
нормально выводит строку
С чего бы не вывести? Доступ есть, массив байт с нулем в конце есть.

Цитата:
и падает только на удалении
Вполне заслуженно...

Цитата:
UPD: компилятор из Microsoft Visual Studio 12
А его варнинги читать не пробывали. Он там не туже strcpy матерится.
miss twin вне форума Ответить с цитированием
Старый 19.06.2015, 15:54   #4
Vapaamies
Ваш К. О.
Участник клуба
 
Аватар для Vapaamies
 
Регистрация: 26.12.2012
Сообщений: 1,770
По умолчанию

Цитата:
Сообщение от miss twin Посмотреть сообщение
старые функции, типа strcpy, писали гики и для скорости. Там нет проверки на размер. Скопировалось, т.к. у вашей программы был доступ к участку памяти и просто повезло.
Плюс память в куче распределяется обычно с большим выравниванием, на 16 байт вроде. Так что если запросить 1 байт, выделится 16 байт, и следующие 15 байт после переменной будут свободны, и в них можно будет что-то записать по указателю.
Vapaamies вне форума Ответить с цитированием
Старый 19.06.2015, 16:09   #5
waleri
Старожил
 
Регистрация: 13.07.2012
Сообщений: 6,330
По умолчанию

Цитата:
Сообщение от Vapaamies Посмотреть сообщение
следующие 15 байт после переменной будут свободны
Это сильно зависит от компилятора. Например MSVC в отладочной сборке записывает специальные куки с обоих концов выделенного блока и проверяет их при удалении (assert).
waleri вне форума Ответить с цитированием
Старый 21.06.2015, 20:28   #6
ACE Valery
Сама себе режиссер
Старожил
 
Аватар для ACE Valery
 
Регистрация: 27.04.2007
Сообщений: 3,365
По умолчанию

Всем спасибо за ответы
Если я вас напрягаю или раздражаю, вы всегда можете забиться в угол и поплакать
ACE Valery вне форума Ответить с цитированием
Старый 22.06.2015, 17:06   #7
Croessmah
Вредный кошак
Участник клуба
 
Аватар для Croessmah
 
Регистрация: 14.10.2012
Сообщений: 1,159
По умолчанию

Цитата:
Сообщение от ACE Valery Посмотреть сообщение
Помогите разобраться
У new-expression имеется две формы.

Первая - для выделения non-array типа.
Вторая - для выделения массива.

Какая из форм будет выбрана зависит от синтаксиса. Синтаксис new-expression:
Цитата:
5.3.4 New
1.
Код:
new-expression:
   ::opt_new new-placement_opt new-type-id new-initializer_opt 
   ::opt_new new-placement_opt ( type-id ) new-initializer_opt 
new-placement:
   ( expression-list )
new-type-id:
   type-specifier-seq new-declarator_opt
new-declarator:
   ptr-operator new-declarator_opt
   noptr-new-declarator 
noptr-new-declarator:
   [ expression ] attribute-specifier-seq_opt
   noptr-new-declarator [ constant-expression ] attribute-specifier-seq_opt
new-initializer:
   ( expression-list_opt )
   braced-init-list
Так что следуя синтаксису Вы выделяете "один элемент" типа int, инициализируя его значением 9:

Код:
new char(9); //new-type-id new-initializer_opt
//new-type-id:
//   type-specifier-seq new-declarator_opt
//new-initializer:
//   ( expression-list_opt )
//new-type-id == char
//expression-list_opt == 9

Цитата:
5.3.4 New
1. Entities created by a new-expression have dynamic storage duration (3.7.4). [ Note: the lifetime of such an entity is not necessarily restricted to the scope in which it is created. — end note ] If the entity is a non-array object, the new-expression returns a pointer to the object created. If it is an array, the new-expression returns a pointer to the initial element of the array.
Цитата:
5.3.4 New
5. When the allocated object is an array (that is, the noptr-new-declarator syntax is used or the new-type-id or type-id denotes an array type), the new-expression yields a pointer to the initial element (if any) of the array. [ Note: both new int and new int[10] have type int* and the type of new int[i][10] is int (*)[10] — end note ] The attribute-specifier-seq in a noptr-new-declarator appertains to the associated array type.

Таким образом здесь:
Код:
strcpy(name, str);
у Вас имеется законное место только для одного символа, а значит в name Вы можете скопировать только пустую строку (в ней будет символ '\0'). Если запишите больше - будет иметь место неопределенное поведение(undefined behavior - UB), которое потому так и называется, что неизвестно что будет - зависит от конкретного компилятора, платформы, состояния памяти и т.д.

Но даже, если Вы скопируете пустую строку и не выйдете за пределы, то Вы вызываете не ту форму delete (их тоже две - для массивов и non-array типов), а это тоже UB:

Цитата:
5.3.4 New
8. A new-expression may obtain storage for the object by calling an allocation function (3.7.4.1). If the new-expression terminates by throwing an exception, it may release storage by calling a deallocation function (3.7.4.2). If the allocated type is a non-array type, the allocation function’s name is operator new and the deallocation function’s name is operator delete. If the allocated type is an array type, the allocation function’s name is operator new[] and the deallocation function’s name is operator delete[]. [Note: an implementation shall provide default definitions for the global allocation functions (3.7.4, 18.6.1.1, 18.6.1.2). A C ++ program can provide alternative definitions of these functions (17.6.4.6) and/or class-specific versions (12.5). — end note ]
Про две формы delete. Синтаксис:

Цитата:
5.3.5 Delete
Код:
1. delete-expression:
   ::opt_delete cast-expression
   ::opt_delete [ ] cast-expression
The first alternative is for non-array objects, and the second is for arrays.
...
2. In the first alternative (delete object), the value of the operand of delete may be a null pointer value, a pointer to a non-array object created by a previous new-expression, or a pointer to a subobject (1.8) representing a base class of such an object (Clause 10). If not, the behavior is undefined. In the second alternative (delete array), the value of the operand of delete may be a null pointer value or a pointer value that resulted from a previous array new-expression.81 If not, the behavior is undefined. [ Note: this means that the syntax of the delete-expression must match the type of the object allocated by new, not the syntax of the new-expression. — end note ] [ Note: a pointer to a const type can be the operand of a delete-expression; it is not necessary to cast away the constness (5.2.11) of the pointer expression before it is used as the operand of the delete-expression. — end note ]

Последний раз редактировалось Croessmah; 22.06.2015 в 17:46.
Croessmah вне форума Ответить с цитированием
Старый 24.06.2015, 22:53   #8
_Bers
Старожил
 
Регистрация: 16.12.2011
Сообщений: 2,329
По умолчанию

Цитата:
Сообщение от Stilet Посмотреть сообщение
Однажды _Bers уже обьяснял, что это за круглые скобки, которые визуализируют тип как функцию. Попробуй поищи ту тему.

P.S. Я если ее найду, я тебе скину ссыль.
вы ошибаетесь.


Код:
int main()
{
   some obj(); //<--- объявление прототипа функции, 
      // а не создание объекта с конструктором по умолчанию.

}
можно писать, вот такой код, например:

http://rextester.com/CVBK10195

Код:

#include <iostream>


void foo(), bar(), baz();


int main()
{
    std::cout << "Hello, world!\n";
    
    foo(), bar(), baz();
    
    int obj(); //<--- создаем прототип функции
      //который все равно нельзя использовать
    
    //потому что язык не поддерживает локальные функции (но можно локальные классы)
    
    // а вот просто объявить - пожалуйста
}

void foo() { std::cout <<"foo\n"; }
void bar() { std::cout <<"bar\n"; }
void baz() { std::cout <<"baz\n"; }

однако в данной ситуации имеет место new-expression

Код:
char * name;

// --- выделяем в куче один единственный символ
// проинициализированный значением 9
name = new char(9);
Цитата:
Сообщение от ACE Valery Посмотреть сообщение
почему компилятор пропускает круглые скобки и не говорит об ошибке
здесь нет ошибки,
это - валидная операция выделения памяти в куче,
и инициализации её при помощи конструктора объекта.

Цитата:
Сообщение от ACE Valery Посмотреть сообщение
а также нормально копирует одну строку в другую, нормально выводит строку, и падает только на удалении.
здесь происходит порча памяти.

компиляторы могут пропасти подобные ошибки.
но не обязаны этого делать.

выставляйте высокий уровень предупреждений.
читайте ворнинги.

подвергайте код статическому анализу.

Последний раз редактировалось Stilet; 25.06.2015 в 08:18.
_Bers вне форума Ответить с цитированием
Старый 25.06.2015, 08:19   #9
Stilet
Белик Виталий :)
Старожил
 
Аватар для Stilet
 
Регистрация: 23.07.2007
Сообщений: 57,097
По умолчанию

Цитата:
вы ошибаетесь.
Поскольку я не пишу на Си, конечно я могу ошибаться, но увы ту тему, где ты расписываешь эту ситуацию я не нашел, поэтому своими словами сказал.
I'm learning to live...
Stilet вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Странности с полиморфизмом _Bers Общие вопросы C/C++ 4 03.02.2012 20:48
UnloadKeyboardLayout - странности Radical_Edward Win Api 0 29.01.2012 14:29
Странности компилятора: ругается на класс Levsha100 Общие вопросы C/C++ 6 17.03.2010 21:37
Странности в Builder 6 Foxtrod C++ Builder 10 03.10.2009 01:09
Странности Chrome` а ]Wowan[ Софт 1 27.04.2009 04:11