Освобождение определенного типа данных в универсальной функции / Расположение ошибки чтения нарушения доступа - PullRequest
0 голосов
/ 01 октября 2018

Я пишу этот код для назначения, и функции должны быть общими, и пользователь должен решить, работать ли с целыми числами или строками.Очевидно, я написал конкретные функции для операций для обоих типов.Единственная проблема, остающаяся в коде, это когда я пытаюсь освободить выделенную память типа int, я получаю следующее:

Exception thrown at 0x0F24904D (ucrtbased.dll) in ConsoleApplication7.exe: 0xC0000005: Access violation reading location 0x00000006.

Я получаю это только при отладке, но компиляция без отладки просто остановится, когда я попытаюсь выполнитьи остановитесь на несколько секунд перед завершением программы.

Вот весь код:

Заголовок:

#ifndef _HEADER_H
#define _HEADER_H

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>

typedef enum { FALSE, TRUE } BOOL;

/* defining specific function names*/
typedef int(*compare_func)(void*, void*);
typedef void(*print_func)(void*);
typedef void(*free_func)(void*);

/* defining struct names and pointers*/
typedef struct set Set;
typedef struct set* PSet;
typedef struct list List;
typedef struct list* PList;


/* creating and initialzing a set*/
List* createSet(compare_func cmp_fnc, print_func prnt_fnc, free_func free_fnc);

/* finding the biggest value in the set*/
void* findMax(PList List);

/* finding the smallest value in the set*/
void* findMin(PList List);

/* finding an element in the set*/
BOOL findInSet(PList List, void* val);

/* function for finding the size of the list*/
int setSize(PList list);

/* inserting a new element.*/
BOOL addToSet(PList List, void *data);

/* deleting an element, pointered by todel*/
BOOL deleteFromSet(PList list, void *todel);

/* print the elements in the set */
void printAll(PList list);

/* deleting the entire set */
void deleteSet(PList list);

#endif

Реализация:

#include "Header.h"

struct set      // Set struct for doubly-linked list
{
    void* data;
    struct  set *next, *prev;
};

struct list      // List struct
{
    int ListSize;
    Set *head;
    Set *tail;
    compare_func compare;
    print_func print;
    free_func free;
};


List* createSet(compare_func cmp_fnc, print_func prnt_fnc, free_func free_fnc)    // Function for initializing and creating a set
{
    PList LIST;
    LIST = (PList)malloc(sizeof(List));
    if (LIST == NULL)
    {
        printf("Error! Memory allocation failed.\n");
        exit(1);
    }
    LIST->ListSize = 0;
    LIST->head = NULL;
    LIST->tail = NULL;
    LIST->compare = cmp_fnc;
    LIST->print = prnt_fnc;
    LIST->free = free_fnc;
    return LIST;
}

void* findMax(PList List)         // Function for finding the biggest value in a set
{
    if (List->head == NULL)     // If the set is empty
        return NULL;

    PSet temp;
    void* max = List->head->data;
    temp = List->head;
    while (temp)
    {
        if (List->compare(temp->data, max) == 1)      // Finding the biggest value
            max = temp->data;
        temp = temp->next;    // Moving to the next node
    }
    return max;
}


void* findMin(PList List)         // Function for finding the smallest value in a set
{
    if (List->head == NULL)        // If the set is empty
        return NULL;

    PSet temp;
    void* min = List->head->data;
    temp = List->head;
    while (temp)
    {
        if (List->compare(temp->data, min) == -1)       // Finding the smallest value
            min = temp->data;
        temp = temp->next;       // Moving to the next node
    }
    return min;
}


BOOL findInSet(PList List, void* val)        // Function for checking whether a given character is in the set
{
    if (List->head == NULL)    // If the list is empty
        return FALSE;

    PSet temp;
    temp = List->head;
    while (temp)
    {
        if (List->compare(temp->data, val) == 0)        // If the character exists
            return TRUE;
        temp = temp->next;     // Moving to the next node
    }
    return FALSE;
}


int setSize(PList list)
{
    return list->ListSize;
}


BOOL addToSet(PList List, void *data)       // Function for adding an item to the set
{
    PSet temp, CurrentNode;
    CurrentNode = List->head;
    temp = (PSet)malloc(sizeof(Set));
    if (temp == NULL)           // If the allocation failed return false
        return FALSE;

    temp->data = data;       // Filling the temp with the data
    temp->next = NULL;
    temp->prev = NULL;

    if (List->head == NULL)      // If the list is empty
    {
        List->head = temp;
        List->tail = temp;
        List->ListSize++;
        return TRUE;
    }
    else {
        while (CurrentNode)          // Loop for checking whether the inserted character exists in the list
        {
            if (List->compare(data, CurrentNode->data) == 0) return FALSE;
            CurrentNode = CurrentNode->next;
        }
        List->tail->next = temp;   // Adding the node to the list
        temp->prev = List->tail;
        List->tail = temp;     // Updating the tail
        List->ListSize++;
        return TRUE;
    }
}


BOOL deleteFromSet(PList list, void *todel)         // Function for deleteing an item from a set
{
    PSet nodeToDel;

    if (list->head == NULL)      // If the list is empty
        return FALSE;

    if (list->compare(todel, list->head->data) == 0)    // If the node to be deleted is the head
    {
        nodeToDel = list->head;
        list->head = list->head->next;
        if (list->head != NULL)
            list->head->prev = NULL;
        list->free(nodeToDel->data);
        free(nodeToDel);
        list->ListSize--;
        return TRUE;
    }
    else if (list->compare(todel, list->tail->data) == 0)         // If the node to be deleted is the tail
    {
        nodeToDel = list->tail;
        list->tail = list->tail->prev;
        list->tail->next = NULL;
        list->free(nodeToDel->data);
        free(nodeToDel);
        list->ListSize--;
        return TRUE;
    }
    else
    {
        nodeToDel = list->head;
        while (nodeToDel->next)      // Any node other than the head or the tail
        {
            if (list->compare(todel, nodeToDel->data) == 0)     // If the character exists in the list
            {
                nodeToDel->next->prev = nodeToDel->prev;
                nodeToDel->prev->next = nodeToDel->next;
                list->free(nodeToDel->data);
                free(nodeToDel);
                list->ListSize--;
                return TRUE;
            }
            nodeToDel = nodeToDel->next;       // Moving to the next node
        }
    }
    return FALSE;      // If the character wasn't found in the list return false
}


void printAll(PList list)        // Funciton for printing all items in a set
{
    PSet temp;
    if (list->head == NULL)      // If the list is empty
        printf("\nThe list is empty.");
    else
    {
        printf("\nThe list is:\n");
        temp = list->head;
        while (temp)       // While there are still nodes left
        {
            list->print(temp->data);   // Call specific function for printing
            temp = temp->next;     // Move to the next node
        }
        printf("\n");
    }
}


void deleteSet(PList list)       // Function for deleting a set
{
    PSet temp;
    if (!(list->head))   // If the list is empty
        printf("\nThe set is empty.\n");
    else
    {
        while (list->head)
        {
            temp = (list->head);
            list->head = list->head->next;   // Moving to the next node
            if (list->head != NULL)
                list->head->prev = NULL;
            list->free((temp->data));     // Call specific function for freeing memory
            free(temp);
        }
        list->ListSize = 0;
        list->head = NULL;
        list->tail = NULL;
        printf("\nThe set has been deleted.\n");
    }
}

Main:

#include "Header.h"

void prnt_string(void* str)       // specific function for printing strings
{
    printf("%s  ", (char*)str);
}

void free_string(void* str)     // specific function for freeing memory
{
    free((char*)str);
}

int cmp_str(void* s1, void* s2)     // specific function for comparing two strings
{
    if (strcmp((char*)s1, (char*)s2) == 0)
        return 0;
    else if (strcmp((char*)s1, (char*)s2) == 1)
        return 1;
    else return -1;
}


