Форум русскоязычного сообщества Ubuntu


Получить помощь и пообщаться с другими пользователями Ubuntu можно
на irc канале #ubuntu-ru в сети Freenode
и в Jabber конференции ubuntu@conference.jabber.ru

Автор Тема: Segmentation fault  (Прочитано 769 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Оффлайн R170

  • Автор темы
  • Участник
  • *
  • Сообщений: 144
    • Просмотр профиля
Segmentation fault
« : 07 Февраль 2015, 19:28:52 »
Попробуйте запустить.Все же вроде правильно.
Код: C
  1. #include <iostream>
  2. using namespace std;
  3.  
  4. class object{
  5.         void (*f)(object*);
  6. public:
  7.         void setFunc(void (*func)(object*)){
  8.                 f = func;
  9.         }
  10.         void callFunc(){
  11.                 f(this);
  12.         }
  13. };
  14.  
  15. class Objects{
  16.         object **mass;
  17.         int size;
  18. public:
  19.         Objects(){
  20.                 size = 0;
  21.                 mass = new object*[size];
  22.         }
  23.         void addObject(object *ob){
  24.                 mass[size++] = ob;
  25.         }
  26.         void callFuncs(){
  27.                 for(int c=0;c<size;c++){
  28.                         mass[c]->callFunc();
  29.                 }
  30.         }
  31. };
  32.  
  33. void out(object *o){
  34.         cout<<o<<endl;
  35. }
  36.  
  37. int main(){
  38.         Objects Main;
  39.         object *n;
  40.         for(int c=0;c<5;c++){
  41.                 n = new object;
  42.                 n->setFunc(out);
  43.                 Main.addObject(n);
  44.         }
  45.         Main.callFuncs();
  46.         return 0;
  47. }
  48.  
Спасибо

Оффлайн goditsa8

  • Участник
  • *
  • Сообщений: 231
    • Просмотр профиля
Re: Segmentation fault
« Ответ #1 : 07 Февраль 2015, 21:13:22 »
Как ни старался, так и не понял, что делает ваша программа. :)
Но, если строку mass = new object*[size]; заменить на mass[size] = new object; то она, по крайней мере, работает и, похоже, выводит адреса объектов object.

Оффлайн R170

  • Автор темы
  • Участник
  • *
  • Сообщений: 144
    • Просмотр профиля
Re: Segmentation fault
« Ответ #2 : 07 Февраль 2015, 21:20:38 »
Есть 2 класса.
object имеет 2 метода
setFunc записывает функцию в закрытую переменную f
callFunc вызывает функцию которая записана в f
Objects имеет тоже 2 метода
addObject lj, записывает адресс обекта в масив
callFuncs вызывает метод callFunc каждого обекта записаного в массив

Пользователь решил продолжить мысль 07 Февраль 2015, 21:22:22:
Если заменить for(int c=0;c<5;c++){ на for(int c=0;c<4;c++){ ошибка не возникает. Почему?
« Последнее редактирование: 07 Февраль 2015, 21:22:22 от R170 »

Оффлайн Кровавый

  • Старожил
  • *
  • Сообщений: 1626
  • Логика творит чудеса!
    • Просмотр профиля
Re: Segmentation fault
« Ответ #3 : 07 Февраль 2015, 21:28:46 »
VC++ съел и даже не поругался. Тем не менее, память вы порите.  :)

Тут вы создали массив указателей нулевого размера:
Код: C++
  1. Objects()
  2. {
  3. size = 0;
  4. mass = new object*[size];
  5. }



VC такое ест, так как в нем разрешено создавать массивы нулевого размера (в WDM используется, чтобы получать смещение динамических данных из буффера).


В вашем же случае, нужно либо передавать размер mass в конструктор Objects, либо при вызове addObject пересоздавать mass.

Пользователь решил продолжить мысль 07 Февраль 2015, 21:44:54:
Массив mass динамически вроде. Он должен сам расширяться.
Вот здесь
Код: C
  1. mass[size++] = ob;


В C/C++ нет динамических массивов. Можете, конечно, использовать std::vector (в новых стандартах std::array). Вот они динамические. А тут вы выделяете участок памяти, размер которого равен размеру object*, умноженному на size, т.е. на 0. В итоге, у вас mass хранит адрес начала памяти, но буффера там нет, поскольку его длинна равна 0. Там может быть все, что угодно. Туда вы пишете по порядку адреса указателей. Но эта память может содержать что угодно, в т.ч. и данные процесса (нитки). Вы их перетираете и получаете сигфолт.  :)
« Последнее редактирование: 07 Февраль 2015, 21:44:54 от Кровавый »
Железо: AMD FX8350 4.2Ghz + 2x4Gb Kingston HeyperX + Asus M5A97 R2.0 + HDD WD WZ10EZEX 1TB 7200 rpm + SSD 128 GB + Win 10 x64.

