Reputation: 11
I am trying to create a program that ask the user to input a sentence and then takes that sentence and puts it in a list. Then the user should be able to search that list for words they already entered, add a new word to the list and get a updated alphabetical list. I feel like the last two parts will not be too taxing. The problem I am having is when I try to create and print the list to the console nothing is coming out.
This is the code I have so far.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define WORD1 256
#define WORD2 256
void word_swap(char** w1, char** w2){return 0;};
int main(int argc, char **argv)
{
int i, j, ans, count, k=0, l=0, swapped=0;
char firstSentence[WORD1][WORD2];
char ch;
char* sentence;
puts ("Could you please type a sentence:");
gets (firstSentence);
puts("\nYour sentence has been saved.");
puts("\n******************************");
puts("\nWhat would you like to do now?");
puts("\n\n1) Read your sentence.");
puts("2) See a list of words in your sentence.");
puts("3) Add a word to your sentencene list.");
puts("4) Search for a word in your sentence list.");
puts("5) Exit the program.");
do
{
puts("\nType your response:");
scanf("%d", &ans);
printf("\n\n");
switch (ans){
case(1):
puts(firstSentence);
break;
case(2):
for (i=0; i<WORD1*WORD2; i++) {
if (*(sentence+i) == '\0') {
firstSentence[k][l] = '\0';
count = k+1;
break;
}
if (*(sentence+i) != ' ') {
firstSentence[k][l] = *(sentence+i);
l++;
}
else {
firstSentence[k][l] = '\0';
k++;
l=0;
}
do {
for (i=0; i<count-1; i++) {
if (strcmp(firstSentence[i], firstSentence[i+1]) > 0) {
word_swap(&firstSentence[i], &firstSentence[i+1]);
swapped = 1;
break;
} else swapped = 0;
}
} while (swapped != 0);
for (i=0; i<count; i++){
printf("%s\n", firstSentence[i]);
}
}
case(3):/* puts("Please enter a new word.");
scanf("%c", &words);
break;
puts("\n\nWould you like to see your new word list now?");
puts("Please enter 'Y' or 'N'");
gets(ch);
if (strcmp(ch, toupper(ch))>= 1){
puts(sentence);
break;
}*/
case(4):
case(5): exit(1);
}
}while ((ans < 1) || (ans > 5));
system("pause");
return 0;
}
The problem is in the case(2) section but I included the full code just in case there is something in there I am missing. Case(1) works fine and case(3) was me getting ahead of myself because I can't really add a word to a list that I haven't created (or is it created and the problem is I can't see it in the console???). When I build and press 2 after the menu it drops 2 empty lines and does not take anymore input nor does it print anything out nor does the 'press any key to continue' prompt come up.
Side note, I am very new to coding this is my 3rd day working on C and any help would be appreciated.
Upvotes: 1
Views: 199
Reputation: 84642
OK, it's obvious, you are quite lost. Continuing from my comment above, let's start with what variables your program needs. (you can do this any number of ways, this is just one). You need a character array (buffer) of sufficient size to hold your sentence
. This is where your WORD1*WORD2
(65K) size comes in. If you allow a maximum of WORDS1
words in your sentence and a maximum of WORDS2
characters in each word in the sentence, then you will need WORD1*WORD2+1
characters to ensure the max number of max sized words fits (the +1 is for the nul-terminating character (which you can safely omit in this case as the WORDS2
word length is way overkill as the longest word in the Unabridged Dictionary (non-medical) is only 29-characters
))
So you can declare char sentence[WORD1*WORD2];
and declare a second array to hold a copy, e.g. char copy[WORD1*WORD2];
because we will use strtok
to separate the sentence into individual words (and strtok
modifies the string it operates on -- so make a copy if you need to preserve the original -- and you do). Your 2D array for storing the separated words char firstSentence[WORD1][WORD2];
is fine, but WORDS2
is still overkill for the same reason -- but fine for now.
So the basic approach is read your sentence into sentence
and then remove the trailing '\n'
by overwriting the '\n'
with the '\0'
character (0
is equivalent, See ASCII Table and Description. Then simply make a copy of sentence
in the equal size array copy
and then use strtok
to separate the individual words in copy
(using delimiters of " \t\n"
(space, tab, newline)) and copy the individual words to the appropriate row in firstSentence
. That process can be:
int main (void) /* you don't take any arguments, specify (void) */
{
int i, ans, k=0, ch;
char sentence[WORD1*WORD2]; /* 65K char array */
char copy[WORD1*WORD2]; /* copy to use w/strtok */
char firstSentence[WORD1][WORD2]; /* 256x256 array of char */
puts ("Could you please type a sentence:");
if (!fgets (sentence, WORD1, stdin)) { /* read w/fgets & validate */
fputs ("error: user canceled input.\n", stderr);
return 1;
}
sentence[strcspn (sentence, "\n")] = 0; /* trim trailing '\n' */
strcpy (copy, sentence); /* copy sentence - strtok modifies string */
/* tokenize individual words into firstSentence[0...WORD1-1] */
for (char *p = strtok(copy," \t\n"); p && k < WORD1; p = strtok (NULL, " \t\n"))
strcpy (firstSentence[k++], p);
puts ("\nYour sentence has been saved.\n");
...
With your sentence read and separated into individual words, it's time to display your menu and take the users choice (note: you must display the menu *within the loop, otherwise after it is displayed once and the user is left wondering what to do). For example:
do
{ /* you need to display menu within loop */
puts ("\n******************************\n" /* you only need 1 puts */
"What would you like to do now?\n\n"
" 1) Read your sentence.\n"
" 2) See a list of words in your sentence.\n"
" 3) Add a word to your sentencene list.\n"
" 4) Search for a word in your sentence list.\n"
" 5) Exit the program.\n\n"
"Type your response:");
if (scanf ("%d", &ans) != 1) { /* validate EVERY input */
fputs ("error: invalid integer input.\n", stderr);
exit (EXIT_FAILURE);
}
printf("\n\n");
...
Now on to your switch()
statement that can be simplified quite a bit from your first attempt. For example to display the sentence, all you need do is puts (sentence);
, e.g.
switch (ans) {
case(1):
puts (sentence); /* buffer contains \n */
break;
...
Listing the words simply requires looping over the filled elements of firstSentence
. That can be done like:
case(2):
for (i = 0; i < k; i++)
puts (firstSentence[i]); /* output word in sentence */
break;
...
Your case 3:
that is currently commented, isn't that difficult, but does have a few caveats given your choice of mixing string and character input. That is doable, but all input is better read with fgets
and then parse the resulting buffer to get the values you need. The largest benefit is that a line-of-input at-a-time is consumed and you don't have to worry about what remains in stdin
messing up your next attempted read. But we will do it the hard way similar to what you had.
The basic approach is read the word into the next element of firstSentence
. scanf
is used below with the "%s"
conversion specifier which stops reading when it encounters the first whitespace (and a '\n'
is considered whitespace). Since scanf
stop reading -- it also stops extracting characters from stdin
leaving the '\n'
in stdin
unread -- just waiting to bite you when you attempt to read a single-character for your Y/N
test.
Thankfully that is solvable by simply reading from stdin
with getchar()
until a '\n'
or EOF
is encountered. So if there are extraneous character you need to discard from stdin
, just loop with getchar()
until one of those conditions is reached. A handy helper-function called empty_stdin
can be written to do this for you. At the top of the source file, I have included:
/* function to empty stdin of all chars */
void empty_stdin (void)
{
int c = getchar();
while (c != '\n' && c != EOF)
c = getchar();
}
That help with your case 3:
to keep things tidy when you need to empty stdin
, e.g.
case(3):
puts("Please enter a new word.");
if (scanf("%255s", firstSentence[k]) == 1) {
strcat (sentence, " ");
strcat (sentence, firstSentence[k]);
k++;
empty_stdin(); /* remove chars from stdin */
puts ("\n\nWould you like to see your new word list now?");
puts ("Please enter 'Y' or 'N'");
ch = getchar(); /* ch must be type int */
empty_stdin(); /* remove chars from stdin */
if (toupper(ch) == 'Y')
for (i = 0; i < k; i++)
puts (firstSentence[i]);
}
break;
(note: if using scanf
to fill a character array, always provide the field-width modifier (of 1-less than the array size) to protect against writing beyond the end of your array if the string you are reading is larger than the number of characters available)
Your case 4:
isn't provided, and currently falls-through to case 5:
(no break;
in 4 -- falls through to case 5:
) where 5 calls exit(1);
-- exit(0);
would be better as returning 1
to your shell generally indicates error.
You should consider adding a default:
case to handle integer values outside your menu range, for example:
case(4):
case(5): exit(1);
default:
fputs ("error: invalid entry.\n", stderr);
break;
}
} while (ans != 5);
(note: also the loop continues as long as the user has not entered 5
to exit -- which you can replace with while(1);
as you use case 5:
to break the loop and exit.
Putting it altogether and adding a simple check so those on Linux do not reach the system("pause");
code presumably used to hold your terminal window open on Windows (which isn't really needed in this code anyway), you could do something like:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h> /* for toupper() */
#define WORD1 256
#define WORD2 WORD1
/* function to empty stdin of all chars */
void empty_stdin (void)
{
int c = getchar();
while (c != '\n' && c != EOF)
c = getchar();
}
int main (void) /* you don't take any arguments, specify (void) */
{
int i, ans, k=0, ch;
char sentence[WORD1*WORD2]; /* 65K char array */
char copy[WORD1*WORD2]; /* copy to use w/strtok */
char firstSentence[WORD1][WORD2]; /* 256x256 array of char */
puts ("Could you please type a sentence:");
if (!fgets (sentence, WORD1, stdin)) { /* read w/fgets & validate */
fputs ("error: user canceled input.\n", stderr);
return 1;
}
sentence[strcspn (sentence, "\n")] = 0; /* trim trailing '\n' */
strcpy (copy, sentence); /* copy sentence - strtok modifies string */
/* tokenize individual words into firstSentence[0...WORD1-1] */
for (char *p = strtok(copy," \t\n"); p && k < WORD1; p = strtok (NULL, " \t\n"))
strcpy (firstSentence[k++], p);
puts ("\nYour sentence has been saved.\n");
do
{ /* you need to display menu within loop */
puts ("\n******************************\n" /* you only need 1 puts */
"What would you like to do now?\n\n"
" 1) Read your sentence.\n"
" 2) See a list of words in your sentence.\n"
" 3) Add a word to your sentencene list.\n"
" 4) Search for a word in your sentence list.\n"
" 5) Exit the program.\n\n"
"Type your response:");
if (scanf ("%d", &ans) != 1) { /* validate EVERY input */
fputs ("error: invalid integer input.\n", stderr);
exit (EXIT_FAILURE);
}
printf("\n\n");
switch (ans) {
case(1):
puts (sentence); /* buffer contains \n */
break;
case(2):
for (i = 0; i < k; i++)
puts (firstSentence[i]); /* output word in sentence */
break;
case(3):
puts("Please enter a new word.");
if (scanf("%255s", firstSentence[k]) == 1) {
strcat (sentence, " ");
strcat (sentence, firstSentence[k]);
k++;
empty_stdin(); /* remove chars from stdin */
puts ("\n\nWould you like to see your new word list now?");
puts ("Please enter 'Y' or 'N'");
ch = getchar(); /* ch must be type int */
empty_stdin(); /* remove chars from stdin */
if (toupper(ch) == 'Y')
for (i = 0; i < k; i++)
puts (firstSentence[i]);
}
break;
case(4):
case(5): exit(1);
default:
fputs ("error: invalid entry.\n", stderr);
break;
}
} while (ans != 5);
#if defined (_WIN32) || defined (_WIN64)
system("pause");
#endif
return 0;
}
Example Use/Output
An example user sessions with your code could be similar to the following that exercises all case
statements in your switch()
(except for case 4:
-- boring...)
$ ./bin/readsentenceintowords
Could you please type a sentence:
My dog has fleas
Your sentence has been saved.
******************************
What would you like to do now?
1) Read your sentence.
2) See a list of words in your sentence.
3) Add a word to your sentencene list.
4) Search for a word in your sentence list.
5) Exit the program.
Type your response:
1
My dog has fleas
******************************
What would you like to do now?
1) Read your sentence.
2) See a list of words in your sentence.
3) Add a word to your sentencene list.
4) Search for a word in your sentence list.
5) Exit the program.
Type your response:
2
My
dog
has
fleas
******************************
What would you like to do now?
1) Read your sentence.
2) See a list of words in your sentence.
3) Add a word to your sentencene list.
4) Search for a word in your sentence list.
5) Exit the program.
Type your response:
3
Please enter a new word.
--bummer
Would you like to see your new word list now?
Please enter 'Y' or 'N'
y
My
dog
has
fleas
--bummer
******************************
What would you like to do now?
1) Read your sentence.
2) See a list of words in your sentence.
3) Add a word to your sentencene list.
4) Search for a word in your sentence list.
5) Exit the program.
Type your response:
1
My dog has fleas --bummer
******************************
What would you like to do now?
1) Read your sentence.
2) See a list of words in your sentence.
3) Add a word to your sentencene list.
4) Search for a word in your sentence list.
5) Exit the program.
Type your response:
5
Look things over and let me know where you have questions. You were way out in left-field on some of the topics, so it is likely you will have one or two questions about what was done and why? I'm happy to help further.
Upvotes: 1