You have two primary challenges in your question:
- separating the space-separated word read into
input; and
- storage for each word.
While there are may ways to "tokenize" (separate) input, when wanting space-separated words, a very simple way to do that is to just read with fgets() to fill input (as you have done) and then simply loop over each word in input using sscanf() with the %s conversion specifier (with a proper field-width modifier to protect your array bounds) and using the %n pseudo-conversion specifier to capture the number of character read on each call to sscanf() so you can capture the next word by providing an offset from the beginning of input.
Using multiple character arrays to hold each word quickly becomes unwieldy (as I suspect you have found). What if you don't know the number of words you are going to read?
Since you emphasize using a "simple" approach, by far the simplest is to use a 2D array of characters where each row holds a word. Now you can simply reference each word by the index for the 2D array (a 2D array actually being a 1D "array-of-arrays" in C - so the first index points to the 1st array, and so on). Here you are limited to reading no more than your rows number of words -- but with a reasonable number of rows set, that provides a great deal of flexibility. You must remember to check each time you add a word against the number of rows you have so you don't attempt to add more words to your 2D array than you have rows for.
A slightly more complex approach would be to declare a pointer-to-array of characters which would allow you to reallocate storage for more words with the only limit being the amount of memory your computer has. (a pointer-to-array allocation also has the benefit of a single-free)
One step further would be to allocate the exact number of characters needed to hold each word and the exact number of pointers needed to keep track of each word in your collection -- but that gets well beyond your "simple" request. Just know there are more flexible ways you will learn in the future.
What Is This Simple Approach?
Before looking at the code, let's think through what you want to do. You will need to:
- Prompt the user and read the words into
input using fgets()
- Loop checking that you still have a row available to hold the next word; and
- Pass
input plus an offset to sscanf()
- separating the next word with
"%s" (with appropriate field-width modifier) to capture the word (you can use a temporary array to hold the separated word and copy to your array, or you can attempt the read directly into your 2D array providing an index); and
- saving the number of characters
sscanf() read to process that word with "%n" so you add that to the offset within input to read the next word on your next call to sscanf().
- You ALWAYS validate that
sscanf() (or any function) succeeds before going further and handle any error that may arise,
- Increment the word count (
nwords) after successfully adding the word to your 2D array of words; and
- Add the number of characters used by
sscanf() to an offset variable so you are ready to process the next word.
- After your loop with
sscanf() ends, you simply loop nwords times outputting each word in the format you desire.
A short bit of code that does that could be:
#include <stdio.h>
#include <string.h>
#define MAXWRDS 64
#define WORDLN 64
#define MAXCHR 1024
int main (void) {
char input[MAXCHR] = "", /* storage for line of input */
words[MAXWRDS][WORDLN] = {""}, /* 2D array of MAXWRDS WORDLN words */
word[WORDLN] = ""; /* temporary storage for each word */
size_t nwords = 0; /* number of words (tokens) read */
int offset = 0,
nchars = 0;
fputs ("input: ", stdout); /* prompt */
/* validate EVERY input */
if (fgets (input, sizeof input, stdin) == NULL) {
return 1;
}
/* Loop over every whitespace separated sequence
* of chars reading into word. Use sscanf() to read
* whitespace separated sequences of chars. Use %n to
* get the number of characters processed in each call to
* sscanf() to provide offset to next word in input.
*
* Do NOT forget field-width modifier to protect word array bounds
* for reading into word and check you read no more than MAXWRDS words.
*/
while (nwords < MAXWRDS &&
sscanf (input + offset, "%63s%n", word, &nchars) == 1) {
strcpy (words[nwords], word); /* copy word to array at nwords index */
nwords += 1; /* increment nwords */
offset += nchars; /* increment offset by no. of chars */
}
putchar ('\n'); /* optional newline before order output */
/* loop over each word stored in words outputting order */
for (size_t i = 0; i < nwords; i++) {
printf ("order %2zu: %s\n", i + 1, words[i]);
}
}
Using a #define up top for each constant you need provides a convenient place to make a single change should you need to adjust how your code behaves later.
Example Use/Output
Compiling the code (ALWAYS with full-compiler-warnings-enabled), your code will now do what you want. With the code compiled to the file named sscanfwordsinput2d, you can do:
$ ./sscanfwordsinput2d
input: my dog has fleas but my cat has none -- lucky cat!
order 1: my
order 2: dog
order 3: has
order 4: fleas
order 5: but
order 6: my
order 7: cat
order 8: has
order 9: none
order 10: --
order 11: lucky
order 12: cat!
If you are using gcc / clang, a good compile string for the code, with full-warnings, would be:
$ gcc -Wall -Wextra -pedantic -Wshadow -Werror -std=c11 -O2 -o sscanfwordsinput2d sscanfwordsinput2d.c
If using Microsoft cl.exe as your compiler (VS, etc..), then a roughly equivalent compile string would be:
$ cl /W3 /wd4996 /Wx /O2 /Fesscanfwordsinput2d /Tcsscanfwordsinput2d.c
Looks things over and let me know if you have questions.
sizeof(buffer)as the size argument tofgets(buffer, sizeof(buffer), fp)is perfectly safe. Don't provide an array of 1 byte; you'll achieve nothing useful. And the buffer needs to be a local or global array, not a function parameter.strtok()to the input string, in a loop.