Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Some of your problems are in the <code>for</code> loop inside <code>htable_insert()</code>:</p> <ol> <li>You don't include <code>return 1;</code> after you insert a new entry in a previously NULL entry.</li> <li><p>Your wraparound code is modifying the wrong variable (<code>i</code>). I think it should be:</p> <pre><code>if (remainder &gt;= h-&gt;capacity - 1) remainder = 0; else remainder++; </code></pre></li> <li><p>You have roughly the same problem in the search code, too.</p></li> </ol> <hr> <p>Suggestion:</p> <p>If you have a relatively complex data structure such as the hash table, it is worth creating (and debugging) a function of the form <code>void dump_htable(FILE *fp, const char *tag, const htable h)</code>. The function will print a diagnostic dump of the contents of the structure to the given file (often <code>stdout</code>, but sometimes <code>stderr</code> or a log file), prefixing the information with the <code>tag</code> so that you can tell which particular call to the dump function the output comes from. The function can also do basic validation — for example, it should ensure that the pointer it is given is not null (though it will print it out regardless), and should clearly only vet the contents of the structure if the pointer is not null. You can call this function immediately after the hash table is created, and again after each insert operation. This will allow you to check that the code is working as you expect.</p> <p>Keep the function in the code; make sure it is compiled routinely (so it doesn't get stale) and use it whenever you run into problems with a hash table.</p> <hr> <h2>SSCCE — Working Code</h2> <h3>htable.h</h3> <pre><code>#ifndef HTABLE_H_INCLUDED #define HTABLE_H_INCLUDED struct htablerec { char **key; int *frequencies; int num_keys; int capacity; }; typedef struct htablerec *htable; extern int htable_insert(htable h, char *str); extern htable htable_new(unsigned size); extern int htable_search(htable h, char *str); extern void htable_free(htable h); #endif /* HTABLE_H_INCLUDED */ </code></pre> <h3>htable.c</h3> <pre><code>#include "htable.h" #include &lt;stdlib.h&gt; #include &lt;stdio.h&gt; #include &lt;string.h&gt; static void *emalloc(size_t size) { void *space = malloc(size); if (space == 0) { fprintf(stderr, "Failed to allocate %zu bytes of memory\n", size); exit(EXIT_FAILURE); } return space; } static unsigned int htable_word_to_int(const char *word) { unsigned int result = 0; while (*word != '\0') { result = (*word++ + 31 * result); } return result; } htable htable_new(unsigned size) { htable h = emalloc(sizeof(*h)); size_t nbytes = size * sizeof(*h-&gt;key); h-&gt;key = emalloc(nbytes); memset(h-&gt;key, '\0', nbytes); h-&gt;frequencies = emalloc(size * sizeof(*h-&gt;frequencies)); h-&gt;capacity = size; h-&gt;num_keys = 0; return h; } void htable_free(htable h) { if (h != 0) { free(h-&gt;frequencies); free(h-&gt;key); free(h); } } int htable_insert(htable h, char *str) { int i; unsigned int index = htable_word_to_int(str); int remainder = index % h-&gt;capacity; for (i = 0; i &lt; h-&gt;capacity; i++) { /* 1. No string at this position */ if (h-&gt;key[remainder] == NULL) { char *key = emalloc(strlen(str) + 1); strcpy(key, str); h-&gt;key[remainder] = key; h-&gt;frequencies[remainder] = 1; h-&gt;num_keys++; return 1; } /* 2. the same string is already there */ if (strcmp(str, h-&gt;key[remainder]) == 0) { h-&gt;frequencies[remainder]++; return h-&gt;frequencies[remainder]; } /* 3. Keep searching */ if (remainder &gt;= h-&gt;capacity - 1) remainder = 0; else remainder++; } /* No match and no empty spaces left - hash table is full */ return 0; } int htable_search(htable h, char *str) { unsigned int index = htable_word_to_int(str); int remainder = index % h-&gt;capacity; for (int i = 0; i &lt; h-&gt;capacity; i++) { if (h-&gt;key[remainder] == NULL) return -1; /* Definitively not present */ if (strcmp(str, h-&gt;key[remainder]) == 0) return remainder; /* Definitively present */ if (remainder &gt;= h-&gt;capacity - 1) remainder = 0; else remainder++; } /* Table's full and key not found */ return -1; } </code></pre> <h3>test.htable.c</h3> <pre><code>#include "htable.h" #include &lt;assert.h&gt; #include &lt;inttypes.h&gt; #include &lt;stdio.h&gt; #include &lt;stdlib.h&gt; static void dump_htable(FILE *fp, const char *tag, const htable h) { fprintf(fp, "HASHTABLE: %s (0x%" PRIXPTR "\n", tag, (uintptr_t)h); if (h != 0) { fprintf(fp, "Capacity: %d; Number of keys: %d\n", h-&gt;capacity, h-&gt;num_keys); fprintf(fp, "Keys: 0x%" PRIXPTR "; Freq: 0x%" PRIXPTR "\n", (uintptr_t)h-&gt;key, (uintptr_t)h-&gt;frequencies); assert(h-&gt;key != 0 &amp;&amp; h-&gt;frequencies != 0); if (h-&gt;num_keys &gt; 0) { for (int i = 0; i &lt; h-&gt;capacity; i++) { if (h-&gt;frequencies[i] != 0) { assert(h-&gt;key[i] != 0); fprintf(fp, "%3d: %2d %s\n", i, h-&gt;frequencies[i], h-&gt;key[i]); } } } } fflush(fp); } int main(void) { htable h = htable_new(113); char word[256]; char op; /*We must have a space before the %c*/ while(2 == scanf(" %c %255s", &amp;op, word)) { if ('+' == op) { if (htable_insert(h, word) &lt;= 0) printf("Error: failed to insert %s\n", word); else dump_htable(stdout, word, h); } else if ('?' == op) printf("%d %s\n", htable_search(h, word), word); else printf("Bogus: %c %s\n", op, word); } htable_free(h); return EXIT_SUCCESS; } </code></pre> <h3>Sample output</h3> <p>Last dump of hash table — for checking — and results.</p> <pre><code>HASHTABLE: unloaded (0x10F100910 Capacity: 113; Number of keys: 50 Keys: 0x10F100930; Freq: 0x10F100CC0 2: 1 wakes 7: 1 necrosis 8: 1 galleries 9: 1 Russia 10: 1 Georges 11: 1 outright 13: 1 brokers 16: 1 factoring 17: 1 keypad 18: 1 Latinizers 19: 1 rhythmically 20: 1 binders 27: 1 sociable 30: 1 Riemannian 33: 1 gentler 38: 1 segregation 39: 1 invalidity 43: 1 snowily 47: 1 cupful 48: 1 zebras 49: 1 Capet 50: 1 dominating 51: 1 unloaded 52: 1 unsound 53: 1 revocable 54: 1 tied 58: 1 combed 59: 1 leadings 60: 1 bran 61: 1 contented 62: 1 sequences 64: 1 replaced 69: 1 escorted 70: 1 infringing 71: 1 onslaught 72: 1 tiring 75: 1 screamer 80: 1 admire 84: 1 build 87: 1 Ottawa 92: 1 Malawi 93: 1 kidded 94: 1 files 95: 1 disconnects 96: 1 puzzles 97: 1 attendances 103: 1 diversification 104: 1 digressed 111: 1 swarthy 112: 1 thickness -1 insincere -1 constants -1 unordered -1 Toland -1 butterfly -1 suburban -1 overtone -1 Hauser -1 numbers -1 disadvantageous -1 saintly -1 Dutton -1 homomorphic -1 corporation -1 climaxes -1 dietitian -1 manifestly -1 greyest -1 challenge -1 tentacle -1 Bernice -1 bottle -1 involve -1 resisted -1 wholesale -1 trustworthiness -1 Poole -1 fourfold -1 relentlessly -1 fittingly -1 doctorates -1 cowlick -1 Missoula -1 curtsy -1 calmness -1 reallocate -1 bossed -1 scarce -1 catheters -1 regained -1 autographing -1 unobservable -1 apprise -1 lancer -1 chicken -1 crunches -1 scrambled -1 reared -1 pealing -1 violate 27 sociable 8 galleries 9 Russia 75 screamer 112 thickness 58 combed 69 escorted 53 revocable 104 digressed 92 Malawi 70 infringing 71 onslaught 94 files 93 kidded 52 unsound 54 tied 87 Ottawa 96 puzzles 84 build 7 necrosis 80 admire 47 cupful 13 brokers 38 segregation 49 Capet 10 Georges 60 bran 20 binders 48 zebras 61 contented 17 keypad 43 snowily 64 replaced 50 dominating 11 outright 18 Latinizers 39 invalidity 2 wakes 103 diversification 30 Riemannian 59 leadings 19 rhythmically 33 gentler 111 swarthy 95 disconnects 16 factoring 62 sequences 72 tiring 97 attendances 51 unloaded </code></pre>
    singulars
    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.
 

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