void prnt_int(void* a)     // Specific function for printing integers
{
    printf("%d  ", (int*)a);
}

void free_int(void* a)      // Specific function for freeing integers
{
    free(a);
}

int int_comp(void* a, void* b)         // Specific function for comparing integers
{
    if ((int*)a == (int*)b)
        return 0;
    else if ((int*)a > (int*)b)
        return 1;
    else return -1;
}


int main()
{
    char ch, tempstr[31], *str;
    int n, option, *num, item;
    void *temp;
    BOOL status;
    PList list;

    printf("Choose the type you want to work with:\n");
    printf("1. Integers\n");
    printf("2. Strings\n");
    printf("Enter input: ");
    scanf("%d", &n);

    switch (n)
    {
    case 1:
        list = createSet(int_comp, prnt_int, free_int);
        do
        {
            printf("\n\nChoose the desired action: ('-1' to exit)\n");
            printf("1. Create a Set\n");
            printf("2. Add To Set\n");
            printf("3. Delete From Set\n");
            printf("4. Find an Item in The Set\n");
            printf("5. Show The Size of The Set\n");
            printf("6. Find The Biggest Value In The Set\n");
            printf("7. Find The Smallest Value In The Set\n");
            printf("8. Delete The Set\n");
            printf("Enter input: ");
            scanf("%d", &option);

            switch (option)
            {
            case 1:
                list = createSet(int_comp, prnt_int, free_int);
                printf("\nThe Set Has Been Initialized.\n\n");
                break;
            case 2:
                num = (int*)malloc(sizeof(int));
                if (num == NULL)
                {
                    printf("Memory allocation failed!");
                    deleteSet(list);
                    return 1;
                }
                else
                {
                    printf("\nEnter a number: ");
                    scanf("%d", &num);
                    status = addToSet(list, num);
                    if (status == TRUE)
                    {
                        printf("Number successfully added to set.\n\n");
                        printAll(list);
                        printf("\n");
                    }
                    else
                    {
                        printf("Operation failed!\nThe number already exists in the set or memory allocation failed.\n\n");
                        deleteSet(list);
                        return 1;
                    }
                }
                break;
            case 3:
                printf("\nEnter number: ");
                scanf("%d", &item);
                status = deleteFromSet(list, item);
                if (status == TRUE)
                {
                    printf("Number successfully deleted.\n\n");
                    printAll(list);
                }
                else
                {
                    printf("Operation failed!\nThe number does not exist in the set.\n\n");
                    printAll(list);
                    printf("\n");
                }
                break;
            case 4:
                printf("\nEnter number: ");
                scanf("%d", &item);
                if (findInSet(list, item) == TRUE)
                    printf("Item exists in the set.\n\n");
                else printf("Item does not exist in the set or the set is empty.\n\n");
                break;
            case 5:
                printf("\nThe size of the set is %d.\n\n", setSize(list));
                break;
            case 6:
                temp = findMax(list);
                if (temp == NULL) printf("\nThe set is empty.\n\n");
                else printf("\nThe biggest value in the set is %d.\n\n", (int*)temp);
                break;
            case 7:
                temp = findMin(list);
                if (temp == NULL) printf("\nThe set is empty.\n\n");
                else printf("\nThe smallest value in the set is %d.\n\n", (int*)temp);
                break;
            case 8:
                deleteSet(list);
                break;
            case -1:
                printf("\nExiting Program\n\n");
                break;
            default:
                printf("\nWrong input!\n\n");
                break;
            }
        } while (option != -1);
        deleteSet(list);
        free(list);
        break;
    case 2:
        list = createSet(cmp_str, prnt_string, free_string);
        do
        {
            printf("\n\nChoose the desired action: ('-1' to exit)\n");
            printf("1. Create a Set\n");
            printf("2. Add To Set\n");
            printf("3. Delete From Set\n");
            printf("4. Find an Item in The Set\n");
            printf("5. Show The Size of The Set\n");
            printf("6. Find The Biggest Value In The Set\n");
            printf("7. Find The Smallest Value In The Set\n");
            printf("8. Delete The Set\n");
            printf("Enter input: ");
            scanf("%d", &option);

            switch (option)
            {
            case 1:
                list = createSet(cmp_str, prnt_string, free_string);
                printf("\nThe Set Has Been Initialized.\n\n");
                break;
            case 2:
                    printf("\nEnter a string(max of 30 characters):\n");
                    scanf("%s", tempstr);
                    str = (char*)malloc(strlen(tempstr) + 1 * sizeof(char));
                    if (str == NULL)
                    {
                        printf("Memory allocation failed!\n\n");
                        deleteSet(list);
                        return 1;
                    }
                    strcpy(str, tempstr);
                    status = addToSet(list, str);
                    if (status == TRUE)
                    {
                        printf("String successfully added to set.\n\n");
                        printAll(list);
                    }
                    else
                    {
                        printf("Operation failed!\nThe string already exists in the set or memory allocation failed.\n\n");
                        deleteSet(list);
                        return 1;
                    }
                break;
            case 3:
                printf("\nEnter string(max of 30 characters): ");
                scanf("%s", tempstr);
                status = deleteFromSet(list, tempstr);
                if (status == TRUE)
                {
                    printf("String successfully deleted.\n\n");
                    printAll(list);
                }
                else
                {
                    printf("Operation failed!\nThe string does not exist in the set.");
                    printAll(list);
                    printf("\n");
                }
                break;
            case 4:
                printf("\nEnter string: ");
                scanf("%s", tempstr);
                if (findInSet(list, tempstr) == TRUE)
                    printf("Item exists in the set.\n\n");
                else printf("Item does not exist in the set.\n\n");
                break;
            case 5:
                printf("\nThe size of the set is %d.\n\n", setSize(list));
                break;
            case 6:
                temp = findMax(list);
                if (temp == NULL) printf("\nThe set is empty.\n\n");
                else
                {
                    printf("\nThe biggest value in the set is ");
                    puts((char*)temp);
                    printf("\n");
                }
                break;
            case 7:
                temp = findMin(list);
                if (temp == NULL) printf("\nThe set is empty.\n\n");
                else
                {
                    printf("\nThe smallest value in the set is ");
                    puts((char*)temp);
                    printf("\n");
                }
                break;
            case 8:
                deleteSet(list);
                break;
            case -1:
                printf("\nExiting Program\n\n");
                break;
            default:
                printf("\nWrong input!\n\n");
                break;
            }
        } while (option != -1);
        deleteSet(list);
        free(list);
        break;
    default:
        printf("\nWrong input!\n\n");
        break;
    }

    getch();
    return 0;
}

Эта функция вызывает проблему:

void free_int(void* a)      // Specific function for freeing integers
{
    free(a);
}

Код отлично работает со строками, но не со значениями типа int.Если кто-то может указать на проблему, я был бы очень благодарен.Заранее спасибо.

1 Ответ

0 голосов
/ 01 октября 2018

Ваша программа может аварийно завершить работу, поскольку вы перезаписываете значение указателя:

   int* num;                        // [1]
   num = (int*)malloc(sizeof(int)); // [2] 
   scanf("%d", &num);               // [3] you are changing value of pointer !!
   // scanf ("%d", num);            // [4] USE THIS LINE
   status = addToSet(list, num);

[1] объявление указателя на int

[2] выделено памяти, на нее указывает num

[3] вы передаете указатель на указатель в качестве аргумента функции scanf, затем вы модифицируете значение указателя (вы не записываете какое-то целое число в область памяти, указанную num!).Поэтому, когда вызывается функция free, она пытается освободить неверный указатель.Это UB.

[4] scanf("%d",num); используйте эту строку, чтобы избежать проблемы с неверным значением указателя

...