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


Хотите сделать посильный вклад в развитие Ubuntu и русскоязычного сообщества?
Помогите нам с документацией!

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

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

Оффлайн R170

  • Автор темы
  • Участник
  • *
  • Сообщений: 144
    • Просмотр профиля
Segmentation fault
« : 07 Февраля 2015, 19:28:52 »
Попробуйте запустить.Все же вроде правильно.
Код: (C++) [Выделить]
#include <iostream>
using namespace std;

class object{
void (*f)(object*);
public:
void setFunc(void (*func)(object*)){
f = func;
}
void callFunc(){
f(this);
}
};

class Objects{
object **mass;
int size;
public:
Objects(){
size = 0;
mass = new object*[size];
}
void addObject(object *ob){
mass[size++] = ob;
}
void callFuncs(){
for(int c=0;c<size;c++){
mass[c]->callFunc();
}
}
};

void out(object *o){
cout<<o<<endl;
}

int main(){
Objects Main;
object *n;
for(int c=0;c<5;c++){
n = new object;
n->setFunc(out);
Main.addObject(n);
}
Main.callFuncs();
return 0;
}
Спасибо

Оффлайн 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++ съел и даже не поругался. Тем не менее, память вы порите.  :)

Тут вы создали массив указателей нулевого размера:
Код: (cpp) [Выделить]
Objects()
{
size = 0;
mass = new object*[size];
}



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


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

Пользователь решил продолжить мысль 07 Февраля 2015, 21:44:54:
Массив mass динамически вроде. Он должен сам расширяться.
Вот здесь
Код: (C++) [Выделить]
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++) [Выделить]
mass[size++] = ob;
Пользователь решил продолжить мысль 07 Февраля 2015, 21:53:50:
VC++ съел и даже не поругался. Тем не менее, память вы порите.  :)

Тут вы создали массив указателей нулевого размера:
Код: (cpp) [Выделить]
Objects()
{
size = 0;
mass = new object*[size];
}

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

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

  • Старожил
  • *
  • Сообщений: 1626
  • Логика творит чудеса!
    • Просмотр профиля
Re: Segmentation fault
« Ответ #6 : 07 Февраля 2015, 21:57:57 »
Код: (C++) [Выделить]
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++) [Выделить]
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, что вы имеете ввиду?

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

Код: (cpp) [Выделить]
void addObject( object* pObj )
{
   // Сохраним указатель на старый массив, чтобы скопировать его в новое место
   object** pOldObjectArray = mass;

   // Создадим новый массив, размер которого больше на 1
   mass = new object* [ size + 1 ];

   // Скопируем весь старый массив в новый
   memcpy( mass, pOldobjectArray, sizeof( object* ) * size );

   // В последний элемент нового допишем пришедший элемент
   mass [ size++ ] = pObj;

   // Освободим память из-под старого массива
   delete [] poldObjectArray;
}
Железо: 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, что вы имеете ввиду?

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

Код: (cpp) [Выделить]
void addObject( object* pObj )
{
   // Сохраним указатель на старый массив, чтобы скопировать его в новое место
   object** pOldObjectArray = mass;

   // Создадим новый массив, размер которого больше на 1
   mass = new object* [ size + 1 ];

   // Скопируем весь старый массив в новый
   memcpy( mass, pOldobjectArray, sizeof( object* ) * size );

   // В последний элемент нового допишем пришедший элемент
   mass [ size++ ] = pObj;

   // Освободим память из-под старого массива
   delete [] poldObjectArray;
}
Спасибо большое.
Тема закрыта

 

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