Форум программистов, компьютерный форум CyberForum.ru
Наши страницы

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
 
Рейтинг: Рейтинг темы: голосов - 23, средняя оценка - 4.78
Stalin45
2 / 2 / 0
Регистрация: 24.04.2011
Сообщений: 66
#1

Null pointer assignment. - C++

24.08.2011, 00:20. Просмотров 3052. Ответов 25
Метки нет (Все метки)

Здравствуйте. Такая проблема: Пытаюсь вызвать функция класса Up()
s2 = s1.up(), возвращая указатель на строку (по-умолчанию в s2 пустая строка имеет адрес NULL).
Вот только почему передается не ссылка, а само значение строки, поскольку компилятор пишет: null pointer assignment. Значит ссылка не поменялась, и он, не выделив память, прострочил прямо с нулевого адреса...
И второй вопрос, как можно в данном случае все-таки передать значение (хотя первый вопрос в силе), но так, чтобы выделить точное кол-во памяти под передаваемую строку в s2?
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include "iostream.h"
#include "CONIO.h"
#include "Ctype.h"
#include "string.h"
using namespace std;
class String
{
 private:
  char* st;
 public:
  String(): st(NULL) {}
  String(char* str) {int len = strlen(str);
             st = new char[len+1]; strcpy(st, str);
            }
  ~String() {delete st;}
  void show()const {cout<<endl<<st;}
  String up() {int len = strlen(st);
           for(int i=0; i<len; i++) st[i] = toupper(st[i]); return st;
          }
};
///////////////////
int main()
{
 String s1 = "Test yes TEsT";
 String s2;
 s2 = s1.up();
 s2.show();
 getch();
return 0;
}
Заранее благодарен!
0
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
24.08.2011, 00:20
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Null pointer assignment. (C++):

Null pointer assignment - C++
Помогите найти ошибку, при заполнении массива вручную в конце выдает - Null pointer assignment. И еще вопрос, как сделать чтобы после...

Ошибка Null pointer assignment - C++
Помогите, пожалуйста, кто знает. BC++ 3.11 выдает 'Null pointer assignment'. Я, в принципе, в курсе, что это из-за того, что я...

Error null pointer assignment - C++
Помогите, программа, которая создает вектор элементы которого равны сумме положительных элементов столбца массива, в конце выводит null...

Null pointer - C++
void C_StringBit :: setStrBit() { char* ptr1; cout &lt;&lt; &quot;Введите строку&quot;&lt;&lt; endl; cin &gt;&gt; ptr1; lengthBit = strlen(ptr1); ...

Invalid null pointer - C++
Так она работает: #include &lt;iostream&gt; #include &lt;conio.h&gt; #include &lt;list&gt; #include &lt;string&gt; using namespace std; void...

string, invalid null pointer - C++
#include &lt;stdio.h&gt; #include &lt;iostream&gt; #include &lt;string&gt; using namespace std; #define SIZE 450 ...

Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
grizlik78
Эксперт С++
1913 / 1445 / 113
Регистрация: 29.05.2011
Сообщений: 3,001
24.08.2011, 00:46 #2
Проблема вот в чём.
В строке 26 функция up() создаёт временный объект String (из указателя). Дальше этот временный объект используется для создания s2 с помощью конструктора копирования. Затем временный объект уничтожается.
А теперь сама проблема: конструктор копирования, созданный компилятором, копирует только указатель, но не само содержимое строки. После удаления временного объекта копия указателя в новом объекте указывает на уже удалённую область памяти.
Выход: определить свой конструктор копирования, который будет осуществлять "глубокое копирование", то есть скопирует не указатель, а саму строку.

Добавлено через 15 минут
Цитата Сообщение от Stalin45 Посмотреть сообщение
возвращая указатель на строку
Цитата Сообщение от Stalin45 Посмотреть сообщение
Вот только почему передается не ссылка, а само значение строки
Ну во-первых всё-таки указатель, а не ссылку.
Во вторых, функция объявлена как возвращающая String, поэтому создаётся временный оъект. А поскольку конструктор объявлен без explicit, то осуществляется неявное преобразование из указателя.
Проблема должна уйти, если объявить функцию up() как возвращающую указатель, но тем не менее конструктор копирования для такого класса в любом случае нужен.

Добавлено через 2 минуты
И ещё, в конструктор было бы правильнее принимать указатель на константную строку, то есть
C++
1
String(const char* str)
или
C++
1
String(char const* str)
что одно и то же.
1
ValeryLaptev
Эксперт С++
1041 / 820 / 48
Регистрация: 30.04.2011
Сообщений: 1,659
24.08.2011, 02:33 #3
Класс, в котором конструктор динамически запрашивает память, обязан реализовать: конструктор копирования, деструктор, операцию присваивания. Остальное - по необходимости.
1
Deviaphan
Делаю внезапно и красиво
Эксперт C++
1287 / 1221 / 50
Регистрация: 22.03.2011
Сообщений: 3,744
24.08.2011, 08:12 #4
Цитата Сообщение от ValeryLaptev Посмотреть сообщение
обязан реализовать
Либо запретить их использование помещением их определения в private.
2
Stalin45
2 / 2 / 0
Регистрация: 24.04.2011
Сообщений: 66
24.08.2011, 13:34  [ТС] #5
grizlik78, огромное спасибо за разъяснение механизма возврата (я считал, что функция up() возвращает объект объект String, через который и запускалась функция изначально, а не создает временный и недолговечный. Это многое объясняет!).

Цитата Сообщение от ValeryLaptev Посмотреть сообщение
Класс, в котором конструктор динамически запрашивает память, обязан реализовать: конструктор копирования, деструктор, операцию присваивания. Остальное - по необходимости.
Операция присваивания...если я правильно понял, то это перегрузка operator= (никогда раньше не использовал).
Попробовал динамически выделить память:
C++
1
2
3
4
5
  String operator= (const String* s1) {int len = strlen(s1->st);
                       st = new char[len+1];
                       strcpy(st, s1->st);
                       return String(st);
                      }
Как всегда все работает, однако в конце все ещё надпись: Null poinet assignment.
Но ведь на этот раз память выделена! Быть может эта надпись появляется даже когда просто NULL адрес был присвоен, но значение в нем не изменено?
C++
1
  String(): st(NULL)
C++
1
2
3
 String s2;
 s2 = s1;
 s2.show();
0
Deviaphan
Делаю внезапно и красиво
Эксперт C++
1287 / 1221 / 50
Регистрация: 22.03.2011
Сообщений: 3,744
24.08.2011, 13:40 #6
Цитата Сообщение от Stalin45 Посмотреть сообщение
однако в конце все ещё надпись: Null poinet assignment.
Так и ошибка никуда не делась.)
Возвращать нужно не String, а String&
1
ForEveR
В астрале
Эксперт С++
7972 / 4734 / 321
Регистрация: 24.06.2010
Сообщений: 10,542
Завершенные тесты: 3
24.08.2011, 13:40 #7
Stalin45, Сигнатура оператора неверная.

