Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <pre><code>holder = (song_t *)malloc(sizeof(song_t)); /* snip */ /* else if */ holder = temp2-&gt;next-&gt;next; /* else */ holder = temp; temp2-&gt;next = temp-&gt;next; free(holder); </code></pre> <p>When you assign <code>holder = temp2-&gt;next-&gt;next;</code> (incidentally, that's always <code>NULL</code> there), or <code>holder = temp;</code>, you're losing your reference to the <code>malloc</code>ed memory. Since you're not really using <code>holder</code> at all, the fix is to remove it from the function. In the first case, you're not using it in any way except to assign a complicated <code>NULL</code>, in the second case, removing <code>holder = temp;</code> and <code>free</code>ing <code>temp</code> is the correct way.</p> <p>There are a few more strange things and mistakes:</p> <pre><code>song_t *DeleteSong(song_t *head, string key){ song_t *temp, *temp2, *holder; holder = (song_t *)malloc(sizeof(song_t)); // as said, remove holder completely temp = head; /* Find song with given title */ while(temp != NULL &amp;&amp; strcasecmp(temp-&gt;title, key) != 0){ temp = temp-&gt;next; } if(temp == NULL){ newline; printf("Song not found."); newline; newline; } /* It's the very first in the list */ else if(temp == head){ if(temp-&gt;next == NULL){ /* It's even the only one */ temp-&gt;next = NULL; // This runs only if temp-&gt;next is already NULL free(temp); // Also free the members of temp, or you're leaking return NULL; } else{ head = temp-&gt;next; // You should now free temp and members, or you're leaking memory } } /* It's the last one in the list, but not the first */ else if(temp-&gt;next == NULL){ temp2 = head; /* Find the penultimate song */ while(temp2-&gt;next-&gt;next != NULL){ temp2 = temp2-&gt;next; } holder = temp2-&gt;next-&gt;next; temp2-&gt;next = NULL; // You should now free temp and members, or you're leaking memory } /* Neither first nor last */ else{ temp2 = head; /* Find song before */ while(temp2-&gt;next != temp){ temp2 = temp2-&gt;next; } holder = temp; temp2-&gt;next = temp-&gt;next; free(holder); } return head; } </code></pre> <p>but apart from the leaks, it is correct, though unnecessarily complicated.</p> <pre><code>song_t *DeleteSong(song_t *head, string key) { song_t *prev = NULL, curr = head; /* Find song and node before that */ while(curr != NULL &amp;&amp; strcasecmp(curr-&gt;title, key) != 0) { prev = curr; curr = curr-&gt;next; } if (curr == NULL) { /* Not found */ newline; printf("Song not found."); newline; newline; } else if (prev == NULL) { /* It's the very first song in the list * so let head point to its successor * and free the song; it doesn't matter * if it's the last in the list */ head = curr-&gt;next; free(curr-&gt;title); // Probably, but not if title isn't malloced free(curr-&gt;artist); // Ditto free(curr-&gt;album); free(curr-&gt;genre); free(curr); } else { /* We have a predecessor, let that point * to the successor and free the song */ prev-&gt;next = curr-&gt;next; free(curr-&gt;title); // See above free(curr-&gt;artist); free(curr-&gt;album); free(curr-&gt;genre); free(curr); } return head; } </code></pre> <p>Your <code>RemoveDuplicate</code> function on the other hand does not do what you intend. Apart from the distinction between the cases where the duplicate immediately follows the original and where it doesn't, for which I can see no reason, the assignments <code>temp = DeleteSong(temp,temp2-&gt;title);</code> resp. <code>temp2 = DeleteSong(temp2-&gt;next,temp2-&gt;title);</code> change what <code>temp</code> resp. <code>temp2</code> point to, but not where the respective predecessor in the list points. Let's illustrate the problem with a little ASCII art:</p> <pre><code> temp temp2 | | v v song1-&gt;song2-&gt;song3-&gt;song4-&gt;song5-&gt;... </code></pre> <p>where <code>song2</code> and <code>song3</code> are duplicates. Now in <code>temp = DeleteSong(temp,temp2-&gt;title);</code>, since the two songs are duplicates, the <code>head</code> argument of <code>DeleteSong</code> already matches, and in your version of <code>DeleteSong</code>, <code>head = temp-&gt;next; return head;</code> is all that is done, so the list is not changed at all, you just get</p> <pre><code> temp temp2 | | v v song1-&gt;song2-&gt;song3-&gt;song4-&gt;... </code></pre> <p>both pointers pointing to the same list node. In my version of <code>DeleteSong</code> that frees the node, <code>song1.next</code> would now point to <code>free</code>d memory, ouch.</p> <p>If the duplicate doesn't immediately follow the original, <code>temp2 = DeleteSong(temp2-&gt;next,temp2-&gt;title);</code> may not find a song with matching title, since the search starts <em>after</em> the known match, in which case the list is not modified at all, and <code>temp2</code> is just changed to point to the successor. If there is a song with matching title after that, the found duplicate is still not removed from the list, and the part after that may be changed, possibly leading to an unsound state. If <code>temp2</code> points to the penultimate node in the list, and the last node has a matching title, the last node is <code>free</code>d, but the <code>next</code> pointer of what was the duplicate isn't changed, so now it points to <code>free</code>d memory, you have a dangling pointer (that's a segfault waiting to happen).</p> <p>A further problem is that the criteria for removal in <code>DeleteSong</code> and <code>RemoveDuplicate</code> are different, in the former, you check only the title, in the latter also artist, album and genre, so using the former function in the latter risks deleting songs that should not be deleted (consider cover versions).</p> <p>When you want to delete a node from a singly linked list, you need a pointer to the preceding node to be able to change what that points to, or you'll create dangling pointers. I have given a standard way to do that above, you can basically copy that into the inner loop, but here it can never happen that we want to remove the first node, so it's a bit simpler:</p> <pre><code>// void, since head is never changed, only duplicates after the original are removed void RemoveDuplicates(song_t *head) { song_t *orig = head, prev, curr; while(orig != NULL &amp;&amp; orig-&gt;next != NULL) { prev = orig; curr = orig-&gt;next; while(curr != NULL) { // Find next song to remove while(curr != NULL &amp;&amp; !meets_deletion_criteria(orig, curr)) { prev = curr; curr = curr-&gt;next; } // Now either curr is NULL, or it shall be deleted if (curr != NULL) { // Let the predecessor point to curr's successor prev-&gt;next = curr-&gt;next; clean_up(curr); // free all malloced members and the node itself curr = prev-&gt;next; } } orig = orig-&gt;next; } } </code></pre>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload