Reputation: 29
I am not understanding why, when I am doing sub=strtok(NULL,delim);
, instead of going to the next word, it is making it null. Please try this code and help me resolve the problem.
#include <stdio.h>
#include <string.h>
int main()
{
char str[100],str1[100],*sub,*sub1;
int c1;
printf("\nEnter the string or sentence: ");
scanf("%[^\n]%*c",str);
strcpy(str1,str);
char delim[]=" ";
sub=strtok(str,delim);
while(sub !=NULL)
{
c1=0;
sub1=strtok(str1,delim);
while(sub1 !=NULL)
{
if(!strcmp(sub,sub1))
{
c1++;
}
sub1=strtok(NULL,delim);
}
printf("\n%s : %d",sub,c1);
sub=strtok(NULL,delim);
}
return 0;
}
Upvotes: 1
Views: 363
Reputation: 598309
You can't parse multiple string buffers concurrently with strtok()
, like you are trying to do. Internally, strtok()
maintains a static reference to the input string, that is how it knows which string to advance through when subsequent calls specify a NULL
string pointer.
Before entering your outer loop, you call strtok(str)
to set the internal reference to str
. Then, inside the loop, you call strtok(str1)
to reset that reference to str1
. So, on the 1st iteration of your outer loop, before entering the inner loop, strtok()
has already lost its reference to your str
buffer since you replace it with the str1
buffer. Then, after the inner loop has finished scanning str1
, your outer loop breaks when calling sub=strtok(NULL,delim);
because there are no more tokens to read from str1
.
For what you are attempting, use strtok_r()
instead:
The
strtok_r()
function is a reentrant versionstrtok()
. Thesaveptr
argument is a pointer to achar *
variable that is used internally bystrtok_r()
in order to maintain context between successive calls that parse the same string....
Different strings may be parsed concurrently using sequences of calls to
strtok_r()
that specify differentsaveptr
arguments.
Also, because strtok(_r)()
is destructive to the input string, inserting '\0'
after each token found, you need to reset the contents of your 2nd string buffer back to the original string before entering the inner loop. Otherwise, the inner loop will stop scanning after is reads the 1st word in your 2nd string buffer.
Try something more like this:
#include <stdio.h>
#include <string.h>
int main()
{
char orig[100], str1[100], str2[100], *sub1, *sub2, *save1, *save2;
char delim[] = " ";
int c1;
printf("\nEnter the string or sentence: ");
scanf("%[^\n]%*c", orig);
strcpy(str1, orig);
sub1 = strtok_r(str1, delim, &save1);
while (sub1 != NULL)
{
c1 = 0;
strcpy(str2, orig);
sub2 = strtok_r(str2, delim, &save2);
while (sub2 != NULL)
{
if (strcmp(sub1, sub2) == 0)
{
++c1;
}
sub2 = strtok_r(NULL, delim, &save2);
}
printf("\n%s : %d", sub1, c1);
sub1 = strtok_r(NULL, delim, &save1);
}
return 0;
}
Otherwise, you can use a single loop through a single string buffer, storing the word counts in a separate array, eg:
#include <stdio.h>
#include <string.h>
typedef struct _wordInfo
{
char* str;
int count;
} wordInfo;
int main()
{
char str[100], *sub;
char delim[] = " ";
wordInfo words[100], *word;
int numWords = 0;
printf("\nEnter the string or sentence: ");
scanf("%[^\n]%*c", str);
sub = strtok(str, delim);
while (sub != NULL)
{
word = NULL;
for (int i = 0; i < numWords; ++i)
{
if (strcmp(sub, words[i].str) == 0)
{
word = &words[i];
break;
}
}
if (!word)
{
if (numWords == 100) break;
word = &words[numWords++];
word->str = sub;
word->count = 1;
}
else {
word->count++;
}
sub = strtok(NULL, delim);
}
for(int i = 0; i < numWords; ++i)
{
word = &words[i];
printf("\n%s : %d", word->str, word->count);
}
return 0;
}
Upvotes: 1