Оффлайн goditsa8

  • Участник
  • *
  • Сообщений: 231
    • Просмотр профиля
Re: Segmentation fault
« Ответ #4 : 07 Февраль 2015, 21:47:54 »
R170,
Цитировать
Если заменить for(int c=0;c<5;c++){ на for(int c=0;c<4;c++){ ошибка не возникает. Почему?
Видимо, особенность реализации компилятора g++. По-ходу, когда Вы инициализируете массив указателей с нулевым числом элементов, компилятор выделяет под него какой-то определенный объем памяти, и в него потом случайным образом влазят максимум 4 объекта object. Но это только мое предположение.
Цитировать
Массив mass динамически вроде. Он должен сам расширяться.
Нет, не динамический, Вы уже задали ему размер size = 0

Оффлайн R170

  • Автор темы
  • Участник
  • *
  • Сообщений: 144
    • Просмотр профиля
Re: Segmentation fault
« Ответ #5 : 07 Февраль 2015, 21:50:46 »
Цитировать
Массив mass динамически вроде. Он должен сам расширяться.
Нет, не динамический, Вы уже задали ему размер size = 0
Код: C
  1. mass[size++] = ob;

Пользователь решил продолжить мысль 07 Февраль 2015, 21:53:50:
VC++ съел и даже не поругался. Тем не менее, память вы порите.  :)

Тут вы создали массив указателей нулевого размера:
Код: C++
  1. Objects()
  2. {
  3. size = 0;
  4. mass = new object*[size];
  5. }

VC такое ест, так как в нем разрешено создавать массивы нулевого размера (в WDM используется, чтобы получать смещение динамических данных из буффера).
В вашем же случае, нужно либо передавать размер mass в конструктор Objects, либо при вызове addObject пересоздавать mass.
Ну вы говорите пересоздавать массив при каждом вызове addObject, что вы имеете ввиду?
« Последнее редактирование: 07 Февраль 2015, 21:53:50 от R170 »

Оффлайн Кровавый

  • Старожил
  • *
  • Сообщений: 1626
  • Логика творит чудеса!
    • Просмотр профиля
Re: Segmentation fault
« Ответ #6 : 07 Февраль 2015, 21:57:57 »
Код: C
  1. mass[size++] = ob;


Этой строкой вы только пишите в память и увеличиваете size на единицу.  :)
Для простоты скажем, что mass имеет содержит адрес 0x0000. Размер object* равен 8 байт (по хорошему, конечно, 32 или 64, но так проще считать). Тогда:


size = 0:
Тогда ob запишется по адресу 0xAAAA0000 + 0x8 * 0, т.е. по 0x0000

size = 1:
Тогда ob запишется по адресу 0xAAAA0000 + 0x8 * 1, т.е. по 0x0008


size = 2:
Тогда ob запишется по адресу 0xAAAA0000 + 0x8 * 2, т.е. по 0x0010


size = 3:
Тогда ob запишется по адресу 0xAAAA0000 + 0x8 * 3, т.е. по 0x0018


size = 4:
Тогда ob запишется по адресу 0xAAAA0000 + 0x8 * 0, т.е. по 0x0020