C++
1
String& operator= (const String& s1);
1
Stalin45
2 / 2 / 0
Регистрация: 24.04.2011
Сообщений: 66
24.08.2011, 13:45  [ТС] #8
Вот я дурак, я же не указатели на String присваиваю друг другу, а обычные объекты!! Т.е. моя функция operator= (String* s1) даже не вызывалась...
Получилось решить проблему строкой:
C++
1
 s2 = &s1
но, верно, в данном случае удобнее изменить сам operator=
Спасибо!
0
grizlik78
Эксперт С++
1913 / 1445 / 113
Регистрация: 29.05.2011
Сообщений: 3,001
24.08.2011, 13:45 #9
Кстати да, я почему-то рассказал про конструктор копирования, хотя в данном случае используется операция присваивания. Ну да не суть, они оба должны быть определены.
И помимо неправильной сигнатуры есть ещё маленькая деталь — в операторе присваивания стоит проверять на присваивание самому себе (это в данном случае не важно, но всё-таки), а ещё перед присваиванием удалять старое содержимое.
1
ValeryLaptev
Эксперт С++
1041 / 820 / 48
Регистрация: 30.04.2011
Сообщений: 1,659
24.08.2011, 13:50 #10
Герб Саттер приводит много более элегантную реализацию операции присваивания:
C++
1
2
3
4
5
6
Листинг 3.12. Реализация операции присваивания "по Саттеру"
TArray& TArray::operator=(const TArray &t)
{ TArray temp(t);       // временнный локальный объект temp = t
  Swap(temp);           // обмен полями с текущим объектом
  return *this;             // возврат текущего объекта
}                   // temp уничтожен
Swap - это функция обмена. Часто можно использовать std::swap().
1
Deviaphan
Делаю внезапно и красиво
Эксперт C++
1287 / 1221 / 50
Регистрация: 22.03.2011
Сообщений: 3,744
24.08.2011, 15:11 #11
Цитата Сообщение от ValeryLaptev Посмотреть сообщение
много более элегантную реализацию операции присваивания
Причём, устраняющую проблему самоприсваивания.
Но там ещё есть условие, что Swap должна быть бессбойной.
1
ValeryLaptev
Эксперт С++
1041 / 820 / 48
Регистрация: 30.04.2011
Сообщений: 1,659
24.08.2011, 15:24 #12
Цитата Сообщение от Deviaphan Посмотреть сообщение
Причём, устраняющую проблему самоприсваивания.
Но там ещё есть условие, что Swap должна быть бессбойной.
Да. И стандартная swap этому удовлетворяет.
Поэтому я практически всегда стараюсь использовать вариант Саттера - писать меньше...
1
Deviaphan
Делаю внезапно и красиво
Эксперт C++
1287 / 1221 / 50
Регистрация: 22.03.2011
Сообщений: 3,744
24.08.2011, 15:26 #13
Цитата Сообщение от ValeryLaptev Посмотреть сообщение
И стандартная swap этому удовлетворяет.
Не удовлетворяет. Если у объекта нет бессбойного конструктора копирования и деструктора, то не удовлетворяет.
2
ValeryLaptev
Эксперт С++
1041 / 820 / 48
Регистрация: 30.04.2011
Сообщений: 1,659
24.08.2011, 16:05 #14
Цитата Сообщение от Deviaphan Посмотреть сообщение
Не удовлетворяет. Если у объекта нет бессбойного конструктора копирования и деструктора, то не удовлетворяет.
Спасибо за напоминание...
1
Сыроежка
Заблокирован
24.08.2011, 21:22 #15
Цитата Сообщение от ValeryLaptev Посмотреть сообщение
Герб Саттер приводит много более элегантную реализацию операции присваивания:
C++
1
2
3
4
5
6
Листинг 3.12. Реализация операции присваивания "по Саттеру"
TArray& TArray::operator=(const TArray &t)
{ TArray temp(t);       // временнный локальный объект temp = t
  Swap(temp);           // обмен полями с текущим объектом
  return *this;             // возврат текущего объекта
}                   // temp уничтожен
Swap - это функция обмена. Часто можно использовать std::swap().
Нельзя использовать std::swap, так как в вашем примере используется синтаксис для вызова функции swap - члена класса.

