Wywołanie malloc() zatrzymuje program

0

Panowie, potrzebuję znowu pomocy. Otóż modyfikuję sobie programik bo chcę uzyskać implementację tablicy z tzw. haszowaniem i funkcją haszującą z wykorzystaniem dynamicznie tworzonych list. Na instrukcji malloc() program zatrzymuje swoje działanie, czy ktoś może mi powiedzieć dlaczego tak się dzieje (a dzieje się to wówczas gdy wciskam "1" czyli insertujemy nowy element i wpisuję np. 15464 a potem 23).
Przedstawiam kod:

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

/* Node for storing an item in a Linked List */
struct node
{
    int key;
    int value;
    struct node *next;
};

/* For storing a Linked List at each index of Hash Table  */
struct arrayitem
{
    struct node *head;
    /* head pointing the first element of Linked List at an index of Hash Table */

    struct node *tail;
    /* tail pointing the last element of Linked List at an index of Hash Table */
};

struct arrayitem *array;

int size = 0;         /* Determines the no. of elements present in Hash Table */
int max = 10;	      /* Determines the maximum capacity of Hash Table array */


struct node* get_element(struct node *list, int find_index);
void remove_element(int key);
void rehash();
void init_array();
int find(struct node *list, int key);


/* This function creates an index corresponding to the every given key */
int hashcode(int key)
{
    return (key % max);
}

void insert(int key, int value)
{
    float n = 0.0;
    /* n => Load Factor, keeps check on whether rehashing is required or not */

    int index = hashcode(key);

    /* Extracting Linked List at a given index */
    struct node *list = (struct node*) array[index].head;

    printf("Test");

    /* Creating an item to insert in the Hash Table */
    struct node *item = (struct node*) malloc(sizeof(struct node));

    printf("Test2");

    item->key = key;
    item->value = value;
    item->next = NULL;

    if (list == NULL)
    {
        /* Absence of Linked List at a given Index of Hash Table */
        printf("Inserting %d(key) and %d(value) \n", key, value);
        array[index].head = item;
        array[index].tail = item;
        size++;
    }
    else
    {
        /* A Linked List is present at given index of Hash Table */
        int find_index = find(list, key);

        if (find_index == -1)
        {
            /* Key not found in existing linked list , Adding the key at the end of the linked list	*/
            array[index].tail->next = item;
            array[index].tail = item;
            size++;
        }
        else
        {
            /* Key already present in linked list , Updating the value of already existing key */
            struct node *element = get_element(list, find_index);
            element->value = value;
        }
    }

    //Calculating Load factor
    n = (1.0 * size) / max;
    if (n >= 0.75)
    {
        //rehashing
        printf("going to rehash\n");
        rehash();
    }
}

void rehash()
{
    struct arrayitem *temp = array;
    /* temp pointing to the current Hash Table array */

    int i = 0, n = max;
    size = 0;
    max = 2 * max;

    /* array variable is assigned with newly created Hash Table with double of previous array size */
    array = (struct arrayitem*) malloc(max * sizeof(struct node));
    init_array();

    for (i = 0; i < n; i++)
    {
        /* Extracting the Linked List at position i of Hash Table array */
        struct node* list = (struct node*) temp[i].head;
        if (list == NULL)
        {
            /* if there is no Linked List, then continue */
            continue;
        }
        else
        {
            /* Presence of Linked List at i Keep moving and accessing the Linked List item until the end.
             *Get one key and value at a time and add it to new Hash Table array. */
            while (list != NULL)
            {
                insert(list->key, list->value);
                list = list->next;
            }
        }
    }
    temp = NULL;
}

/* This function finds the given key in the Linked List Returns it's index , Returns -1 in case key is not present */
int find(struct node *list, int key)
{
    int retval = 0;
    struct node *temp = list;
    while (temp != NULL)
    {
        if (temp->key == key)
        {
            return retval;
        }
        temp = temp->next;
        retval++;
    }
    return -1;
}

/* Returns the node (Linked List item) located at given find_index  */
struct node* get_element(struct node *list, int find_index)
{
    int i = 0;
    struct node *temp = list;
    while (i != find_index)
    {
        temp = temp->next;
        i++;
    }
    return temp;
}

/* To remove an element from Hash Table */
void remove_element(int key)
{
    int index = hashcode(key);
    struct node *list = (struct node*) array[index].head;

    if (list == NULL)
    {
        printf("This key does not exists\n");
    }
    else
    {
        int find_index = find(list, key);
        if (find_index == -1)
        {
            printf("This key does not exists\n");
        }
        else
        {
            struct node *temp = list;
            if (temp->key == key)
            {
                array[index].head = temp->next;
                printf("This key has been removed\n");
                return;
            }

            while (temp->next->key != key)
            {
                temp = temp->next;
            }

            if (array[index].tail == temp->next)
            {
                temp->next = NULL;
                array[index].tail = temp;
            }
            else
            {
                temp->next = temp->next->next;
            }

            printf("This key has been removed\n");
        }
    }
}

/* To display the contents of Hash Table */
void display()
{
    int i = 0;
    for (i = 0; i < max; i++)
    {
        struct node *temp = array[i].head;
        if (temp == NULL)
        {
            printf("array[%d] has no elements\n", i);
        }
        else
        {
            printf("array[%d] has elements-: ", i);
            while (temp != NULL)
            {
                printf("key= %d  value= %d\t", temp->key, temp->value);
                temp = temp->next;
            }
            printf("\n");
        }
    }
}

/* For initializing the Hash Table */
void init_array()
{
    int i = 0;
    for (i = 0; i < max; i++)
    {
        array[i].head = NULL;
        array[i].tail = NULL;
    }
}

/* Returns size of Hash Table */
int size_of_array()
{
    return size;
}

int main()
{
    int choice, key, value, n, c;
    system("cls");

    array = (struct arrayitem*) malloc(max * sizeof(struct arrayitem*));
    printf("xz\n");
    init_array();
    printf("xyz");
    do {

        printf("Implementation of Hash Table in C chaining with Singly Linked List \n\n");
        printf("MENU-: \n1.Inserting item in the Hash Table"
                              "\n2.Removing item from the Hash Table"
                              "\n3.Check the size of Hash Table"
                              "\n4.To display a Hash Table"
               "\n\n Please enter your choice -: ");

        scanf("%d", &choice);

        switch(choice)
        {
            case 1:
              printf("Inserting element in Hash Table\n");
              printf("Enter key and value-:\t");
              scanf("%d", &key);
              scanf("%d", &value);
              insert(key, value);
              break;

            case 2:
              printf("Deleting in Hash Table \nEnter the key to delete-:");
              scanf("%d", &key);
              remove_element(key);
              break;

            case 3:
              n = size_of_array();
              printf("Size of Hash Table is-:%d\n", n);
              break;

            case 4:
              display();
              break;

            default:
              printf("Wrong Input\n");
              break;
        }

        printf("\nDo you want to continue-:(press 1 for yes)\t");
        scanf("%d", &c);
    }
    while(c == 1);

    getch();
    return 0;
}

Wyświetla się "Test", ale już nie "Test2".
Proszę również zignorować to że nie ma zwalniania pamięci w programie, to tylko test, docelowo będzie oczywiście, nie chciało mi się tego wstawiać na razie.
Może ktoś to przetestować na swoim kompie wpisując te dane i sprawdzając czy "test2" się pojawi czy nie...?

5
xz
=================================================================
==296357==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x607000000070 at pc 0x000000402290 bp 0x7ffc92efe7e0 sp 0x7ffc92efe7d8
WRITE of size 8 at 0x607000000070 thread T0
    #0 0x40228f in init_array() /tmp/xd.cc:243
    #1 0x402446 in main /tmp/xd.cc:260
    #2 0x7f556f04a50f in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
    #3 0x7f556f04a5c8 in __libc_start_main_impl ../csu/libc-start.c:381
    #4 0x400bf4 in _start (/tmp/a.out+0x400bf4)

0x607000000070 is located 0 bytes to the right of 80-byte region [0x607000000020,0x607000000070)
allocated by thread T0 here:
    #0 0x7f556feba6af in __interceptor_malloc (/lib64/libasan.so.8+0xba6af)
    #1 0x402430 in main /tmp/xd.cc:258
    #2 0x7f556f04a50f in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58

SUMMARY: AddressSanitizer: heap-buffer-overflow /tmp/xd.cc:243 in init_array()
Shadow bytes around the buggy address:
  0x0c0e7fff7fb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c0e7fff7fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c0e7fff7fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c0e7fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c0e7fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c0e7fff8000: fa fa fa fa 00 00 00 00 00 00 00 00 00 00[fa]fa
  0x0c0e7fff8010: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c0e7fff8020: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c0e7fff8030: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c0e7fff8040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c0e7fff8050: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==296357==ABORTING

napraw to

0

W jaki sposób? Czy ktoś może mi powiedzieć w jaki sposób to naprawić? Zauważyłem dodatkowo że po usunięciu dwóch linii kodu, ale tylko printf z początku:

    printf("xz\n");

    printf("xyz");

to w ogóle przestało mi w ogóle wyświeltać informację z opisem, a więc wnioskuję (być może błędnie) że po usunięciu tych dwóch linii kodu z tylko i wyłącznie rozkazami printf, nie działa początkowy malloc. A zatem pytanie brzmi: jaki związek ma printf z mallociem bo ja go w ogóle nie widzę i kompletnie nie rozumiem z czego wynika i jak naprawić ten problem z przepełnieniem sterty.
Potrzebuję pomocy fachowca.

