Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Некорректное завершение программы!?

29K
29 мая 2009 года
EXAngel
29 / / 08.07.2008
Есть два варианта кода:
Цитата:
1. Это писал я, поэтому он работает некорректно. Выводится нужная информация, но завершается не правильно.


Код:
// newstr.cpp
// using new to get memory for strings
#include <iostream>
#include <cstring>       //for strcpy(), etc
#include <Cctype>
using namespace std;
////////////////////////////////////////////////////////////////
class String             //user-defined string type
   {
   private:
      char* str;                    //pointer to string
   public:
      String(char* s)               //constructor, one arg
         {
         int length = strlen(s);    //length of string argument
         str = new char[length+1];  //get memory
         strcpy(str, s);            //copy argument to it
         }
      ~String()                     //destructor
         {
         cout << "\nDeleting str\n";
         delete[] str;              //release memory
         }
      void display()                //display the String
         {
         cout << str << endl;
         }

    void upit();
   };
//--------------------------------------------------------------
void String::upit()
{
    while(*str)
    {
        putchar (toupper(*(str++)));
    }
}
////////////////////////////////////////////////////////////////
int main()
   {                                //uses 1-arg constructor
   String s1 = "Who knows nothing doubts nothing.";

   cout << "s1=";                   //display string
   s1.display();
   s1.upit();
   return 0;
   }

Если закомментировать деструктор, тогда все ОК!
Цитата:
2. Этот код из книги и работает верно(оба делают одно и то же, переводят строку в верхний регистр).


Код:
// ex10_2.cpp
// member function converts String objects to upper case
#include <iostream>
#include <cstring>       //for strcpy(), etc
#include <cctype>        //for toupper()
using namespace std;
////////////////////////////////////////////////////////////////
class String             //user-defined string type
   {
   private:
      char* str;                    //pointer to string
   public:
      String(char* s)               //constructor, one arg
         {
         int length = strlen(s);    //length of string argument
         str = new char[length+1];  //get memory
         strcpy(str, s);            //copy argument to it
         }
      ~String()                     //destructor
         { delete str; }
      void display()                //display the String
         { cout << str; }
      void upit();                  //uppercase the String
   };
//--------------------------------------------------------------
void String::upit()                 //uppercase each character
   {
   char* ptrch = str;               //pointer to this string
   while( *ptrch )                  //until null,
      {
      *ptrch = toupper(*ptrch);     //uppercase each character
      ptrch++;                      //move to next character
      }
   }
////////////////////////////////////////////////////////////////
int main()
   {
   String s1 = "He who laughs last laughs best.";

   cout << "\ns1=";       //display string
   s1.display();
   s1.upit();             //uppercase string
   cout << "\ns1=";       //display string
   s1.display();
   cout << endl;
   return 0;
   }

Вопросы:
1. Почему 1й вариант работает неправильно?
2. toupper как-то работает с 'cout'?
535
29 мая 2009 года
Нездешний
537 / / 17.01.2008
Внимание, вопрос: куда указывает str после выполнения метода upit?
29K
29 мая 2009 года
EXAngel
29 / / 08.07.2008
Цитата:
Внимание, вопрос: куда указывает str после выполнения метода upit?


На '\0' (последний нулевой символ массива)?
Получается что деструктор не удаляет str?

После этого все заработало:

 
Код:
void String::upit()
{
    while(*str)
    {
        putchar (toupper(*(str++)));
    }
    str=0;
}

Отсюда вытекают 2 вопроса:
1. Почему в первом случае:
 
Код:
~String()                     //destructor
         {
         cout << "\nDeleting str\n";
         delete[] str;              //release memory
         }

В втором:
 
Код:
~String()                     //destructor
         { delete str; }

В книге я читал чтобы удалить массив нужно после delete поставить []...
2. Для чего была сделана ссылка на ссылку?
 
Код:
*ptrch = toupper(*ptrch);

Для того чтобы не обнулять str?
87
29 мая 2009 года
Kogrom
2.7K / / 02.02.2008
Цитата: EXAngel
На '\0' (последний нулевой символ массива)?
Получается что деструктор не удаляет str?


да

Цитата: EXAngel
После этого все заработало:
 
Код:
void String::upit()
{
    while(*str)
    {
        putchar (toupper(*(str++)));
    }
    str=0;
}


Не заработало. Память не освобождается. Указатель не вернулся к исходной точке.

Цитата: EXAngel
2. Для чего была сделана ссылка на ссылку?
 
Код:
*ptrch = toupper(*ptrch);

Для того чтобы не обнулять str?


Не ссылка на ссылку, а разименовавание указателя.

397
29 мая 2009 года
SergPas
527 / / 03.02.2007
Дело в том, что функция upit() смещает указатель на следующий байт за последним символом строки str и фактически ни на что не указывает.
Поэтому Вам надо сместить указатель на начальную позицию, либо сохранить эту позицию во временной переменной с последующим восстановлением, например так:
 
Код:
void String::upit()
{
    char* tmp = str;
    while(*str)
    {
        putchar (toupper(*(str++)));
    }
    str = tmp;
}

Либо так:
 
Код:
void String::upit()
{
    char* tmp = str;
    while(*tmp)
    {
        putchar (toupper(*(str++)));
    }
}

Тогда и деструктор вызывается корректно:
 
Код:
~String()                     //destructor
{
         cout << "\nDeleting str\n";
         delete [] str;              //release memory
}
Ко всему прочему, Вы не преобразуете строку к верхнему регистру... Можете повторно вызвать метод display() и убедиться в этом на практике:
Код:
int main()
   {                                //uses 1-arg constructor
   String s1 = "Who knows nothing doubts nothing.";

   cout << "s1=";                   //display string
   s1.display();
   s1.upit();
   cout<<endl;
   s1.display();
   return 0;
   }
Лучше, наверно, использовать библиотечную функцию strupr()
P.S. Все беды топикстартера из-за невнимательности...
29K
29 мая 2009 года
EXAngel
29 / / 08.07.2008
Да вроде работает:

Код в приложении.

Цитата:
Не заработало. Память не освобождается. Указатель не вернулся к исходной точке.


Разве str=0; не выставляет указатель на начало?
Или Вы хотите сказать что str=0 не равно адресу первого элемента?

Цитата:
Не ссылка на ссылку, а разименовавание указателя.


Это я погорячился. :p действительно разыменование..

Цитата:
Ко всему прочему, Вы не преобразуете строку к верхнему регистру... Можете повторно вызвать метод display() и убедиться в этом на практике:


Да, действительно я только вывожу ее на экран..

P.S.

Цитата:
Все беды топикстартера из-за невнимательности...


И это тоже. Но еще ко всему тема по указателям идет тяжеловато..
Чем дальше двигаюсь по книге, тем больше раз перечитываю главы :)

397
29 мая 2009 года
SergPas
527 / / 03.02.2007
Цитата:
Да вроде работает:

Работает, но Вы не удалили выделенную под массив память (утечка)...:)

Цитата:
Разве str=0; не выставляет указатель на начало?
Или Вы хотите сказать что str=0 не равно адресу первого элемента?

Не выставляет и не равно адресу первого элемента. (адрес str станет равным 0x00000000)
Мой Вам совет - воспользуйтесь дебагером и Вы поймёте как работает программа...

29K
29 мая 2009 года
EXAngel
29 / / 08.07.2008
Цитата:
Работает, но Вы не удалили выделенную под массив память (утечка)


Так вот что такое утечки памяти... :rolleyes: вот я сними и столкнулся..

Спасибо за помощь.

Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог