Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>So let's start at the beginning. You read key,data pairs of strings from a file. You build a linked list of those pairs in the order you've read them. Then what?</p> <pre><code>/* compile with: gcc -std=c89 -pedantic -Wall -O2 -o so_10185705 so_10185705.c test with: valgrind ./so_10185705 */ #include &lt;stdlib.h&gt; #include &lt;string.h&gt; #include &lt;stdio.h&gt; struct node_t { char key[32]; char value[64]; struct node_t *next; }; static void print_list(const struct node_t *curr) { while (curr) { printf("%s, %s\n", curr-&gt;key, curr-&gt;value); curr = curr-&gt;next; } } static void free_list(struct node_t **currp) { struct node_t *curr = *currp; *currp = NULL; /* don't leave dangling pointers */ while (curr) { struct node_t *next = curr-&gt;next; curr-&gt;next = NULL; free((void *)curr); curr = next; } } /* O(n) but useful */ static const struct node_t * find_in_list(const struct node_t *curr, const char *key) { while (curr) { if (!strncmp(curr-&gt;key, key, sizeof(curr-&gt;key))) return curr; curr = curr-&gt;next; } return NULL; } /* Same as find_in_list but less useful */ static int is_in_list(const struct node_t *curr, const char *key) { while (curr) { if (!strncmp(curr-&gt;key, key, sizeof(curr-&gt;key))) return 1; curr = curr-&gt;next; } return 0; } int main() { struct node_t *head = NULL; FILE *f = fopen("foo", "r"); if (!f) exit(1); while (!feof(f)) { struct node_t *new_node = malloc(sizeof(struct node_t)); fscanf(f, "%s %s", new_node-&gt;key, new_node-&gt;value); new_node-&gt;next = head; head = new_node; } fclose(f); print_list(head); const struct node_t *node = find_in_list(head, "abcd2"); if (node) { printf("found! key = %s, value = %s\n", node-&gt;key, node-&gt;value); } else { printf("not found!\n"); } if (is_in_list(head, "abcd3")) { printf("found key in list but now I don't know the value associated with this key.\n"); } else { printf("not found!\n"); } free_list(&amp;head); return 0; } /* explanation of bugs in OP's code */ struct node_t_2 { char *key; char *value; struct node_t_2 *next; }; void build_list(FILE *f, struct node_t_2 *curr) { while (!feof(f)) { /* These variable are allocated on the stack. Their lifetime is limited to the current scope. At the closing curly brace of the block in which they are declared, they die, the information in them is lost and pointer to them become invalid garbage. */ key char[32]; value char[64]; /* Of course, you can only read keys up to 31 bytes long and values up to 63 bytes long. Because you need an extra byte for the string's NUL terminator. fscanf puts that NUL terminator for you. If it didn't, you would not be able to use the data: you would not know the lenth of the string. If you need 32-byte long keys, declare the variable key to be 33 bytes long. */ fscanf(f, "%s %s", key, value); /* You can use key and value here */ struct node_t_2 bad_new_node; /* You cannot add bad_new_node to the list, because as soon as you reach '}' it will die. You need a place for the node that will not disappear (be reused on the next iteration of the loop). So it must be on the heap. How many bytes do you need for the node? Enough to hold the three pointers: 12 bytes on 32bit, 24 bytes on 64bit. The compiler knows how many bytes a struct needs. */ struct node_t_2 *new_node = malloc(sizeof(struct node_t_2)); /* You can add new_node to the list, because it is on the heap and will exist until either passed to free() or the process (program) exits. */ new_node-&gt;key = key; new_node-&gt;value = value; /* That was a bug, because we stored pointers to garbage. Now new_node has a pointer to a place that will cease to exist as soon as we reach '}'. */ new_node-&gt;key = strdup(key); new_node-&gt;value = strdup(value); /* strdup is a standard function that can be implemented like this: char * strdup(const char *s) { int len = strlen(s) char *p = malloc(len); memcpy(p, s, len); return p; } Now new_node has pointers to memory on the heap that will continue to exist until passed to free or the process terminates. */ new_node-&gt;next = curr; curr = new_node; /* At the next line, memory for key and value is disappears and is re-used if we re-enter the loop. */ } } /* If your list nodes have pointers instead of arrays, you need to free the strings pointed to by those pointers manually, becuause freeing the list node wont free stuff it points to. */ free_list(struct node_t_2 **currp) { struct node_t_2 *curr = *currp; *currp = NULL; while (curr) { struct node_t_2 *next = curr-&gt;next; free((void *)curr-&gt;key); curr-&gt;key = NULL; free((void *)curr-&gt;value); curr-&gt;value = NULL; curr-&gt;next = NULL; free((void *)curr); curr = next; } } </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.
    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