Tak więc teraz mam taki kod i już nie wyświetla się nic i program po odpaleniu się kończy niezwłocznie nic nie wypisując nawet:

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

    /* Node for storing an item in a Linked List */
    struct node
    {
    	int key;
    	int value;
    	struct node *next;
    };

    /* For storing a Linked List at each index of Hash Table  */
    struct arrayitem
    {
    	struct node *head;
    	/* head pointing the first element of Linked List at an index of Hash Table */

    	struct node *tail;
    	/* tail pointing the last element of Linked List at an index of Hash Table */
    };

    struct arrayitem *array;

    int size = 0;         /* Determines the no. of elements present in Hash Table */
    int max = 10;	      /* Determines the maximum capacity of Hash Table array */


    struct node* get_element(struct node *list, int find_index);
    void remove_element(int key);
    void rehash();
    void init_array();
    int find(struct node *list, int key);


    /* This function creates an index corresponding to the every given key */
    int hashcode(int key)
    {
    	return (key % max);
    }

    void insert(int key, int value)
    {
      	float n = 0.0;
      	/* n => Load Factor, keeps check on whether rehashing is required or not */

    	int index = hashcode(key);

    	/* Extracting Linked List at a given index */
    	struct node *list = (struct node*) array[index].head;

    	printf("Test");

    	/* Creating an item to insert in the Hash Table */
    	struct node *item = (struct node*) malloc(sizeof(struct node));

    	printf("Test2");

    	item->key = key;
    	item->value = value;
    	item->next = NULL;

    	if (list == NULL)
        {
    		/* Absence of Linked List at a given Index of Hash Table */
    		printf("Inserting %d(key) and %d(value) \n", key, value);
    		array[index].head = item;
    		array[index].tail = item;
    		size++;
    	}
        else
        {
        	/* A Linked List is present at given index of Hash Table */
    		int find_index = find(list, key);

    		if (find_index == -1)
    		{
    			/* Key not found in existing linked list , Adding the key at the end of the linked list	*/
    			array[index].tail->next = item;
    			array[index].tail = item;
    			size++;
    		}
    		else
            {
    			/* Key already present in linked list , Updating the value of already existing key */
    			struct node *element = get_element(list, find_index);
    			element->value = value;
            }
    	}

    	//Calculating Load factor
    	n = (1.0 * size) / max;
    	if (n >= 0.75)
        {
    		//rehashing
    		printf("going to rehash\n");
    		rehash();
    	}
    }

    void rehash()
    {
    	struct arrayitem *temp = array;
    	/* temp pointing to the current Hash Table array */

    	int i = 0, n = max;
    	size = 0;
    	max = 2 * max;

    	/* array variable is assigned with newly created Hash Table with double of previous array size */
    	array = (struct arrayitem*) malloc(max * sizeof(struct node));
    	init_array();

    	for (i = 0; i < n; i++)
        {
    		/* Extracting the Linked List at position i of Hash Table array */
     		struct node* list = (struct node*) temp[i].head;
    		if (list == NULL)
    		{
    			/* if there is no Linked List, then continue */
    			continue;
    		}
    		else
    		{
    			/* Presence of Linked List at i Keep moving and accessing the Linked List item until the end.
    			 *Get one key and value at a time and add it to new Hash Table array. */
    			while (list != NULL)
    			{
    				insert(list->key, list->value);
    				list = list->next;
    			}
    		}
    	}
    	temp = NULL;
    }

    /* This function finds the given key in the Linked List Returns it's index , Returns -1 in case key is not present */
    int find(struct node *list, int key)
    {
    	int retval = 0;
    	struct node *temp = list;
    	while (temp != NULL)
    	{
    		if (temp->key == key)
    		{
    			return retval;
    		}
      		temp = temp->next;
    		retval++;
    	}
    	return -1;
    }

    /* Returns the node (Linked List item) located at given find_index  */
    struct node* get_element(struct node *list, int find_index)
    {
    	int i = 0;
    	struct node *temp = list;
    	while (i != find_index)
    	{
    		temp = temp->next;
    		i++;
    	}
    	return temp;
    }

    /* To remove an element from Hash Table */
    void remove_element(int key)
    {
    	int index = hashcode(key);
    	struct node *list = (struct node*) array[index].head;

    	if (list == NULL)
    	{
    		printf("This key does not exists\n");
    	}
    	else
    	{
    		int find_index = find(list, key);
    		if (find_index == -1)
    		{
    			printf("This key does not exists\n");
    		}
    		else
    		{
     			struct node *temp = list;
    			if (temp->key == key)
    			{
      				array[index].head = temp->next;
    				printf("This key has been removed\n");
    				return;
    			}

    			while (temp->next->key != key)
    			{
     				temp = temp->next;
    			}

      			if (array[index].tail == temp->next)
      			{
    				temp->next = NULL;
    				array[index].tail = temp;
    			}
      			else
      			{
    				temp->next = temp->next->next;
    			}

    			printf("This key has been removed\n");
    		}
    	}
    }

    /* To display the contents of Hash Table */
    void display()
    {
    	int i = 0;
    	for (i = 0; i < max; i++)
    	{
    		struct node *temp = array[i].head;
    		if (temp == NULL)
    		{
    			printf("array[%d] has no elements\n", i);
    		}
    		else
    		{
    			printf("array[%d] has elements-: ", i);
    			while (temp != NULL)
    			{
    				printf("key= %d  value= %d\t", temp->key, temp->value);
    				temp = temp->next;
    			}
    			printf("\n");
    		}
    	}
    }

    /* For initializing the Hash Table */
    void init_array()
    {
    	int i = 0;
    	for (i = 0; i < max; i++)
    	{
    		array[i].head = NULL;
    		array[i].tail = NULL;
    	}
    }

    /* Returns size of Hash Table */
    int size_of_array()
    {
    	return size;
    }

    int main()
    {
    	int choice, key, value, n, c;
    	system("cls");

    	array = (struct arrayitem*) malloc(max * sizeof(struct arrayitem*));
    	init_array();
    	do {

    		printf("Implementation of Hash Table in C chaining with Singly Linked List \n\n");
    		printf("MENU-: \n1.Inserting item in the Hash Table"
                                  "\n2.Removing item from the Hash Table"
                                  "\n3.Check the size of Hash Table"
                                  "\n4.To display a Hash Table"
    		       "\n\n Please enter your choice -: ");

     		scanf("%d", &choice);

     		switch(choice)
     		{
     			case 1:
    		      printf("Inserting element in Hash Table\n");
    		      printf("Enter key and value-:\t");
    		      scanf("%d", &key);
    		      scanf("%d", &value);
    		      insert(key, value);
    		      break;

     			case 2:
     			  printf("Deleting in Hash Table \nEnter the key to delete-:");
    		      scanf("%d", &key);
    		      remove_element(key);
    		      break;

     			case 3:
    		      n = size_of_array();
    		      printf("Size of Hash Table is-:%d\n", n);
    		      break;

     			case 4:
    		      display();
    		      break;

     			default:
    		      printf("Wrong Input\n");
    		      break;
    		}

    		printf("\nDo you want to continue-:(press 1 for yes)\t");
    		scanf("%d", &c);
    	}
    	while(c == 1);

    	getch();
    	return 0;
    }

