È bene usare un numero primo per dimensionare la hashtable. Per cancellare un nodo da una lista, si deve prima far puntare il nodo precedente al nodo successivo.

Così dovrebbe andare:

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

#define M 4093
#define DIM_ELEM 89

typedef struct tagNodo
{
	int key;
	char* val;
	struct tagNodo* next;
} nodo;

typedef struct tagHashMap
{
	nodo* lista[M];
}hashmap;

typedef int (*HashFunz)(int k);//puntatore a funzione 

int hash1(int k);

void hm_free_list(nodo* first);
void hm_insert(hashmap* h, char* e, int k, HashFunz hf);
nodo* hm_delete_node(nodo *first, int k);
void hm_delete(hashmap* h, int k, HashFunz hf);
char* hm_search(hashmap* h, int k, HashFunz hf);
void print(hashmap* h);
int menu();


int main()
{
	hashmap tavola;
	int metodo;
	HashFunz funzHash;
	int chiave;
	int scelta;
	char* elemento;
	int k;

	funzHash = hash1;

	for (k = 0; k < M; k++)
		tavola.lista[k] = NULL;

	while(1)
	{
		scelta = menu();
		elemento = (char*)malloc(DIM_ELEM * sizeof(char) + 1);
		if ( !elemento )
		{
			printf("Memoria insufficiente.\n");
			break;
		}

		switch (scelta)
		{
			case 1: 
				printf("Inserisci chiave:\n");
				scanf("%d", &chiave);
				printf("Inserisci elemento:\n");
				scanf("%s", elemento);
				hm_insert(&tavola,elemento,chiave,funzHash);
				break;
			case 2:	
				printf("Cerca chiave:\n");
				scanf("%d", &chiave);
				elemento = hm_search(&tavola,chiave,funzHash);	
				if(elemento==NULL)
					printf("Chiave non trovata.\n");
				else
					printf("Elemento trovato: %s\n", elemento);
				break;
			case 3:
				printf("Cancella chiave:\n");
				scanf("%d", &chiave);
				hm_delete(&tavola,chiave,funzHash);
				break;
			case 4:
				print(&tavola);
				break;	
			default:
				for (k = 0; k < M; k++)
					hm_free_list(tavola.lista[k]);
				return 0;
		}
	}
	
	return 0;
}

int hash1(int k)
{
	return k%M;
}

void hm_free_list(nodo* first)
{
	nodo *n1 = first, *n2;
	while ( n1 != NULL )
	{
		free(n1->val);
		n2 = n1->next;
		free(n1);
		n1 = n2;
	}
}

void hm_insert(hashmap* h, char* e, int k, HashFunz hf)
{
	nodo *temp, *nuovo;
	int indice;

	if ( hm_search(h, k, hf) != NULL )
	{
		printf("La chiave inserita, %d, e' gia' presente nel dizionario.\n", k);
		return;
	}

	indice = (*hf)(k);

	nuovo = (nodo*)malloc(sizeof(nodo));
	if ( !nuovo )
	{
		printf("Memoria insufficiente.\n");
		return;
	}

	nuovo->key = k;
	nuovo->val = e;
	nuovo->next = NULL;
	temp = h->lista[indice];
	if(temp != NULL)
	{
		while(temp->next != NULL)
		{
			temp = temp->next;
		}
		temp->next = nuovo;
	}
	else
	{
		h->lista[indice] = nuovo;
	}

	printf("Voce inserita nel dizionario.\n");
}

nodo* hm_delete_node(nodo *first, int k)
{
	nodo *n1 = first, *n2;
	nodo *prev = NULL;

	if ( first == NULL )
		return NULL;

	while ( n1 != NULL )
	{
		if ( n1->key == k )
		{
			if ( !prev ) /* Se prev è NULL, stiamo cancellando il primo nodo della lista */
			{
				n1 = n1->next;
				free(first);
				return n1;
			}
			else
			{
				n2 = n1->next;
				free(n1);
				prev->next = n2;
				return first;
			}
		}
		else
		{
			prev = n1;
			n1 = n1->next;
		}
	}

	return first;
}

void hm_delete(hashmap* h, int k, HashFunz hf)
{
	int indice = (*hf)(k);
	nodo* temp = h->lista[indice];

	h->lista[indice] = hm_delete_node(temp, k);
}

char* hm_search(hashmap* h, int k, HashFunz hf)
{
	int indice = (*hf)(k);
	nodo* temp = h->lista[indice];
	while(temp != NULL)
	{
		if(temp->key == k)
		{
			return temp->val;
		}
		else
		{
			temp = temp->next;
		}
	}
	return NULL;
}

void print(hashmap* h)
{
	int i;
	nodo* temp;

	printf("\n\n********************************\n");
	printf("Voci dizionario:\n");
	printf("Indice\t\tChiave\t\tElemento\n");

	for(i = 0; i < M; i++)
	{
		temp = h->lista[i];
		while(temp != NULL)
		{
			printf("%d\t\t%d\t\t%s\n",i,temp->key,temp->val);
			temp = temp->next;
		}
	}
	printf("\n********************************\n\n");
	return;
}

int menu()
{
	int scelta;

	printf("\nMENU' DIZIONARIO");
	printf("\n1) Aggiungi voce (con chiavi distinte)");
	printf("\n2) Cerca chiave");
	printf("\n3) Elimina chiave");
	printf("\n4) Visualizza dizionario");
	printf("\n5) Esci");
	printf("\nScelta: ");
	scanf("%d", &scelta);
	
	return scelta;
}