Ошибка при выделении памяти в Си (Access violation)

267
10 апреля 2017, 07:14

Здравствуйте, возникла проблема при выполнении программы.

    #include <conio.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <memory.h>
    struct Customer {
        char fio[20];       // ФИО покупателя
        int id;             // порядковый номер
        char address[20];   // адрес покупателя
        char delivDate[20]; // дата доставки
        struct Customer *next;  //следующий покупатель
    };
    typedef struct Customer *PCust;   // массив структур

    PCust CreateCustomer(char *NewFio, char *NewAdress, char *NewData, int id);
    PCust Find(PCust Head, char NewFio[]);
    void AddFirst(PCust * Head, PCust NewCustomer);
    void AddLast(PCust *Head, PCust NewCustomer);
    void AddAfter(PCust p, PCust NewCustomer);
    void DeleteNode(PCust *Head, PCust p);
    ...
    int main() {
        while (1)
            switch (menu()) 
            {
            case 1:newList(); break;
            case 2:readFromFile(); break;
            case 3:addCustomer(); break;
            case 4:deleteCustomer(); break;
            case 5:changeCustomerField(); break;
            case 6:searchInCustomers(); break;
            case 7:return 0;
            default:printf("Neverniy vibor\n");
            }
    }
    int menu()
    {
        int choice;
        do
        {
            //system("cls");
            printf("Menu\n");
            printf("1.New list\n");
            printf("2.Read from file\n");
            printf("3.Add customer\n");
            printf("4.Delete customer\n");
            printf("5.Change customer field\n");
            printf("6.Search in customers\n");
            printf("7.Exit\n");
            printf("Vash vibor?\n");
            scanf_s("%d", &choice);
            //system("cls");
        } while (choice>7);
        return choice;
    }
    void addCustomer(void) {
        PCust Head = NULL;
        struct Customer currentCustomer;
        printf("Vvedite FIO pokupatelya: ");
        scanf("%s", currentCustomer.fio);
        printf("Vvedite datu dostavki: ");
        scanf("%s", currentCustomer.delivDate);
        printf("Vvedite adres pokupatelya: ");
        scanf("%s", currentCustomer.address);
        printf("Vvedite nomer pokupatelya: ");
        scanf("%d", &currentCustomer.id);
        PCust customerNode = CreateCustomer(currentCustomer.fio, currentCustomer.address,
            currentCustomer.delivDate, currentCustomer.id);
        AddLast(&Head, customerNode);
        //    writeToFile(&customerNode);
    }
    void writeToFile(PCust *Head) {
    //    FILE *f;
    //    f=fopen("customers.txt", "w");
    PCust q = *Head;        // Начали с головы
    if (*Head == NULL)
        return;
    while (q->next) // Пока не дошли до конца
    {
        printf("%s\n", q->fio);
        printf("%d\n", q->id);
        printf("%s\n", q->address);
        printf("%s\n", q->delivDate);
        //        q = q->next;  // Переходим к следующему узлу
    }
    printf("Vishli");
    //    fclose(f);
}
PCust CreateCustomer(char *NewFio, char *NewAdress, char *NewData, int id){
    PCust NewCustomer = (PCust)malloc(sizeof(PCust));
    strcpy(NewCustomer->fio, NewFio);
    strcpy(NewCustomer->address, NewAdress);
    strcpy(NewCustomer->delivDate, NewData);
    NewCustomer->id = id;
    NewCustomer->next = NULL;
    return NewCustomer;
}
// Добавление нового узла
void AddFirst(PCust * Head, PCust NewCustomer){
    NewCustomer->next = *Head;
    Head = &NewCustomer;
}
// Добавление узла между элементами
void AddAfter(PCust p, PCust NewCustomer){
    NewCustomer->next = p->next;
    p->next = NewCustomer;
}
// Добавить узел в конец списка
void AddLast(PCust *Head, PCust NewCustomer){
    PCust q = *Head;
    // Если список пустой
    if (*Head == NULL)
    {
        AddFirst(Head, NewCustomer);
        return;
    }
    // Цикл прохода до последнего узла списка
    while (q->next)
        q = q->next;
    // Добавление узла после заданного узла,
    // в данном случае после q
    AddAfter(q, NewCustomer);
}

Я использую односвязный список и при добавлении клиента (функция addCustomer()), выдает ошибку:

Exception thrown at 0x77466EDD (ntdll.dll) in CourseWork_Test.exe: 0xC0000005: Access violation reading location 0x00000003.

указывая на строку

PCust NewCustomer = (PCust)malloc(sizeof(PCust));

Ошибка появляется при добавлении второго или третьего клиента.
Скриншот вывода программы:

Спасибо

Answer 1

Совершенно не понятно, чего вы пытаетесь добиться создавая списки для локального указателя Head в каждой из своих функций типа addCustomer и никак не возвращая его наружу. Как эти функции собираются общаться между собой (а по замыслу они должны общаться между собой) - не ясно.

Что касается падения, то налицо популярная ошибка

PCust NewCustomer = (PCust)malloc(sizeof(PCust));

вызванная типичными и легко узнаваемыми "манерами" низкокачественного кода. В данном случае - использование имени типа под sizeof и сокрытие указательного типа под typedef

У вас PCust - это тип-указатель. Соответственно ваш malloc(sizeof(PCust)) выделяет память под один указатель, а не под структуру struct Customer. Вам нужно sizeof(struct Customer) байтов памяти, а не sizeof(PCust).

Как минимум исправьте размер в этом malloc.

А лучше - уберите из кода нафиг тип PCust - не надо скрывать указательные типы под typedef именами (это бывает полезно, но отнюдь не в таких контекстах). Сделайте typedef на struct Customer, если вам так уж хочется более короткой записи

typedef struct Customer Customer;

И научитесь пользоваться идиомой

T *p = malloc(sizeof *p);

В вашем случае

Customer *NewCustomer = malloc(sizeof *NewCustomer);

Также отдельная белиберда написана в AddFirst. Должно быть

void AddFirst(PCust * Head, PCust NewCustomer){
    NewCustomer->next = *Head;
    *Head = NewCustomer;
    // а не `Head = &NewCustomer`
}
READ ALSO
Как узнать, нажималась ли кнопка в форме

Как узнать, нажималась ли кнопка в форме

Приветствуюподскажите, есть обычная форма подписки и есть всплывающее окно при уходе с сайта

258
Как правильно расширить класс?

Как правильно расширить класс?

Пытаюсь расширить класс Array при помощи prototype, добавив в него свой метод, но при обходе массива циклом созданный метод видится элементом массива:

236
Первые шаги в typescript

Первые шаги в typescript

В коде я часто использую функцию как объект, то есть:

226