Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
Форум программистов > C/C++: Общие вопросы > На пути познания |
Автор: Vendigo 13.1.2006, 18:28 | ||||
Чем спамить в разных темах решил создать свою, где и буду озвучивать все те вопросы которые возникают у меня при изучении этого языка. Добавлено @ 18:34 Для начала сугубо конкретный вопрос. Помогите найти ошибку. У меня есть структура:
И функция которая вводит данные в структуру:
Функция gets() работает неправильно, срабатывает только второй вызов этой функции. Если использовать оператор cin >> то все работает нормально. Насколько я понимаю в функцию gets() в качестве параметра нужно передать имя символьного массива (эдакую строку) без индекса. Имя символьного массива без индекса в свою очередь трактуется в С++ как указатель на его первый [0] элемент. Разве член структуры Data_book[i].name не соответствует этому определению? |
Автор: Partizan 13.1.2006, 18:47 |
Во первых какую размерность имеет Data_book??? упс ![]() |
Автор: _hunter 13.1.2006, 18:52 |
в смысле "рабатывает только второй вызов этой функции"? в чем это выражается? |
Автор: Void 13.1.2006, 19:19 | ||||||
Проблема проявляется из-за того, что оператор >> оставляет в потоке '\n', gets читает его и тут же завершается. Можно убедиться на следующем примере:
Лечение простое:
Манипулятор ws поскипает пробелы и служебные символы. Да, и еще: мешать потоки и C stdio - плохая затея. Вместо gets воспользуйся лучше cin.getline:
|
Автор: bilbobagginz 13.1.2006, 20:38 |
и вообще КТО ЭТОТ Data_book ?! ![]() где он объявлен ? ![]() какого черту далась тебе эта функция в инструкции которой написано: НЕ ИСПОЛЬЗУЙТЕ ЭТУ ФУНКЦИЮ. ? |
Автор: blackofe 13.1.2006, 20:44 | ||
оффтоп, но вспомнилось просто из spaceballs: там в звездолете кнопка большая и красная: "аварийная остановка. ни в коем случае не нажимать!" ![]() |
Автор: Void 13.1.2006, 21:28 | ||||
cin/cout - это стандартные потоки ввода-вывода.
Эта функция не проверяет, не выходят ли введенные данные за пределы выделенного буфера. Поэтому ее категорически не рекомендуется использовать. Вместо нее следует применять fgets или istream::getline. |
Автор: blackofe 13.1.2006, 22:22 | ||
я со всем согласен, но напрашиваются параллели. ведь char a[20] тоже нельзя использовать - потому что легко можно выйти за пределы строки. и какой-нибудь strcat() тоже нельзя использовать. а указатели совершенно не рекомендуется использовать - мало ли что с их помощью можно натворить! а уж new - просто под замок - потому что сплошь и рядом забывают вызывать ответный delete. вывод: не программируйте, други мои. это опасно для жизни. ни в коем случае не наезд и не попытка растления неопытных. но согласитесь, логика таки в моих словах есть. ![]() |
Автор: Void 13.1.2006, 22:28 | ||||
Из вышесказанного, ИМХО, следует несколько иной вывод: не программируйте на C++ - это опасно для жизни. ![]() Прошу не воспринимать как призыв к холивару - просто настроение у меня такое ![]()
Дао, высказанное словами, не есть Дао. ![]() Так что, действительно, давайте не будем растлевать малолетних ![]() |
Автор: blackofe 13.1.2006, 22:42 | ||
deal ![]() а настроение, действительно, того.. только клопов давить под такое настроение ![]() |
Автор: dronzo 13.1.2006, 22:59 | ||
Void, Это не холивар, это ты Страуструпа цитируешь : "Программируя на С вы легко можете прострелить себе ногу, программируя на С++ - это сделать сложнее, но если вы это сделаете, то вам оторвёт ногу целиком". ![]() |
Автор: Void 13.1.2006, 23:14 |
dronzo Так и быть, спрячусь за Мастера ![]() |
Автор: DrLazy 14.1.2006, 01:21 |
dronzo Вывод, не цельтесь себе в ногу, даже в шутку ![]() |
Автор: Vendigo 17.1.2006, 18:42 | ||||
Привет всем, это опять я. Изучение продвигается, сейчас я осваиваю классы. Предыдущий пример со структурой я переписал в виде класса:
Создал массив объектов:
Но опять таки все уперлось в получение строки из консоли. Void пишет, что можно использовать fgets() (вместо gets() которая не работает). Нашел её прототип в справке: char *fgets(char *s, int n, FILE *stream); Объясните параметр FILE *stream, про потоки я еще ничего не знаю, так что... помогите. |
Автор: Vendigo 17.1.2006, 19:21 |
Несколько соображений по поводу классов. Хочу узнать у вас правильно ли я их понимаю. Объекты, которые определяются на основе классов, объединяют в себе данные и методы с помощью которых можно работать с этими данными. Данные нужно описывать в закрытой части класса, чтобы ограничить их использование вне класса. Таким образом данные становятся недоступны из программы, невидимы. Что бы работать с данными нужно использовать методы - функции которые описаны в открытой части класса. В этих функциях нужно проверять правильность ввода/вывода значений в/из закрытых данных, тем самым защищая их. То есть в описанном мною классе Data_list в поле int birthday храниться дата рождения. А через функцию int birthday_put(int a) я получаю эту дату. И в ней я должен предусмотреть что бы вводимое значение являлось действительной датой. Например функция будет возвращать 1 если пользователь ввел правильный формат и полю birthday присвоено значение. И 0, если формат не верен, и данные не записаны. А в программе я буду обрабатывать эти значения. Так? Добавлено @ 19:24 Еще небольшой вопрос. Я работаю в Builder 6, и слева от текста кода, в проводнике, у меня отображается структура класса. Так вот когда я меняю объявление класса эта структура не меняется. Подскажете, как это лечится. |
Автор: Romikgy 18.1.2006, 13:30 |
Вообщето то для работы с файлами , имхо. |
Автор: Vendigo 18.1.2006, 20:00 | ||||
Млин, товарищи сертифицированные специалисты. Может разьясните как правильно получить строку из консоли? А то чегой то у меня ![]() Вот полный текст программы:
Так тож не получается:
|
Автор: asdf 18.1.2006, 21:48 | ||
|
Автор: asdf 18.1.2006, 22:26 | ||||
ещё ты можешь получать доступ к закрытым членам класса, указав функцию не являющуюся членом, как friend в его объявлении.
|
Автор: Vendigo 19.1.2006, 00:32 |
Спасибо asdf, вроде работает. Сейчас уже поздно, завтра буду разбираться.![]() ![]() ![]() |
Автор: Vendigo 20.1.2006, 20:15 | ||
1. Все, разобрался ![]() Оказывается у меня и здесь еще была ошибка:
я получал первый символ а не указатель на него! 2. Подскажите пожалуйста функцию которая возвращает код символа. Перерыл все свои книги и весь форум не могу найти такой простой вещи. |
Автор: Void 20.1.2006, 20:28 | ||
Ее нет ![]() |
Автор: Mayk 20.1.2006, 20:50 | ||||||
Просто кастаните в int.
Теперь потабаним.
Почти согласен. Только не так категарично. strcat действительно не следует использовать в общем случае. Точно так же как не стоит использовать strcpy и sprintf. Вместо них лучше использовать strncat, strncpy, snprintf (пример из жизни - скаченная и собранная quake1 у меня вылетала, так как там в Sys_Printf использовали vsprintf на 1024 байтный буфер, а строка(которая содержала всякие характеристики видюхи, и вообще была юзеру(мне) не нужна) получалась более 1024 символов. Результат - Segmentation fault). Про new - есть такие замечательные штуки как auto_ptr и shared_ptr, которые при определенным стечении обстоятельств позволят избежать утечек памяти и не вызывать delete. Указатели порой действительно можно заменить ссылками, что а) предотвратит передачи NULL'а, и кроме того б) увеличит скорость разработки , так как вместо "if(a) a->b" можно будет писать "a.b" :-) Вывод: используйте безопасные функции, и ваши волосы будут мягкими и пушистими. Соглсен ![]() зы. Вот чем хорош стандарт - там ф-ции snprintf и sprintf описываются рядом. Во всяких книжках "с++ за обеденный перерыв" (во всяком случае в тех, что попадались мне) такого можно не дождаться. Кстати, в С99 ф-ция snprintf(7.19.6.5) описывается ДО sprintf(7.19.6.6) ![]() |
Автор: Vendigo 20.1.2006, 21:25 | ||||
Void Mayk Спасибо! Всего труднее найти то, что у тебя перед глазами ![]() Можете еще объяснить про кодировки? Я сделал так:
И получил таблицу символов. Так эти символы отображаются в консоли. Что то мне подсказывает что в оконном приложении символы были бы другие (или расположенны по другому). И еще такой вопрос:
|
Автор: blackofe 20.1.2006, 21:43 | ||
вполне возможно. хотя бы потому, что оконное приложение могло использовать windows-кодировку, а консольное - dos-кодировку. про кодировку тут говорили не раз. воспользуйся поиском. к примеру, можно поискать слово "locale". |
Автор: Fin 20.1.2006, 21:44 | ||
Что то тебе подсказывает правильно. Досовская русская кодировка (CP-866) отличается от кодировки Винды (Windows-1251) в верхней части таблици. До символа с номером 127 все кодировки повторяются. Как выглядит кодировка можно посмотреть Character Map которая идет в комплекте постаки винды. Там нужно вызвать на показ любой шрифт соответствуюший кодировке винды. Я например смотрю или Arial или Courier New Cyr. |
Автор: asdf 22.1.2006, 13:07 | ||
переоткрытием проекта. если перед изменением объявления ты переходишь к нему 2х кликом в проводнике классов, структура должна правиться сходу .... |
Автор: Vendigo 25.1.2006, 19:21 | ||
Ничего не понимаю ![]() Я написал код который как я думаю выводит DOS кодировку символов. Но обратное преобразование не получается т.е. (int)c возвращает странный код. Например если char c = 'б' то (int)c = -95 ![]()
|
Автор: Void 25.1.2006, 19:57 |
Объяви c, как unsigned char. |
Автор: Vendigo 25.1.2006, 22:22 |
Все понял! Спасибо Void ![]() Если у меня char то коды лежат в пределах от -128 до 127 ! Чтоб я делал без этого форума! |
Автор: Vendigo 12.2.2006, 21:45 | ||||
Всем доброго времени суток ![]() Главный вопрос, конечно же, остался: Смогу ли я когда-нибудь выучить этот С++? И если да, то сколько мне его еще штудировать? Но появляются и более "низменные" вопросы. Так в главе "Перегрузка операторов" автор рассматривает создание своего класса строк:
Вопрос такой: Зачем в этом классе перегрузка оператора присваивания? Ведь класс не содержит в своих данных указателей. Операция присваивания, которая определена по умолчанию (побитовая копия) прекрасно работает. Зачем огород городить? И второй вопрос: Присваивание строки с завершающим нулем. Имхо так было бы проще:
|
Автор: Mayk 14.2.2006, 08:55 | ||
Наверное, чтобы не копировать три сотни символов, если можно меньше скопировать. А вообще strcpy надо заменить на strncpy(); А то на длинных строках будет ой. В operator'ах и конструкторе char* заменить на const char*, и возвращать в operator='ах не str_type, а str_type&. |
Автор: Vendigo 14.2.2006, 21:19 |
Насколько я понимаю, const char* в параметрах служит для того, чтобы функция не могла изменить переданный ей аргумент. А это что значит? "возвращать в operator='ах не str_type, а str_type&." ( Я знаю, только, что &a значит "Получить адрес переменной а" ) |
Автор: Lotrex 15.2.2006, 09:08 | ||||||
Это значит, что фактически (на уровне команд) будет возвращатся не значение, а указатель. На уровне С++ будет отличие - такой указатель назыв. ссылкой, но разыменовывать его не надо - он как бы уже разыменован, и с ним надо обращатся как с переменной, содержащей некоторое значение, а не адрес. Отсюда существенное отличие записей
и
отличия будут в выражениях типа следующего:
В первом случае значение возвращаемого пр-ра будет копироватся дважды - один раз внутри оператора b = c (при вызове оператора return str; где str имеет тип str_type) произойдет копирование в стек, потом - передача адреса содержимого стека в качестве входного параметра в операторе a = b. Во втором случае в стек сначала будет копироватся значение не содержимого str, а ее адреса, и если str будет автоматической (стековой) переменной, то во втором операторе (a = b) произойдет ошибка. |
Автор: Vendigo 2.3.2006, 20:54 | ||||||||||
Добрый вечер всем кто в сети ![]() Упражнялся я со своим Builderom и в результате неких экспериментов накопил к вам ряд вопросов. Допустим мне нужно чтоб функция возвращала двумерный массив. Например такой
Целиком массив из функции вернуть нельзя, так же как нельзя в нее массив передать. Для этого используется указатель на первый элемент массива так? Но как оказалось недостаточно объявить ф-ию:
и в ней написать
компилятор ругается "E2034 Cannot convert 'int ( *)[25]' to 'int *'" – не знаю, что это значит. Хоть учебник и утверждает, что "использование имени массива без индекса генерирует указатель на первый элемент" Я поступил таким образом:
И только было возрадовался своей хитрости, сумевшей обмануть компилятор, как обнаружил, что программа все равно не работает!!! Меня ждало жестокое разочарование! Массив созданный внутри функции, суть локальные переменные, и указатель на его начало, никоим образом мне помочь не может. Как только функция завершается память тотчас освобождается. В итоге я остался там же где и начал. Неужели нет способа возвратить из функции массив? Весь код:
|
Автор: sergejzr 2.3.2006, 20:55 |
Модератор: Название темы должно отражать ее суть! Модератор: Пожалуйста, один топик - один вопрос. |
Автор: Vendigo 2.3.2006, 20:57 | ||
И другой вопрос, уже не такой философско-риторический, допустим, я хочу передать двумерный массив в функцию.
И использую указатель int *d в ее параметре. Как мне обращаться к элементам этого массива? d[i][j] – не работает (в принципе понятно почему) писать что то вроде этого: d[i*r+j] , где r – длинна строки в массиве? |
Автор: MAKCim 2.3.2006, 22:06 | ||||
может d[i*(r-1)+j], в C/C++ обычно первый индекс 0 Добавлено @ 22:07
либо память динамически выделять, либо пользоваться std::vector, можешь написать свой класс, ... |
Автор: Vendigo 2.3.2006, 22:49 | ||||
Точно! Можно же так
vector я еще не разбирал, а свой класс писать для такой простой вещи... |
Автор: Void 2.3.2006, 23:36 |
Ты компилировать это пробовал? |