C Programming, what am I doing wrong? Strtok - c

In the notepad that is saved in the same file as my main.c program is,
ape apple
ball bill bull
foot
parrot peeble
season
zebras zoo
For example, assume that the word “bull” is in the dictionary. The word “bull” contains 1 ‘b’ character, 2 ‘l’ characters, and 1 ‘u’ character. Now say the input letters were “alblldi”. In “alblldi”, we have enough ‘b’ characters for “bull”, since “alblldi” contains at least 1 ‘b’ character. Similarily, “alblldi”, has enough ‘l’ characters for “bull”, since “alblldi” contains at least 2 ‘l’ characters. However, “alblldi” does not have at least 1 ‘u’ character, and as such we know that we cannot make “bull” from “alblldi”.
How do I achieve this?
So I just started to type this code and I need help, so far I got:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE 100
int main( void )
{
int found = 0;
char string[SIZE];
char name[ SIZE ];
FILE *cfPtr;
char word[ SIZE ];
char *tokenPtr; // create char pointer
printf("\nGive me a sentence: ");
fgets( string, SIZE, stdin );
printf("The string to be tokenized is: %s\n", string);
printf("Give me a word: ");
scanf("%s",word);
tokenPtr = strtok( string, "" ); // begin tokenizing sentence
puts("");
// continue tokenizing sentence until tokenPtr becomes NULL
while ( tokenPtr != NULL ) {
if (!strcmp(word,tokenPtr)) {
printf("%s : This is the word you are looking for!\n", tokenPtr);
found = 1;
}
else {
printf( "%s\n", tokenPtr );
}
tokenPtr = strtok( NULL, " " ); // get next token
} // end while
if (!found) {
printf("The word \"%s\" was not found in the sentence\n",word);
}
if ( ( cfPtr = fopen( "dictionary.txt", "r" ) ) == NULL ) {
puts( "File could not be opened" );
}
else {
fgets( name, SIZE, cfPtr );
while ( !feof( cfPtr ) ) {
printf( "Line from file is: %s\n", name );
tokenPtr = strtok( name, "\t" ); // begin tokenizing sentence
// continue tokenizing sentence until tokenPtr becomes NULL
while ( tokenPtr != NULL ) {
printf( "\t%s\n", tokenPtr );
tokenPtr = strtok( NULL, "\t" ); // get next token
} // end while
fgets( name, SIZE, cfPtr );
}
fclose( cfPtr );
}
}

