In addition to initializing set and copying word, there are a number of additional somewhat subtle issues you are missing, and that can bite you. To begin lets start with a couple of non-consequential logic issues. Rarely, if ever do you actually want to store a string with the '\n' dangling off the end, just remove the newline read and included in word by fgets, e.g.
/* remove trailing '\n' */
size_t len = strlen (word);
if (word[len - 1] == '\n')
word[--len] = 0; /* overwrite with nul-byte */
(having len also gives you the ability to allocate the exact amount of memory required to hold word, e.g. len + 1)
Which also gives you the opportunity to check for your exit condition with a simple length and character comparison at this point, e.g.
if (len == 1 && *word == '-') /* test for '-' */
break;
(which also means your read loop can simply be for (;;) {...} which will not store "-" as one of your words)
As noted in my comment, never directly assign the return of the pointer being reallocated. Why? If realloc fails, set is not freed and realloc returns NULL -- which you then assign to set losing the reference to set and creating a memory leak. Instead, always use a temporary pointer, e.g.
/* process - validate all allocations */
void *tmp = realloc (set, sizeof *set * (numberWord + 1));
if (!tmp) {
fprintf (stderr, "error: virtual memory exhausted - realloc.\n");
break;
}
set = tmp;
You are allocating memory for each word, but failing to free the memory you allocate for each word. You can do this in your output loop if you no longer need the memory thereafter, e.g.
/* output */
printf ("\nSORTED:\n");
for (j = 0; j < numberWord; j++) {
printf (" %s\n", set[j]);
free (set[j]); /* don't forget to free word */
}
free(set); /* free pointers */
putchar ('\n'); /* don't use printf for single char */
Above you indicate your are outputting your words in SORTED order, but nowhere do you sort your words. The simplest way to sort the words is to create a simple comparison function for the pointers in set and then pass set to qsort for sorting, e.g.
int cmpstrings (const void *a, const void *b) {
return strcmp (*(char * const *)a, *(char * const *)b);
}
int main (void) {
...
qsort (set, numberWord, sizeof *set, cmpstrings); /* sort */
Putting all the pieces together and rearranging the logic of your request for input in a more concise manner, you could do something like the following:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define WORD_SIZE 11
int cmpstrings (const void *a, const void *b) {
return strcmp (*(char * const *)a, *(char * const *)b);
}
int main (void) {
char word[WORD_SIZE] = "",
**set = NULL;
int j, numberWord = 0;
for (;;) {
/* input */
printf("Insert a word, or '-' to stop: ");
fgets(word, WORD_SIZE, stdin);
/* remove trailing '\n' */
size_t len = strlen (word);
if (word[len - 1] == '\n')
word[--len] = 0; /* overwrite with nul-byte */
if (len == 1 && *word == '-') /* test for '-' */
break;
/* process - validate all allocations */
void *tmp = realloc (set, sizeof *set * (numberWord + 1));
if (!tmp) {
fprintf (stderr, "error: virtual memory exhausted - realloc.\n");
break;
}
set = tmp;
set[numberWord] = malloc (sizeof *set[numberWord] * (len + 1));
if (!set[numberWord]) {
fprintf (stderr, "error: virtual memory exhausted - malloc.\n");
break;
}
strcpy (set[numberWord], word);
numberWord++;
}
qsort (set, numberWord, sizeof *set, cmpstrings); /* sort */
/* output */
printf ("\nSORTED:\n");
for (j = 0; j < numberWord; j++) {
printf (" %s\n", set[j]);
free (set[j]); /* don't forget to free word */
}
free(set); /* free pointers */
putchar ('\n'); /* don't use printf for single char */
return 0;
}
Example Use/Output
$ ./bin/dynwords
Insert a word, or '-' to stop: my
Insert a word, or '-' to stop: dog
Insert a word, or '-' to stop: has
Insert a word, or '-' to stop: fleas
Insert a word, or '-' to stop: the
Insert a word, or '-' to stop: cat
Insert a word, or '-' to stop: doesn't
Insert a word, or '-' to stop: have
Insert a word, or '-' to stop: any
Insert a word, or '-' to stop: -
SORTED:
any
cat
doesn't
dog
fleas
has
have
my
the
In any code you write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.
It is imperative that you use a memory error checking program to insure you haven't written beyond/outside your allocated block of memory, attempted to read or base a conditional jump on an uninitialized value and finally to confirm that you have freed all the memory you have allocated.
For Linux valgrind is the normal choice. There are similar memory checkers for every platform. They are all simple to use, just run your program through it, e.g.
$ valgrind ./bin/dynwords
==10572== Memcheck, a memory error detector
==10572== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==10572== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==10572== Command: ./bin/dynwords
==10572==
Insert a word, or '-' to stop: my
Insert a word, or '-' to stop: dog
Insert a word, or '-' to stop: has
Insert a word, or '-' to stop: fleas
Insert a word, or '-' to stop: the
Insert a word, or '-' to stop: cat
Insert a word, or '-' to stop: doesn't
Insert a word, or '-' to stop: have
Insert a word, or '-' to stop: any
Insert a word, or '-' to stop: -
SORTED:
any
cat
doesn't
dog
fleas
has
have
my
the
==10572==
==10572== HEAP SUMMARY:
==10572== in use at exit: 0 bytes in 0 blocks
==10572== total heap usage: 18 allocs, 18 frees, 402 bytes allocated
==10572==
==10572== All heap blocks were freed -- no leaks are possible
==10572==
==10572== For counts of detected and suppressed errors, rerun with: -v
==10572== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Always confirm you have freed all memory you have allocated and that there are no errors.
Look things over and let me know if you have any questions. There are a number of subtle changes incorporated, so if there is something you don't understand, just drop a comment below.
char **set;-->char **set = NULL;2)set[j]doesn't set word.strcpy(set[numberWord], word);beforenumberWord++;.char **set = NULL;? (attempted access of an uninitialized variable is Undefined Behavior) Also, never assign the result ofreallocto the variable itself, ifreallocfails, you lose the reference to your pointer and create a memory leak. Instead use atmppointer, e.g.void *tmp = realloc (set, ...); if (tmp) set = tmp;