2

Masz strasznie przekombinowane funkcje.
Ponad 10 wierszy - trzeba dzielić - pamiętaj, dziel i rządź!
Używaj wyjątków (assert) zamiast ifologii połączonej ze smarowaniem po konsoli.
To samo da się zapisać co najmniej 5 razy krócej, przy czym odzyskując kontrole nad kodem.
Teraz to on cię kontroluje.

0

Niestety ale muszę przyznać się że nie potrafię jeszcze tego zrobić. Przeczytałem tylko to: https://pl.wikibooks.org/wiki/C/assert
Niestety nie rozumiem jak miałbym wyłapać "wyjątek" związany z mallociem w kodzie używając takiego asserta.

0

Po pierwsze, podziel program na logiczne części. Przy każdej dawaj printf() i niech wypisuje co się dzieje. I sprawdzaj kolejno czy wszystko jest w porządku. Krok po kroku. Od deklaracji zmiennych, przez przypisywanie im wartości, przez alokowanie pamięci, przez ustawianie wskaźników po czyszczenie pamięci. I przyzwyczajaj się do takiego pisania dokąd się nie nauczysz/nie nabierzesz doświadczenia w praktyce gdzie w 90% przypadków będzie to już dla Ciebie zbędne.

Mam pytanie, po co Ci funkcja "size_of_array()"? W programowaniu obiektowym to by miało sens, bo zabezpieczenia mogłyby krzyczeć ale tutaj? (chyba, że zamierzasz ją dopiero tworzyć).

1

Wrócmy jeszcze raz do tego:

==296357==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x607000000070 at pc 0x000000402290 bp 0x7ffc92efe7e0 sp 0x7ffc92efe7d8
WRITE of size 8 at 0x607000000070 thread T0
    #0 0x40228f in init_array() /tmp/xd.cc:243
    #1 0x402446 in main /tmp/xd.cc:260
    #2 0x7f556f04a50f in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
    #3 0x7f556f04a5c8 in __libc_start_main_impl ../csu/libc-start.c:381
    #4 0x400bf4 in _start (/tmp/a.out+0x400bf4)

0x607000000070 is located 0 bytes to the right of 80-byte region [0x607000000020,0x607000000070)
allocated by thread T0 here:
    #0 0x7f556feba6af in __interceptor_malloc (/lib64/libasan.so.8+0xba6af)
    #1 0x402430 in main /tmp/xd.cc:258
    #2 0x7f556f04a50f in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58

tutaj komunikat mówi, że zapisujesz coś za tablicą (0 bajtów na prawo od regionu 80-batjowego). Zastanów się, czemu w init_array byś miał zapisywać coś na bajcie 80 (80==80+0).

Nie rozumiem wniosków na temat usuwania printfów. Wyjaśnisz? Poza tym, z pewnością masz świadomość, że printf wcale nie gwarantuje, że dane które wypisujesz znajdą się natychmiastowo na konsoli? One mogą być buforowane - to znaczy, że dopóki danych jest dostatecznie mało, może się zdarzyć tak, że się będą agregować w tablicy, i dopiero jak się zbiorą, zostaną wszystkie naraz wypisane. Chociaż tutaj akurat pewnie tak się nie dzieje.