Общая длинна - 0x28, что соответствует буферу в 40 байт.
Железо: AMD FX8350 4.2Ghz + 2x4Gb Kingston HeyperX + Asus M5A97 R2.0 + HDD WD WZ10EZEX 1TB 7200 rpm + SSD 128 GB + Win 10 x64.

Оффлайн R170

  • Автор темы
  • Участник
  • *
  • Сообщений: 144
    • Просмотр профиля
Re: Segmentation fault
« Ответ #7 : 07 Февраль 2015, 22:04:11 »
Код: C
  1. mass[size++] = ob;


Этой строкой вы только пишите в память и увеличиваете size на единицу.  :)
Для простоты скажем, что mass имеет содержит адрес 0x0000. Размер object* равен 8 байт (по хорошему, конечно, 32 или 64, но так проще считать). Тогда:


size = 0:
Тогда ob запишется по адресу 0xAAAA0000 + 0x8 * 0, т.е. по 0x0000

size = 1:
Тогда ob запишется по адресу 0xAAAA0000 + 0x8 * 1, т.е. по 0x0008


size = 2:
Тогда ob запишется по адресу 0xAAAA0000 + 0x8 * 2, т.е. по 0x0010


size = 3:
Тогда ob запишется по адресу 0xAAAA0000 + 0x8 * 3, т.е. по 0x0018


size = 4:
Тогда ob запишется по адресу 0xAAAA0000 + 0x8 * 0, т.е. по 0x0020


Общая длинна - 0x28, что соответствует буферу в 40 байт.
Как тогда перевыделять память под массив?

Оффлайн Кровавый

  • Старожил
  • *
  • Сообщений: 1626
  • Логика творит чудеса!
    • Просмотр профиля
Re: Segmentation fault
« Ответ #8 : 07 Февраль 2015, 22:06:47 »
Ну вы говорите пересоздавать массив при каждом вызове addObject, что вы имеете ввиду?

Если не учитывать, что надо проверять, выделилась ли память и т.д., то как-то так.

Код: C++
  1. void addObject( object* pObj )
  2. {
  3.    // Сохраним указатель на старый массив, чтобы скопировать его в новое место
  4.    object** pOldObjectArray = mass;
  5.  
  6.    // Создадим новый массив, размер которого больше на 1
  7.    mass = new object* [ size + 1 ];
  8.  
  9.    // Скопируем весь старый массив в новый
  10.    memcpy( mass, pOldobjectArray, sizeof( object* ) * size );
  11.  
  12.    // В последний элемент нового допишем пришедший элемент
  13.    mass [ size++ ] = pObj;
  14.  
  15.    // Освободим память из-под старого массива
  16.    delete [] poldObjectArray;
  17. }
Железо: AMD FX8350 4.2Ghz + 2x4Gb Kingston HeyperX + Asus M5A97 R2.0 + HDD WD WZ10EZEX 1TB 7200 rpm + SSD 128 GB + Win 10 x64.

Оффлайн R170

  • Автор темы
  • Участник
  • *
  • Сообщений: 144
    • Просмотр профиля
Re: Segmentation fault
« Ответ #9 : 07 Февраль 2015, 22:08:46 »
Ну вы говорите пересоздавать массив при каждом вызове addObject, что вы имеете ввиду?

Если не учитывать, что надо проверять, выделилась ли память и т.д., то как-то так.

Код: C++
  1. void addObject( object* pObj )
  2. {
  3.    // Сохраним указатель на старый массив, чтобы скопировать его в новое место
  4.    object** pOldObjectArray = mass;
  5.  
  6.    // Создадим новый массив, размер которого больше на 1
  7.    mass = new object* [ size + 1 ];
  8.  
  9.    // Скопируем весь старый массив в новый
  10.    memcpy( mass, pOldobjectArray, sizeof( object* ) * size );
  11.  
  12.    // В последний элемент нового допишем пришедший элемент
  13.    mass [ size++ ] = pObj;
  14.  
  15.    // Освободим память из-под старого массива
  16.    delete [] poldObjectArray;
  17. }
Спасибо большое.
Тема закрыта

 

Страница сгенерирована за 0.114 секунд. Запросов: 24.