передача структуры в функцию создает ошибку по умолчанию - PullRequest
0 голосов
/ 18 апреля 2011

Обе эти функции (по крайней мере в моем компиляторе) гарантированно создают ошибку сегмента, но я понятия не имею, почему.мне очень нравится их функциональность, и я видел похожие примеры, поэтому мне любопытно узнать, что здесь происходит не так или как сделать то, что, на мой взгляд, на самом деле делает, то есть передать «уровень» в какую-то функцию и затем иметь возможность манипулироватьего переменная (например, lvl.lvl_cl [x] [y] [z] = some_number), а затем передать его обратно для дальнейшего использования

любая помощь приветствуется:)

typedef struct {
    int lvl_cl[500][500][50];
    char lvl_ch[500][500][50];
} level;

level plugh(level * in_lvl){
    in_lvl->lvl_cl[444][444][44]++; //it segfaults even if this line is removed
    return * in_lvl;
}

level foo(level inlvl){
    inlvl.lvl_cl[443][443][43]++;   //it segfaults even if this line is removed
    return inlvl;
}

int main(void){
    level world;
    plugh(&world);
    foo(world);
    return 0;
    }

Ответы [ 6 ]

3 голосов
/ 18 апреля 2011

Переполнение стека?

Серьезно, вы когда-нибудь задумывались, насколько велика ваша структура? Если вы сохраните его в стеке, он переполнится ...

Попробуйте sizeof(level), было бы интересно увидеть фактический размер.

РЕДАКТИРОВАТЬ: Если вам нужно что-то такое большое, вы действительно должны подумать, где и как вы храните это. Если вы передадите его функции, вы создадите копию структуры и поместите ее в стек. Если вы вернете структуру, вам, скорее всего, понадобится еще одна копия стека.

Вам действительно нужно передать и вернуть структуру? Если нет, вы можете поместить его в обычную статическую память (обычную глобальную переменную ) или выделить ее в кучу. В любом случае, если вы передадите указатель на него, он будет использовать только часть полной структуры.

2 голосов
/ 18 апреля 2011

Прежде всего, это много памяти:

500x500x50x1 (потому что 1 байт в символе) + 500x500x50x4 (потому что 4 байта в int) = 59.605 МБ памяти.

Вы храните все это в стеке, а не используете указатели и размещаете их в куче, что должно вызвать переполнение стека.

Кроме того, в ваших функциях plugh и foo вы возвращаете совершенно новую структуру. Зачем проходить по указателю, модифицировать объект, а затем возвращать копию? Каждый раз, когда вы вызываете эти функции, вы выделяете еще 59.605 МБ памяти, потому что вы возвращаете копию. Однако, поскольку вы не используете копию, компилятор, вероятно, оптимизирует и удаляет эту дорогостоящую копию.

1 голос
/ 19 апреля 2011

Это segfaults

0x8048471 <main>:       lea    0x4(%esp),%ecx
0x8048475 <main+4>:     and    $0xfffffff0,%esp
0x8048478 <main+7>:     pushl  -0x4(%ecx)
0x804847b <main+10>:    push   %ebp
0x804847c <main+11>:    mov    %esp,%ebp
0x804847e <main+13>:    push   %esi
0x804847f <main+14>:    push   %ebx
0x8048480 <main+15>:    push   %ecx
0x8048481 <main+16>:    sub    $0xb2d060c,%esp
0x8048487 <main+22>:    lea    -0x7735958(%ebp),%eax
0x804848d <main+28>:    lea    -0x3b9acb8(%ebp),%edx
0x8048493 <main+34>:    mov    %edx,0x4(%esp)      <<---- segfaults here
0x8048497 <main+38>:    mov    %eax,(%esp)
0x804849a <main+41>:    call   0x80483f4 <plugh>

Ошибка возникает при адресации нового указателя стека после выделения кадра стека 62 500 000 байт (32 бита int).

Большие структуры всегда должны бытьпередано по ссылке.Особенно учитывая логику foo().

1 голос
/ 18 апреля 2011

Проблема в том, что вы кладете в стек около 100 МБ, а ваш стек не такой большой.

Вам нужно начать использовать указатели на эту level структуру и выделение кучи, а не пытаться скопировать ее в стек!

0 голосов
/ 19 апреля 2011

Вы пробовали функцию, которая просто передает ссылку на вашу структуру и ничего не возвращает? Что-то вроде строк void foo (level * var) {// ваш код, который изменяет var} И в основном вы просто называете foo (& myVar).

Передача такой огромной структуры в качестве параметра функции или возвращение ее в качестве возвращаемого значения может создать вам некоторые проблемы. Также, если вам действительно нужно получить возвращаемое значение, попробуйте также вернуть ссылку на вашу структуру. например level * foo (level * in) {// ваш код здесь}.

И в основном вы просто разыменовываете результат функции, такой как level myLvl = * (foo (& myOtherLvl)). Таким образом, все, что вы передаете в своей функции - это ссылки на ваши структуры, ведь в основном это целые числа. Надеюсь, это поможет

0 голосов
/ 19 апреля 2011

Каждый раз, когда вы вызываете функцию foo, она копирует всю структуру world, и она довольно большая.Попробуйте передать указатель:

void foo(level *inlvl){
    inlvl->lvl_cl[443][443][43]++;
}
...