1

Wiecie co, dziękuję wszystkim za chęć pomocy. Poradzę sobie z tym sam, bo dopiero teraz widzę że printf nie mają tutaj nic do rzeczy.
Kwestia czasu.
Pozdrawiam.

0

Dobra Panowie. Problem zidentyfikowany, o jedną gwiazdkę za dużo było. Teraz powinno być ok:

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

/* Node for storing an item in a Linked List */
struct node
{
	int key;
	int value;
	struct node *next;
};

/* For storing a Linked List at each index of Hash Table  */
struct arrayitem
{
	struct node *head;
	/* head pointing the first element of Linked List at an index of Hash Table */

	struct node *tail;
	/* tail pointing the last element of Linked List at an index of Hash Table */
};

struct arrayitem *array;

int size = 0;         /* Determines the no. of elements present in Hash Table */
int max = 10;	      /* Determines the maximum capacity of Hash Table array */

struct node* get_element(struct node *list, int find_index);
void remove_element(int key);
void rehash();
void init_array();
int find(struct node *list, int key);


/* This function creates an index corresponding to the every given key */
int hashcode(int key)
{
	return (key % max);
}

void insert(int key, int value)
{
	float n = 0.0;
	/* n => Load Factor, keeps check on whether rehashing is required or not */

	int index = hashcode(key);

	/* Extracting Linked List at a given index */
	struct node *list = (struct node*) array[index].head;

	/* Creating an item to insert in the Hash Table */
	struct node *item = (struct node*) malloc(sizeof(struct node));

	item->key = key;
	item->value = value;
	item->next = NULL;

	if (list == NULL)
	{
		/* Absence of Linked List at a given Index of Hash Table */
		printf("Inserting %d(key) and %d(value) \n", key, value);
		array[index].head = item;
		array[index].tail = item;
		size++;
	}
	else
	{
		/* A Linked List is present at given index of Hash Table */
		int find_index = find(list, key);

		if (find_index == -1)
		{
			/* Key not found in existing linked list , Adding the key at the end of the linked list	*/
			array[index].tail->next = item;
			array[index].tail = item;
			size++;
		}
		else
		{
			/* Key already present in linked list , Updating the value of already existing key */
			struct node *element = get_element(list, find_index);
			element->value = value;
		}
	}

	//Calculating Load factor
	n = (1.0 * size) / max;
	if (n >= 0.75)
	{
		//rehashing
		printf("going to rehash\n");
		rehash();
	}
}

void rehash()
{
	struct arrayitem *temp = array;
	/* temp pointing to the current Hash Table array */

	int i = 0, n = max;
	size = 0;
	max = 2 * max;

	/* array variable is assigned with newly created Hash Table with double of previous array size */
	array = (struct arrayitem*) malloc(max * sizeof(struct node));

	init_array();

	for (i = 0; i < n; i++)
	{
		/* Extracting the Linked List at position i of Hash Table array */
		struct node* list = (struct node*) temp[i].head;
		if (list == NULL)
		{
			/* if there is no Linked List, then continue */
			continue;
		}
		else
		{
			/* Presence of Linked List at i Keep moving and accessing the Linked List item until the end.
			 *Get one key and value at a time and add it to new Hash Table array. */
			while (list != NULL)
			{
				insert(list->key, list->value);
				list = list->next;
			}
		}
	}
	temp = NULL;
}

/* This function finds the given key in the Linked List Returns it's index , Returns -1 in case key is not present */
int find(struct node *list, int key)
{
	int retval = 0;
	struct node *temp = list;
	while (temp != NULL)
	{
		if (temp->key == key)
		{
			return retval;
		}
		temp = temp->next;
		retval++;
	}
	return -1;
}

/* Returns the node (Linked List item) located at given find_index  */
struct node* get_element(struct node *list, int find_index)
{
	int i = 0;
	struct node *temp = list;
	while (i != find_index)
	{
		temp = temp->next;
		i++;
	}
	return temp;
}

/* To remove an element from Hash Table */
void remove_element(int key)
{
	int index = hashcode(key);
	struct node *list = (struct node*) array[index].head;

	if (list == NULL)
	{
		printf("This key does not exists\n");
	}
	else
	{
		int find_index = find(list, key);
		if (find_index == -1)
		{
			printf("This key does not exists\n");
		}
		else
		{
			struct node *temp = list;
			if (temp->key == key)
			{
				array[index].head = temp->next;
				printf("This key has been removed\n");
				return;
			}

			while (temp->next->key != key)
			{
				temp = temp->next;
			}

			if (array[index].tail == temp->next)
			{
				temp->next = NULL;
				array[index].tail = temp;
			}
			else
			{
				temp->next = temp->next->next;
			}

			printf("This key has been removed\n");
		}
	}
}

/* To display the contents of Hash Table */
void display()
{
	int i = 0;
	for (i = 0; i < max; i++)
	{
		struct node *temp = array[i].head;
		if (temp == NULL)
		{
			printf("array[%d] has no elements\n", i);
		}
		else
		{
			printf("array[%d] has elements-: ", i);
			while (temp != NULL)
			{
				printf("key= %d  value= %d\t", temp->key, temp->value);
				temp = temp->next;
			}
			printf("\n");
		}
	}
}