Obviously homework so I'm not doing it for you, but: You can do it on paper well enough to ask a clear question, so just figure out how to implement that in code.
A counter for each letter `int a=0; int b=0; int z=0;... (one variable per letter? there has to be a better way...)
set your counters based on the input word
check if the word you are searching can satisfy all of the counters
There are a couple of easily identified common routines here.

I would do it like so:
#include <string.h>
#include <stdio.h>
int count(char *str, int c) {
int n = 0;
for (size_t i = 0; i < strlen(str); i++) {
if (str[i] == c) {
n++;
}
}
return n;
}
int check_word(int counts[256], char *str) {
if (str == NULL) {
return 0;
}
for (int i = 0; i < 256; i++) {
if (count(str, i) < counts[i]) {
return 0;
}
}
return 1;
}
int check_words(char *word, char **words, size_t n) {
int counts[256] = {0};
for (size_t i = 0; i < strlen(word); i++) {
counts[(int)word[i]]++;
}
int k = 0;
for (size_t i = 0; i < n; i++) {
if (check_word(counts, words[i])) {
printf(">>> %s\n", words[i]);
k++;
} else {
printf(" %s\n", words[i]);
}
}
return k;
}
int main(void) {
char *words[] = {
"bull", "bill", "ball", "bubblel", "babble", "bible",
};
check_words("bull", words, 6);
return 0;
}
I initially build an array containing the count for each character in the initial word, and then for each string in the array, I check whether it contains enough of each.
Running this code gives me the following output, which I expected.
>>> bull
bill
ball
>>> bubblel
babble
bible
meaning that bull matches bull, and bubblel.

Related

how to determine last words of each string?

I have this assignment:
Enter a sequence of sentences from the keyboard into the string array (the end of entering - empty string). Determine the last word of each of these sentences.
The problem is that my program outputs the last word of the last sentence, and I need the last word of each sentence to be output.
Program I have tried:
#include <stdio.h>
#include <string.h>
int main() {
char str[10][100];
int i;
printf("Enter a sequence of sentences:\n");
for (i = 0; i < 10; i++) {
if (*gets(str) == '\0')
break;
}
printf("The last word of each of these sentences is:\n");
for (i = 0; i < 10; i++) {
char *word;
word = strtok(str[i], ".");
while (word != NULL) {
char *last_word = word;
word = strtok(NULL, ".");
}
printf("%s\n", last_word);
}
return 0;
}
The delimiter in this call
word = strtok(str[i], ".");
does not make sense.
It seems you mean
word = strtok(str[i], " \t.");
provided that a sentence can be ended only with a dot and words are separated by spaces or tab characters.
Another problem is that the variable last_word must be declared before the while loop.
For example
char *last_word = NULL;
char *word;
word = strtok(str[i], " \t.");
while (word != NULL) {
last_word = word;
word = strtok(NULL, " \t.");
}
And it is better to use for loop instead of the while loop
char *last_word = NULL;
for ( char *word = strtok(str[i], " \t." );
word != NULL;
word = strtok(NULL, " \t.") )
{
last_word = word;
}
Pay attention to that the function gets is unsafe and is not supported by the C Standard. Instead use standard C function fgets.
And the condition in the second for loop
for(i=0; i<10; i++)
{
char *word;
//...
is incorrect because the user can enter less than 10 sentences.
Without repeating the commentary of the accepted answer provided by #Vlad (kudos!), here is an alternative offering (with comments)
#include <stdio.h>
#include <string.h>
int main( void ) {
// A single large buffer allowing very long lines to be entered.
char buf[ 10 * 100 ], *p = buf;
size_t left = sizeof buf;
int i = 0;
// up to 10 'lines' of input, breaking on an empty line, too
while( i++ < 10 && fgets( p, left, stdin ) && p[0] != '\n' ) {
// typical invocation of strtok() to isolate "words"
// and a "wasteful" copy of each word to the current start of the buffer
for( char *tkn = p; ( tkn = strtok( tkn, " .\n" ) ) != NULL; tkn = NULL )
strcpy( p, tkn );
// having copied the last "word", append '\n' and advance the pointer
size_t len = strlen( p );
p += len;
strcpy( p++, "\n" );
left -= len + 1; // eroding the available size of the buffer
}
printf( "%s", buf ); // a single output of "word1\nword2\nword3\n..."
return 0;
}
NB: strcpy() of overlapping buffers is fraught with hazards. This works in this case, but the practise and its effects must be very well considered before using this technique.

Using strtox for word generator ,

I'm trying to create word generator in C and found Segmentation Fault message.
gdb output :
_GI___strtok_r (
s=0x562d88201188 "some text without comma",
delim=0x562d8820117f " ", save_ptr=0x7f570a47aa68 <olds>) at strtok_r.c:72
code with strtox function :
char **words = malloc(sizeof(char *) * NUM_WORDS);
int num_words = 0;
char *save_ptr;
char *word = strtok(text, " ");
while (word != NULL) {
// Strip leading and trailing whitespace
while (isspace(*word)) {
word++;
}
int len = strlen(word);
while (len > 0 && isspace(word[len - 1])) {
len--;
}
// Allocate memory for the word and copy it using strdup()
words[num_words] = strdup(word);
// Move to the next word
num_words++;
word = strtok(NULL, " ");
}
how to use function with an indeterminate number of words in text?
Can't believe someone finally asked for this!
You may want to add verification that realloc() hasn't returned a NULL.
In brief, the string is chopped on the delimiters provided to strtok() while realloc() is used to grow an array of pointers to each of those segments.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char buf[] = "Once upon a time there lived a beautiful princess.", *p = buf;
char **t = NULL; size_t sz = sizeof *t;
int n = 0;
while(!!(t=realloc(t,(n+1)*sz))&&!!(t[n]=strtok(p," .\n"))) p=NULL, n++;
for( int i = 0; i < n; i++ )
puts( t[i] );
free( t );
return 0;
}
Once
upon
a
time
there
lived
a
beautiful
princess
EDIT
Then there is the extension that can handle multiple input lines:
int main() {
char *buf[] = { "Once upon a time\n", "there lived\n", " a beautiful princess.\n" };
char **t = NULL; size_t sz = sizeof *t;
int n = 0;
for( int ln = 0; ln < sizeof buf/sizeof buf[0]; ln++ ) {
char *p = buf[ln];
while(!!(t=realloc(t,(n+1)*sz))&&!!(t[n]=strtok(p," .\n"))) p=NULL, n++;
}
for( int i = 0; i < n; i++ )
puts( t[i] );
free( t );
return 0;
}
/* Output same as shown above */
Put the strtok() as the parameter to strdup() and you've got yourself something that will preserve words while using a single line input buffer.

How to take words from stdin, and put them into array to sort later?

How can I take words from STDIN, then put them into an array I can sort later? this is the code I have for taking in STDIN.
printf("Please enter words to sort:\n");
char *line = NULL;
size_t len = 0;
ssize_t lineSize = 0;
lineSize = getline(&line, &len, stdin);
printf("You entered: %swhich has %zu chars.\n", line, lineSize - 1);
free(line);
return 0;
In order to sort the words, I recommend that you create an array of char *, in which every element of the array points to a word.
In order to find the start of the words and to make the words properly terminated by a null character, I recommend that you use the function strtok or strtok_r.
Here is an example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_WORDS 100
//custom compare function for the function "qsort" which does
//nothing else than call the function "strcmp" for comparison
//purposes
int my_compare( const void *a, const void *b )
{
return strcmp( *(const char**)a, *(const char**)b );
}
int main( void )
{
char *words[MAX_WORDS];
int num_words = 0;
char *line = NULL, *p;
size_t len = 0;
ssize_t lineSize = 0;
//prompt user for input
printf( "Please enter words to sort:\n" );
//read one line of input
lineSize = getline( &line, &len, stdin );
if ( lineSize <= 0 )
{
fprintf( stderr, "Input error!\n" );
exit( EXIT_FAILURE );
}
//remove newline character, if it exists
line[strcspn(line,"\n")] = '\0';
//find first word
p = strtok( line, " " );
//loop until no more words are found, processing one word
//per loop iteration
while ( p != NULL )
{
//verify that we are not overflowing the array
if ( num_words == MAX_WORDS )
{
fprintf( stderr, "Too many words for array!\n" );
exit( EXIT_FAILURE );
}
//add pointer to found word to the "words" array
words[num_words++] = p;
//find next word for next loop iteration
p = strtok( NULL, " " );
}
//now we can sort the array
qsort( words, num_words, sizeof *words, my_compare );
//print the sorted words
for ( int i = 0; i < num_words; i++ )
{
printf( "%s\n", words[i] );
}
//cleanup
free( line );
}
For the input
apple orange banana dog cat
this program has the following output:
apple
banana
cat
dog
orange
As you can see, the words were properly sorted.
How to take words from stdin, and put them into array to sort later?
Properly read a line into a string, parse the string for words and save the words in a master linked list. No need for a WORDS_MAX restriction.
After all lines read, allocate for the required string pointer array based on linked-list length.
Move the string pointers from the link-list to the array. Delete the linked-list.
Small issue. Properly use/print ssize_t. ssize_t has no specified matching print specifier. - 1 not needed.
// ssize_t lineSize = 0;
// lineSize = getline(&line, &len, stdin);
// printf("You entered: %swhich has %zu chars.\n", line, lineSize - 1);
ssize_t number_of_characters_read = getline(&line, &len, stdin);
if (number_of_characters_read < 0) {
Handle_error();
} else {
printf("You entered: \"%s\" which has length %lld.\n",
line, (long long) number_of_characters_read);
}

Strlwr function - getting an error in xcode 9.2

I'm trying to convert a string from upper case to lower case to check if it is a palindrome, however I keep getting the error:
"function declaration is not a prototype"
I already added #include <string.h> in the header, but it still doesn't work. How do I get around this issue?
This is the code:
int main (void)
{
char *user_string, *user_string_rev;
/* the malloc function is used to make sure that enough memory is allocated for the string and that it does not overwrite memory boxes of other variables. */
user_string= (char*)malloc(BUFF_SIZE*sizeof(char));
user_string_rev= (char*)malloc(BUFF_SIZE*sizeof(char));
printf("Please enter a string:");
fgets(user_string,BUFF_SIZE, stdin); /* fgets function take the string the user inputs and stores it into user_string. */
user_string_rev=strcpy(user_string_rev, user_string); /*the strcpy takes the string the user inputs and copies it to user_string_rev. */
strlwr(user_string_rev);
palindrome_check(user_string,user_string_rev); /*this is the palindrome function used to check if the two strings are palindromes, it intakes two arguments, the two strings and does not return anything. */
return 0;
}
Replace :
strlwr(user_string_rev);
which is not a standard function with:
int i = 0;
while (user_string_rev[i])
{
if (isalpha(user_string_rev[i]))
user_string_rev[i] |= 32;
++i;
}
Don't forget to add the ctype header at the top of your .c file to use isalpha:
#include <ctype.h>
the following proposed code:
incorporates the comments to the question
cleanly compiles
properly checks for errors
will treat a string that is nothing but a newline as NOT a palindrome
And now the proposed code:
#include <stdio.h> // getline(), printf()
#include <stdlib.h> // free()
#include <ctype.h> // tolower()
#include <string.h> // strlen(), strchr()
// prototypes
void palindrome( char *, size_t length );
int main( void )
{
char *inputStr = NULL;
size_t lengthStr = 0;
printf("Please enter a string:");
if( -1 != getline( &inputStr, &lengthStr, stdin ) )
{
size_t length = strlen( inputStr );
for( size_t i = 0; i < length; i++ )
{
inputStr[i] = (char)tolower( inputStr[i] );
}
char *newline = strchr( inputStr, '\n' );
if( newline )
{
*newline = '\0';
length--;
}
palindrome( inputStr, length );
}
free( inputStr );
return 0;
}
void palindrome( char stringToCheck[], size_t length )
{
size_t index = length - 1; // don't check NUL terminator byte
size_t i;
for( i = 0; i < index; i++ )
{
if( stringToCheck[i] != stringToCheck[ index ] )
{
break;
}
index--;
}
if( i < index )
{
printf( "%s is not a palindrome\n", stringToCheck );
}
else
{
printf( "%s is a palindrome\n", stringToCheck );
}
}

Strange behaviour using fgets and strtok_r

This is my code:
#define LEN 40
#define STUDLIST "./students.txt"
int main()
{
FILE * studd;
char del[] = "" " '\n'";
char name[LEN], surname[LEN], str[LEN];
char *ret;
char *tokens[2] = {NULL};
char *pToken = str;
unsigned int i = 0;
/* open file */
if ( (studd = fopen(STUDLIST,"r") ) == NULL )
{
fprintf(stderr, "fopen\n");
exit(EXIT_FAILURE);
}
while((ret = fgets(str, LEN, studd)))
{
if(ret)
{
for( tokens[i] = strtok_r( str, del, &pToken ); ++i < 2;
tokens[i] = strtok_r( NULL, del, &pToken ) );
strcpy(name, tokens[0]);
strcpy(surname, tokens[1]);
printf( "name = %s\n", name );
printf( "surname = %s\n", surname );
}
fflush(studd);
}
fclose(studd);
return 0;
}
Here there is the file students.txt: http://pastebin.com/wNpmXYis
I don't understand why the output isn't correct as I expected.
I use a loop to read each line with fgets, then I have a sting composed by [Name Surname], and I want to divide it in two different strings ([name] and [surname]) using strtok_r. I tried with a static string and it works well, but If I read many strings from FILE the output is not correct as you can see here:
http://pastebin.com/70uPMzPh
Where is my fault?
Why are you using forloop?
...
while((ret = fgets(str, LEN, studd)))
{
if(ret)
{
tokens[0] = strtok_r( str, del, &pToken );
tokens[1] = strtok_r( NULL, del, &pToken );
strcpy(name, tokens[0]);
strcpy(surname, tokens[1]);
printf( "name = %s\n", name );
printf( "surname = %s\n", surname );
}
}
You start i at zero:
unsigned int i = 0;
And later you increment it:
++i < 2;
You never set i back to zero, and in fact, continue incrementing i again for every new line in your file. With 14 names in your input file, I expect i to get to about 14.(or maybe 13 or 15, depending on the exact logic).
So this line:
tokens[i] = strtok_r(...);
ends up putting strtok results into tokens[2..15]. But only tokens[0] and tokens[1] are valid. Everything else is undefined behavior.
Answer: Be sure you reset i to zero when you read a new line of your file.

Resources