WedX - журнал о программировании и компьютерных науках

Ошибка сегментации при попытке memset() указателя структуры на 0

Я просто хочу установить 0 для указателя на такую ​​структуру:

#include <stdio.h>
#include <string.h>
struct apple
{
     int f;
     int d;
     size_t tree;
};
struct apple *app;
int main(void)
{
 memset(&app,0,sizeof(app));
 app->tree = 1;
 app->d = 4;
 app->f = 2;
 printf("%d %d %lu\n",app->d, app->f, app->tree);
}

Он отлично компилируется с gcc -o foo foo.c, но когда я запускаю, я получаю ошибку Segmentaion. я пробовал memset(app, 0 , sizeof(app));, но он жалуется, я пробовал memset(*app, 0,sizeof(app)); тоже жалуется. Этот компилируется нормально, но я все еще получаю ошибку segmemset((void *) &app, 0, sizeof(app));

Что я должен сделать, чтобы установить этот указатель на структуру 0? Если у меня есть простая структура, подобная этой: struct apple app;(без указателя), она должна выглядеть как memset(&app, 0, sizeof(app));

Поскольку это указатель, а memset имеет первый параметр a void* , почему не работает передача простой переменной без "&"?


Ответы:


1

Этот:

memset(&app,0,sizeof(app));

Заменяет app (указатель) нулями. Мы плохо начали.

Затем мы пытаемся сослаться на app (теперь это NULL):

app->tree = 1;

И все стало еще хуже.

Вы хотите выделить что-то, на что app будет указывать:

app = malloc(sizeof(struct apple));
memset(app, 0, sizeof(struct apple));

or

app = calloc(1, sizeof(struct apple));   // calloc zeroes things out for you
10.09.2015
  • Хорошо, я пробовал с malloc и с memset(app, 0 , sizeof(*app));, и это работает как шарм, но без malloc это не работает. Почему? Также, пожалуйста, объясните мне, почему я должен использовать sizeof(*app); вместо sizeof(app)? 11.09.2015
  • без malloc это не работает, потому что использование неинициализированного указателя - опасная, непредсказуемая, плохая идея. sizeof(app) будет просто размером самого указателя. Это может быть больше или меньше размера файла struct. Либо вы перезапишете память, которой не владеете (больше), либо не заполните всю структуру (меньше). 11.09.2015
  • @Paul Roub: часть памяти после него не перезаписывается нулями, потому что размер memset равен sizeof(app) (указатель), а не sizeof(*app) (структура). Таким образом, memset фактически эквивалентен: app = NULL; (во всех реальных системах, где указатель всех нулевых байтов совпадает с NULL). Очевидно неправильно, но это не превышение; память до и после остается неизменной, только NULL разыменование делает плохие вещи. 11.09.2015
  • @ShadowRanger Ага. Исправлено. Спасибо. 11.09.2015
  • Еще одно исправление: malloc и calloc должны использовать sizeof(*app) для размера выделения, иначе он выделяет достаточно только для указателя, а не для структуры. Когда он работает без этого, это совпадение выделения malloc/calloc с большей шириной, чем запрошено (это может сработать или повредить вашу кучу, повеселитесь, угадав, что именно). :-) 11.09.2015
  • Теперь после модификации это работает, но у меня есть еще один быстрый вопрос. Странно, что когда я пытаюсь в своем терминале valgrind ./foo, он говорит: heap usage: 1 allocs, 1 frees, 16 bytes allocated почему 16 ? я думаю, что размер моей структуры равен 8, потому что sizeof (size_t) = 8 байт. 11.09.2015
  • Это между вами и вашим компилятором; или, по крайней мере, это отдельный вопрос. 11.09.2015
  • Возможно, следует отметить, что memset() в этом примере является избыточным — указатель уже инициализирован 0, поскольку он размещен статически. 11.09.2015
  • @Hoenir: процедуры выделения памяти обычно округляют выделения до размера блока, с которым они работают. 11.09.2015

  • 2

    Вы передаете &app в качестве параметра memset здесь:

    memset(&app,0,sizeof(app));
    

    Это означает, что вы устанавливаете значение этого указателя на 0. Затем вы переходите к разыменовыванию.

    app->tree = 1;
    

    Крайне маловероятно, что адрес 0 указывает на место, куда вы можете писать (фактически возможно, но не дано, что этот адрес представляет нулевой указатель). Этого достаточно, чтобы вызвать нарушение сегментации.

    Вам нужно решить, что вы имеете в виду под «установить 0 в указатель на структуру». Если вы хотите, чтобы содержимое указателя было равно нулю, вы можете использовать memset таким образом, после, чтобы оно указывало на некоторую выделенную память:

    app = malloc(sizeof(*app));  // allocate space for an apple object
    memset(app, 0, sizeof(*app)); // app, not &app!!!
    

    Обратите внимание, что вы можете выделить и обнулить выделенную память, используя calloc< /а>.

    app = calloc(1, sizeof(*app));
    

    Если вы действительно хотите установить значение указателя равным 0, то, возможно, вы имеете в виду установку нулевого указателя, которого вы можете добиться следующим образом:

    app = NULL;
    

    Но теперь вы не можете отменить ссылку на указатель.

    10.09.2015
  • Обратите внимание, что даже при правильном распределении вещей вызов memset(&app, ...) не делает того, что намеревается сделать OP. 11.09.2015
  • Новые материалы

    Объяснение документов 02: BERT
    BERT представил двухступенчатую структуру обучения: предварительное обучение и тонкая настройка. Во время предварительного обучения модель обучается на неразмеченных данных с помощью..

    Как проанализировать работу вашего классификатора?
    Не всегда просто знать, какие показатели использовать С развитием глубокого обучения все больше и больше людей учатся обучать свой первый классификатор. Но как только вы закончите..

    Работа с цепями Маркова, часть 4 (Машинное обучение)
    Нелинейные цепи Маркова с агрегатором и их приложения (arXiv) Автор : Бар Лайт Аннотация: Изучаются свойства подкласса случайных процессов, называемых дискретными нелинейными цепями Маркова..

    Crazy Laravel Livewire упростил мне создание электронной коммерции (панель администратора и API) [Часть 3]
    Как вы сегодня, ребята? В этой части мы создадим CRUD для данных о продукте. Думаю, в этой части я не буду слишком много делиться теорией, но чаще буду делиться своим кодом. Потому что..

    Использование машинного обучения и Python для классификации 1000 сезонов новичков MLB Hitter
    Чему может научиться машина, глядя на сезоны новичков 1000 игроков MLB? Это то, что исследует это приложение. В этом процессе мы будем использовать неконтролируемое обучение, чтобы..

    Учебные заметки: создание моего первого пакета Node.js
    Это мои обучающие заметки, когда я научился создавать свой самый первый пакет Node.js, распространяемый через npm. Оглавление Глоссарий I. Новый пакет 1.1 советы по инициализации..

    Забудьте о Matplotlib: улучшите визуализацию данных с помощью умопомрачительных функций Seaborn!
    Примечание. Эта запись в блоге предполагает базовое знакомство с Python и концепциями анализа данных. Привет, энтузиасты данных! Добро пожаловать в мой блог, где я расскажу о невероятных..


    Для любых предложений по сайту: [email protected]