/* For initializing the Hash Table */
void init_array()
{
	int i = 0;
	for (i = 0; i < max; i++)
	{
		array[i].head = NULL;
		array[i].tail = NULL;
	}
}

/* Returns size of Hash Table */
int size_of_array()
{
	return size;
}

int main()
{
	int choice, key, value, n, c;
	system("cls");

	array = (struct arrayitem*) malloc(max * sizeof(struct arrayitem));

	init_array();
	do {

		printf("Implementation of Hash Table in C chaining with Singly Linked List \n\n");
		printf("MENU-: \n1.Inserting item in the Hash Table"
				"\n2.Removing item from the Hash Table"
				"\n3.Check the size of Hash Table"
				"\n4.To display a Hash Table"
				"\n\n Please enter your choice -: ");

		scanf("%d", &choice);

		switch(choice)
		{
			case 1:
				printf("Inserting element in Hash Table\n");
				printf("Enter key and value-:\t");
				scanf("%d", &key);
				scanf("%d", &value);
				insert(key, value);
				break;

			case 2:
				printf("Deleting in Hash Table \nEnter the key to delete-:");
				scanf("%d", &key);
				remove_element(key);
				break;

			case 3:
				n = size_of_array();
				printf("Size of Hash Table is-:%d\n", n);
				break;

			case 4:
				display();
				break;

			default:
				printf("Wrong Input\n");
				break;
		}

		printf("\nDo you want to continue-:(press 1 for yes)\t");
		scanf("%d", &c);
	} while(c == 1);

	getch();
	return 0;
}

0

Znacznie lepiej, ale nadal za długie te funkcje.

Np:

struct node
{
    int key;
    int value;
    struct node *next;
};

Zamieniamy na:

typedef struct _node
{
    int key;
    int value;
    struct _node *next;
} node;

Więc dalej zapominamy o słowie struct

Np:

    	struct node *item = (struct node*) malloc(sizeof(struct node));

    	printf("Test2");

    	item->key = key;
    	item->value = value;
    	item->next = NULL;
node *makenode(int key,int value,node *next)
{
    node *item=(node*)malloc(sizeof(node));
    assert(item!=NULL);
    item->key=key;
    item->value=value;
    item->next=next;
    return item;
}

oraz użycie:

    	struct node *item=makenode(key,value,NULL);
0

Tutaj masz przykład jak można to zrobić (bez usuwania pojedyńczego elementu(chyba) - może potem to dodam, za to z usuwaniem wszystkich na koniec, no i może zliczę rozmiar pamięci aktualnie używanej przez listę oraz dodam opcję sortowania). Umieszczam na stercie tylko nowe elementy typu struct *node. Pojedyńczo. Jakieś tam drobne mankamenty są ale mniej więcej o coś takiego mi chodziło.

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

/* Node for storing an item in a Linked List */
struct node
{
    int key;
    int value;
    int index;
    struct node *next;
};

/* For storing a Linked List at each index of Hash Table  */
struct arrayitem
{
    struct node *head;
    /* head pointing the first element of Linked List at an index of Hash Table */

    struct node *tail;
    /* tail pointing the last element of Linked List at an index of Hash Table */
};

struct arrayitem array;

int size = 0;         /* Determines the no. of elements present in Hash Table */
int max = 10;	      /* Determines the maximum capacity of Hash Table array */

// wyszukanie ostatniego elementu
struct node *find_last(){
	struct node *tmp_node;
	tmp_node=array.head;
	for(tmp_node=array.head;tmp_node->next!=NULL;tmp_node=tmp_node->next)
	{
	}
	return tmp_node;
}


// sprawdzenie czy istnieje juz obiekt o wpisanej przez uzytkownika wartosci pola "key"
struct node *check_list(int key_to_find){
	struct node *tmp_node;
	struct node *out_node=NULL;
	for(tmp_node=array.head;tmp_node->next!=NULL;tmp_node=tmp_node->next)
	{
		if(tmp_node->key==key_to_find){out_node=tmp_node;
		}
	}
	return out_node;
}

// prosta metoda wyswietlajaca pobiera element i dodaje pobrany opis
void print_item(struct node *tmp_node,char arr[20]){
printf("%s%d%s%d%s%d%s"," item with index ",tmp_node->index,"  with key ",tmp_node->key,"  and value ",tmp_node->value,arr);}

/* For initializing the Hash Table */
void init_array()
{
        array.head = NULL;
        array.tail = NULL;
 
}
// dodajemy nowy element
void insert(int key, int value)
{   
	struct node *tmp_node,*tmp_node_2,*item;
	
	if(size<max){ // skoro tak boisz się maxa

if(array.head==NULL){
		item = (struct node*) malloc(sizeof(struct node));

		item->key = key;
		item->value = value;
		item->next = NULL;
		item->index=size;
		printf("Inserting %d(key) and %d(value) \n", key, value);
		array.head = item;
		size++;
		}	
	else
	{	
		tmp_node_2 = check_list(key);
		
		// jesli element zostal znaleziony to podmieniamy wartosc value
		if(tmp_node_2!=NULL){
			
		tmp_node_2->value=value;	
		}
		else
		{
		item = (struct node*) malloc(sizeof(struct node));	
		item->key = key;
		item->value = value;
		item->next = NULL;
		item->index=size;	
		size++;	
		tmp_node_2 = find_last();	
		tmp_node_2->next = item;	
		}
	}
}
system("cls");
}

void display(){
system("cls");
struct node *tmp_node;
tmp_node=array.head;
printf("%s%d%s","Size of the list is  ",size,"\n");
if(array.head==NULL){
	printf("There are no items to view.");
	getch();
system("cls"); 
}else{

for(tmp_node=array.head;tmp_node!=NULL;tmp_node=tmp_node->next)
	{
		printf("%s%d%s%d%s%d%s","Index of element is ",tmp_node->index," with key ",tmp_node->key,"  has a value ",tmp_node->value,"\n");
	}	
	printf("Press any key to continue.");
	getch();
system("cls");	
}	
	
	
}
// funkcja zwalniajca pamiec

void freedom_for_lists(){

//usuwanie listy
int removed_size=0;
if(array.head!=NULL && array.head->next!=NULL){
	
struct node *tmp_node=array.head;
struct node *tmp_node_2;	
do{
tmp_node_2 = tmp_node;
tmp_node=tmp_node->next;
print_item(tmp_node, " shall be free!\n");
free(tmp_node_2);
removed_size++;	
}while(tmp_node!=NULL);	
	
}else{
if(size>1)	{removed_size=2;
print_item(array.head->next, " shall be free!\n");
free(array.head->next);
print_item(array.head, " shall be free!\n");
free(array.head);
}else{print_item(array.head, " shall be free!\n");removed_size=1;
free(array.head);
}}
printf("%s%d%s","Removed ",removed_size," items\n");
getch()	;
system("cls");
}




int main(int argc, char** argv) {

 	int choice, key, value, n, c;//choice=0;
   
	init_array();
	
	
	do {
	

					printf("Implementation of Hash Table in C chaining with Singly Linked List \n\n");
					printf("MENU-: \n1.Inserting item in the Hash Table"
				"\n2.Removing item from the Hash Table"
				"\n3.Check the size of Hash Table"
				"\n4.To display a Hash Table"
				"\n5.To quit press 0\n\n Please enter your choice -: ");

choice=getch();

switch(choice)
		{
			case 49:
			    system("cls");
				printf("Inserting element in Hash Table\n");
				printf("Enter key-:\n");
				scanf("%d", &key);
				printf("Enter value-:\n");
				scanf("%d", &value);
				insert(key, value);
				break;

			case 50:
				printf("Deleting in Hash Table \nEnter the key to delete-:");
				scanf("%d", &key);
			//	remove_element(key);
				break;

			case 51:
			//	n = size_of_array();
				printf("Size of Hash Table is-:%d\n", n);
				break;

			case 52:
				display();
				break;

			default:
				printf("Wrong Input\n");
				break;
		}

	

	
	}while(choice!=48);
	freedom_for_lists();
	return 0;
}
1
infinityhost napisał(a):
struct arrayitem
{
    struct node *head;
    struct node *tail;
};

Widzę że masz wskaźnik na ostatni element, to dobrze.

infinityhost napisał(a):
// wyszukanie ostatniego elementu
struct node *find_last(){
	struct node *tmp_node;
	tmp_node=array.head;
	for(tmp_node=array.head;tmp_node->next!=NULL;tmp_node=tmp_node->next)
	{
	}
	return tmp_node;
}

Doprawdy? A nie:

// wyszukanie ostatniego elementu
struct node *find_last() { return array.tail; }

?

Za wcześnie dla ciebie kogoś nauczać.

0

@infinityhost:
Albo ten tail używasz albo nie, bo jak masz ten tail którego ustawienie po każdym wstawianiu oraz usuwaniu ma koszt O(1) to nie ma co się zastanawiać i wyszukiwać ten koniec z kosztem O(N) Usuwanie tail!?!?
Puknij się w łeb pisanie kontenera który ma koszt wstawienia O(1) i używania w nim funkcji z kosztem O(N) - wylewasz kąpiel z dzieckiem!
Algorytmika się kłania! Na robocie to ty na 100% się nie znasz!
Różnica między nami jest taka że ja programuję zawodowo zaś ty znasz kilka instrukcji i tyle.
Do sprawdzenia służą testy jednostkowe a nie sam kod. Ja kontroluję kod podczas pisania czyli ten tail będzie zawsze odpowiedni i aktualizowany z kosztem O(1).
Zobacz jak ładnie działa tail myślący inaczej noob nieprogramisto:

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

#define GROWUP 1.8
#define SINKDOWN 0.4

typedef struct node
{
    int key;
    int value;
    struct node *next;
} node,*pnode;

typedef struct arrayitem
{
    pnode head,tail;
} arrayitem,*parrayitem;

typedef struct hashmap
{
	int listsize,size;
	parrayitem list;
} hashmap,*phashmap;

int hashcode(phashmap map,int key) { return key%(map->listsize); }

parrayitem listbykey(phashmap map,int key) { return map->list+hashcode(map,key); }

phashmap makemap(int listsize)
{
	phashmap ret=(phashmap)malloc(sizeof(hashmap));
	ret->listsize=listsize;
	ret->size=0;
	ret->list=(parrayitem)calloc(listsize,sizeof(arrayitem)); // wyzeruje
	return ret;
}

void freelist(parrayitem list)
{
	while(list->head)
	{
		pnode n=list->head;
		list->head=n->next;
		free(n);
	}
}

void freearray(parrayitem list,int listsize)
{
	for(int i=0;i<listsize;++i) freelist(list+i);
	free(list);
}

void freemap(phashmap map)
{
	freearray(map->list,map->listsize);
	free(map);
}

pnode makenode(int key,int value,pnode next)
{
    pnode ret=(pnode)malloc(sizeof(node));
    ret->key=key;
    ret->value=value;
    ret->next=next;
    return ret;
}

int containskey(parrayitem list,int key)
{
	for(pnode n=list->head;n;n=n->next) if(n->key==key) return 1;
	return 0;
}

int insertlist(parrayitem list,pnode item)
{
	if(list->tail) list->tail->next=item;
	else list->head=item;
	list->tail=item;
	return 1;
}

int insertnode(phashmap map,int key,int value)
{
    parrayitem list=listbykey(map,key);
	if(containskey(list,key)) return 0;
    insertlist(list,makenode(key,value,NULL));
    return 1;
}

void rehash(phashmap map,int newsize)
{
	phashmap tmpmap=makemap(newsize);
	int tmplistsize=map->listsize; // wymiana rozmiarów
	map->listsize=tmpmap->listsize;
	tmpmap->listsize=tmplistsize;
	parrayitem tmplist=map->list; // wymiana list
	map->list=tmpmap->list;
	tmpmap->list=tmplist;
    for(int i=0;i<tmpmap->listsize;++i)
    {
    	parrayitem list=tmpmap->list+i;
    	while(list->head)
		{
			pnode n=list->head;
			list->head=n->next;
			n->next=NULL;
			insertlist(listbykey(map,n->key),n);
		}
    }
    free(tmpmap->list);
}

int insertkey(phashmap map,int key,int value)
{
	if(!insertnode(map,key,value)) return 0;
    if(++map->size>=GROWUP*map->listsize) rehash(map,(map->listsize)<<1);
    return 1;
}

int removekey(phashmap map,int key)
{
	parrayitem list=listbykey(map,key);
	for(pnode p=NULL,n=list->head;n;p=n,n=n->next)
	{
		if(n->key==key)
		{
			if(p) p->next=n->next;
			else list->head=n->next;
			if(!n->next) list->tail=p;
			free(n);
			if(--map->size<=SINKDOWN*map->listsize) rehash(map,(map->listsize)>>1);
			return 1;
		}
	}
	return 0;
}

void display(phashmap map)
{
    for(int i=0;i<map->listsize;++i)
    {
    	parrayitem list=map->list+i;
	   	printf("list[%d]={",i);
	   	int first=1;
    	for(pnode n=list->head;n;n=n->next)
		{
			if(first) first=0; else printf(",");
			printf(" %d=>%d",n->key,n->value);
		}
		printf(" }\n");
    }
}

int main()
{
	phashmap map=makemap(1);
    printf("Implementation of Hash Table in C chaining with Singly Linked List\n\n");
    for(;;)
	{
        printf
		(
			"MENU:\n"
			"1. Inserting item in the Hash Table\n"
            "2. Removing item from the Hash Table\n"
            "3. To display a Hash Table\n"
            "0. Koniec\n"
		);
        int choice;
        while((printf("Please enter your choice: "))&&(scanf("%d",&choice)!=1)) while(getchar()!='\n') {}
        switch(choice)
	    {
    	    case 1:
    	    {
            	printf("Inserting element in Hash Table\n");
    	    	int key,value;
		        while((printf("Enter key and value: "))&&(scanf("%d%d",&key,&value)!=2)) while(getchar()!='\n') {}
	            if(insertkey(map,key,value)) display(map);
				else printf("Key %d already contains\n",key);
    	        break;
			}
            case 2:
            {
				printf("Deleting in Hash Table\n");
				int key;
        		while((printf("Enter the key to delete: "))&&(scanf("%d",&key)!=1)) while(getchar()!='\n') {}
				if(removekey(map,key)) display(map);
				else printf("Not found key %d\n",key);
				break;
			}
            case 3:
            {
            	display(map);
            	break;
			}
			case 0:
			{
				freemap(map);
			    return 0;
			}
            default:
            {
				printf("Wrong Input\n");
        		break;
			}
        }
    }
}

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.