Добавлено через 7 минут
Цитата Сообщение от Stalin45 Посмотреть сообщение
Здравствуйте. Такая проблема: Пытаюсь вызвать функция класса Up()
s2 = s1.up(), возвращая указатель на строку (по-умолчанию в s2 пустая строка имеет адрес NULL).
Вот только почему передается не ссылка, а само значение строки, поскольку компилятор пишет: null pointer assignment. Значит ссылка не поменялась, и он, не выделив память, прострочил прямо с нулевого адреса...
И второй вопрос, как можно в данном случае все-таки передать значение (хотя первый вопрос в силе), но так, чтобы выделить точное кол-во памяти под передаваемую строку в s2?
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include "iostream.h"
#include "CONIO.h"
#include "Ctype.h"
#include "string.h"
using namespace std;
class String
{
 private:
  char* st;
 public:
  String(): st(NULL) {}
  String(char* str) {int len = strlen(str);
             st = new char[len+1]; strcpy(st, str);
            }
  ~String() {delete st;}
  void show()const {cout<<endl<<st;}
  String up() {int len = strlen(st);
           for(int i=0; i<len; i++) st[i] = toupper(st[i]); return st;
          }
};
///////////////////
int main()
{
 String s1 = "Test yes TEsT";
 String s2;
 s2 = s1.up();
 s2.show();
 getch();
return 0;
}
Заранее благодарен!
У вас тут несколько ошибок. первое - у вас не определен конструктор копирования. Второе - у вас нет определения оператора присваивания. Третье - в деструкторе вы вместо delete выражения должны использовать delete [] выражение, так как вы должны удалить массив. Четвертое - в функции up вы не делаете проверку на то, что ваш указатель равен NULL.

Саму функцию up можно написать проще.

C++
1
2
3
4
5
6
7
8
9
String String::up() const
{
   if ( st )
   {
      while ( *st ) *st = toupper( *st );
   }
 
   return ( st );
}
1
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
24.08.2011, 21:22
Привет! Вот еще темы с ответами:

Что делать, если "просят" разыменовать null-pointer? - C++
Есть код примерно следующего содержания: class Foo { private: int *ptr; public: int&amp; operator*() { ...

Из-за чего может возникать следующая ошибка: "Invalid null pointer"? - C++
NEBTELA* fggff; //указатель на объект базового класса fggff = new Zvezda; //переопределение в объект производного класса в...

Shared_ptr - stored pointer, owned pointer - C++
Зачем в shared_ptr нужен хранимый указатель, отличный от владеемого? И так в этом средстве, вроде как предназначенном для уменьшения...

delete[] *pointer vs. delete pointer и утечка памяти - C++
Здравствуйте! Есть класс &quot;умного&quot; указателя counted_ptr, который удаляет хранящийся в нём T* owned; только если кол-во владельцев...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
Yandex
Объявления
24.08.2011, 21:22
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru