There are many things that an experience programmer would do differently. But I understand that you are still learning. So let's first fix the bug in your program.
Take a look at your function del:
piece* del(piece* p_list,int number) \\ deletes the element (number) from list
{
if (p_list->num == number)
{
piece* p_delete = p_list;
p_list = p_list->p_next;
delete p_delete;
return p_list;
}
else
{
return p_list->p_next = del(p_list->p_next,number); }
}
Actually, this function should not return anything. But as you are passing the list pointer by value (first argument) you can't modify the list pointer that resides outside the function. Therefore, you returned the new list pointer and the caller's responsibility is to assign it to the outside list pointer.
As the function del should work recursively (no good idea!), you are deferring another responsibility to the caller, namely to fix the p_next pointer in the previous element (to which function del has no access). And that is the design flaw. The caller has no idea, whether he should simply fix the previous p_next or whether he has to fix the outside list pointer.
Here is the way to resolve that: Give del as first agrument a piece**, that is:
void del (piece** pp_list, int number)
Now you can manipulate the outside list pointer from with del. And the interface of del is that after it returns, all is done. The caller has not to care about anything.
I leave it up to you to modify the code inside the function. The important part is to give the previous element's p_next pointer's address as first argument in the recursive call:
else
{
piece* p_elem = *pp_list;
del (&p_elem->p_next, number);
}
After you fixed that, I would strongly recommend to do a non-recursive version,
which is not only easier to write, but will also be faster.