C: counting number of words (need help fixing) - c

I am new to C programming and trying to write a code for counting the number of words in a string.Here is my code for counting the number of codes.
#include<stdio.h>
#include<string.h>
void main()
{
int count=0,i,len;
char str[100];
printf("enter the sentence");
gets(str);
len=strlen(str);
for(i=0;i<=len;i++)
{
if(str[i]==' ')
count++;
}
printf("the number of words are :\t%d",count+1);
}
When my input is:Here is four words it works fine. it gives output
the number of words are : 4
My question is how do I handle "two consecutive spaces" between the word, "space at the beginning" of the input and "space at the last" of the input.

Instead of counting spaces, count the first non-space character of each word.
#include<stdio.h>
int main()
{
int count=0;
char str[100];
printf("enter the sentence");
gets(str);
char *cur= str;
for (;;)
{
while (*cur == ' ')
{
cur++;
}
if (*cur == 0)
{
break;
}
count++;
while (*cur != 0 && *cur != ' ')
{
cur++;
}
}
printf("the number of words are :\t%d",count);
return 0;
}

You can use:
while(str[i]==' '&&str[i]!=EOF)
{
count++;
i++;
}
instead of your if part. You also need to add these code before the for loop to read the beginning spaces.

I think the loop in the current form may not work properly,
It should be as follows,
for(i=0;i<len;i++)
{
if(i!=0)
{
if(str[i]==' ')
count++;
}
}
To check the other criteria change the code as follows,
for(i=0;i<len;i++)
{
if(str[i]==' ')
{
if(i!=0)
{
if(str[i+1]!=' ')
{
count++;
}
}
}

Just ignore spaces at the beginning and spaces directly after other spaces, and +1 if there are no spaces at the last.
#include <stdio.h>
#include <string.h>
// #include <stdlib.h>
int main() // void main is a bad practice
{
int count = 0, i, len, ignoreSpace;
char str[100];
printf("enter the sentence\n");
gets(str);
len = strlen(str);
ignoreSpace = 1; // handle space at the beginning
for(i = 0; i < len; i++) // not i<=len
{
if(str[i] == ' '){
if(!ignoreSpace){
count++;
ignoreSpace = 1; // handle two or more consecutive spaces
}
}else{
ignoreSpace = 0;
}
}
if( !ignoreSpace ) // handle space at the last
count++;
printf("the number of words are :\t%d\n", count); // +1 is moved to previous line
// system("pause");
return 0;
}

use strtok and first call of strtok use strtok(string," ") and for rest of calls use strtok(NULL, " \n")

You should count the transitions from space to non-space characters + a possible non-space character in the beginning itself.
#include<stdio.h>
#include<string.h>
int main()
{
int count=0,i,len, cur_is_spc;
char str[100];
printf("enter the sentence");
gets(str);
len=strlen(str);
cur_is_spc = 0; // 0, if current character is not space. 1, if it is.
for(i=0; str[i]!='\0'; i++)
{
if(str[i] != ' ')
{
switch(cur_is_spc) // currently holding value for previous character
{
case 0: count++; break; //count the spc->non-spc transitions
case 1: break;
default: cout << "Erroneous value"; exit(1);
}
cur_is_spc = 1; //updated for current character.
}
else
{
cur_is_spc = 0; //updated for current character.
}
}
printf("the number of words are :\t%d",count+1);
return 0;
}
Here, I am checking with only spaces. But there can be characters like newline, tab etc. How would your code handle them? Hint: use isspace() function.
/moreover, the transition can be done from non-alphabet characters to alphabet characters if you decide that words are made up of alphabets only. This approach is inherently flexible to suit your needs.

One quick way to do this is use strtok and break everything according to a predicate. This function satisfy all your requirements.
#include<stdio.h>
#include<string.h>
int countSpace(char* str){
int counter = 0;
char * newString;
newString= strtok (str, " "); // now the newString has the str except first word
while (newString != NULL){
counter++; // Put counter here to ignore the newString == NULL
// Or just -1 from the counter on main()
newString= strtok (NULL, " "); //Break the str in to words seperated by spaces
}
return counter;
}
void main(){
int count=0,i,len;
char str[100];
printf("Enter the sentence:\n");
fgets (str , 100 , stdin);
count = countSpace(str);
printf("The number of words are :\t%d\n",count);
return 0;
}
Thank you

Why not use strtok and bypass it altogether:
int main()
{
int num_words = 0;
char str_one[] = "This string has a trailing space ";
char str_two[] = " This string has a preceeding space";
char str_three[] = "This string contains two spaces consecutively twice!";
char delim[] = " ";
char *ret;
/* fgets() for user input as desired... */
if (( ret = strtok(str_one, delim)) != NULL )
{
while ( ret )
{
num_words++;
ret = strtok(NULL, delim);
}
}
else
{
/* no spaces, but might contain a word if the string isn't empty */
if ( str_one[0] != '\0' )
num_words = 1;
}
printf("str_one contains %i words\n", num_words);
num_words = 0;
...
return 0;
}
And by the way: main should ALWAYS return!!!

Related

how to change a word in a string by its number?

I have this assignment:
Replace the numbered word in the sentence with three characters: ???
The problem is I can't replace the whole word by its number, my program changes only 3 first characters.
Here is my code:
#include <stdio.h>
#include <string.h>
int main() {
char sentence[100];
int word_number;
int pos;
int i;
printf("Enter sentence: ");
fgets(sentence, 100, stdin);
printf("Enter word number: ");
scanf("%d", &word_number);
pos = 0;
for (i = 0; i < strlen(sentence); i++) {
if (sentence[i] == ' ') {
word_number--;
}
if (word_number == 1) {
pos = i;
break;
}
}
// Update the sentence
sentence[pos] = '?';
sentence[pos + 1] = '?';
sentence[pos + 2] = '?';
printf("Result sentence: %s\n", sentence);
return 0;
}
There are multiple issues in the code:
Your approach only works if the word to be replaced has exactly 3 letters. For longer or shorter words, you need to move the contents of the remainder of the string.
Another restriction in your code is you assume that words a separated by a single space, which may of may not be explicitly stated in the assignment.
Similarly, you assume the n-th word is followed by a space, which may not be the case if the word is the last one in the sentence.
you should check the return values of fgets() and scanf() to detect invalid or missing input.
Here is a modified version.
#include <stdio.h>
#include <string.h>
int is_sep(char cc) {
// separators are space, newline and the null byte
return (cc == ' ' || cc == '\n' || cc == '\0');
// you could also accept punctuation as word separators:
//return strchr(" \t\n.,:;?!'`"##$%^&*()[]{}<>/`~+=|", cc);
}
int main() {
char sentence[200];
int word_number;
printf("Enter sentence: ");
// read a sentence, allow for 2 extra bytes to insert replacement
if (!fgets(sentence, sizeof(sentence) - 2, stdin))
return 1;
printf("Enter word number: ");
if (scanf("%d", &word_number) != 1)
return 1;
int len = strlen(sentence);
int start = 0;
int wn = 1;
char last = ' ';
for (int i = 0;; i++) {
char cc = sentence[i];
if (is_sep(cc)) {
if (!is_sep(last)) {
/* end of word */
if (wn == word_number) {
// replace this word with `???`
memmove(sentence + start + 3, sentence + i, len + 1 - i);
memcpy(sentence + start, "???", 3);
break;
}
wn++;
}
} else {
if (is_sep(last)) {
/* start of a word */
start = i;
}
}
last = cc;
if (cc == '\0')
break;
}
printf("Result sentence: %s\n", sentence);
return 0;
}
I’m not sure I’d try to do this in-place. For small data, it doesn’t hurt to just create a new buffer, even if it is just a temporary.
But, since we are posting solutions, here’s a single-pass version:
#include <iso646.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void replace_nth_word_with( char * dest, int n, const char * src, const char * word )
{
char last = ' ';
while (*src) // For each character in src:
if ((*src != ' ') and (last == ' ') and !n--) // If we found a word-begin AND it is the Nth word:
{ //
for (size_t k = 0; word[k]; k++) // Copy the new word to dest
*dest++ = word[k]; //
while (*src and (*src != ' ')) ++src; // Skip the old word in src
} //
else // Otherwise just copy the character over
last = *dest++ = *src++; //
*dest = '\0'; // End of string
}
void ask_string( const char * prompt, char * s, size_t n )
{
printf( "%s", prompt );
fgets( s, (int)n, stdin );
char * p = strpbrk( s, "\n\r" );
if (p) *p = '\0';
}
void ask_int( const char * prompt, int * n )
{
char s[20];
printf( "%s", prompt );
fgets( s, sizeof s, stdin );
*n = strtol( s, NULL, 10 );
// It hurts to write this without error checking, LOL
}
int main(void)
{
char sentence[1000];
ask_string( "Sentence? ", sentence, sizeof sentence );
int word_number;
ask_int( "Word number (counting from 1)? ", &word_number );
char new_word[100];
ask_string( "New word? ", new_word, sizeof new_word );
char new_sentence[sizeof sentence + sizeof new_word];
replace_nth_word_with( new_sentence, word_number-1, sentence, new_word );
printf( "\"%s\"\n", new_sentence );
return 0;
}

How to print length of each word in a string before the each Word

I want to print the length of each word in a string.
I have tried but not getting right answer. After running the code it will print the length of each word after the word instead of printing before the each word.
char str[20] = "I Love India";
int i, n, count = 0;
n = strlen(str);
for (i = 0; i <= n; i++) {
if (str[i] == ' ' || str[i] == '\0') {
printf("%d", count);
count = 0;
} else {
printf("%c", str[i]);
count++;
}
}
I except the output is 1I 4Love 5India, but the actual output is I1 Love4 India5.
You can use strtok as Some programmer dude sugested. You may want to make a copy of the original string as strtok modifies the passed string. Also strtok is not thread-safe and must be replaced with strtok_r when working with multi-threaded programs.
#include <stdio.h>
#include <stdlib.h>
/* for strtok */
#include <string.h>
int main() {
char str[20] = "I Love India";
int n;
char* tok = strtok(str, " ");
while (tok != NULL) {
n = strlen(tok);
printf("%d%s ", n, tok);
tok = strtok(NULL, " ");
}
return EXIT_SUCCESS;
}
You want to compute and print the length of each word before you print the word.
Here is a simple solution using strcspn(), a standard function that should be used more often:
#include <stdio.h>
#include <string.h>
int main() {
char str[20] = "I Love India";
char *p;
int n;
for (p = str; *p;) {
if (*p == ' ') {
putchar(*p++);
} else {
n = strcspn(p, " "); // compute the length of the word
printf("%d%.*s", n, n, p);
p += n;
}
}
printf("\n");
return 0;
}
Your approach is wrong as you print the word before the length. So you need to calculate the length first then print it and then print the word.
It could be something like:
int main(void)
{
char str[20]="I Love India";
size_t i = 0;
while(str[i])
{
if (str[i] == ' ') // consider using the isspace function instead
{
// Print the space
printf(" ");
++i;
}
else
{
size_t j = i;
size_t count = 0;
// Calculate word len
while(str[j] && str[j] != ' ')
{
++count;
++j;
}
// Print word len
printf("%zu", count);
// Print word
while(i<j)
{
printf("%c", str[i]);
++i;
}
}
}
}
The basic idea is to have two index variables for the string, i and j. The index i is at the words first character and index j is used for finding the end of the word. Once the end of word has been found, the length and the word can be printed.
This is what you want:
#include <stdio.h>
#include <string.h>
int main()
{
char str[20]="I Love India";
char buf[20];
int i,n,count=0;
n=strlen(str);
for (i=0; i <= n; i++) {
if(str[i]==' ' || str[i]=='\0'){
buf[count] = '\0';
printf("%d", count); /* Print the size of the last word */
printf("%s", buf); /* Print the buffer */
memset(buf, 0, sizeof(buf)); /* Clear the buffer */
count = 0;
} else {
buf[count] = str[i];
count++;
}
}
return 0;
}
You will want to keep a buffer of the word that is currently being counted. (buf)
Increment count each time its not a space or 0/. Then, when it is a space or a 0/, print count first, then buf. Then, we will clear buf and set count to 0, so that the variable i is still incrementing through the entire string str, but we are inserting the words into buf starting from 0.

How do I count the occurrences of each word in a string?

I'm trying to figure out how to count the occurrences of each word in a string entered by the user. I want to use an array for the input and copy each element/word into another array(words), only if the word hasn't been copied already. If it's already been copied, I want to just increment the number of occurrences by using a parallel counter array(count). So far, what I have compiles, but when I run the program it just gives me 0 for all of the count values, and it still prints every word in the string even if it's already been printed before. Any help will be greatly appreciated!
#include <stdio.h>
#include <string.h>
#define STR_LEN 1000
int read_line(char *str, int n);
int main() {
char input[STR_LEN + 1];
char *token;
char words[50];
char *p1;
char *p2;
int i;
int count[50] = { 1 };
printf("Please enter a string: ");
read_line(input, STR_LEN); //Calls the readline function
printf("Input: %s\n", input);
for (i = 0; i < strlen(input); i++) {
p1 = &input[i];
p2 = &words[i];
if (strstr(p1, input) == 0) {
strcpy(p2, p1);
} else
count[i]++;
}
printf("Output: \n");
token = strtok(words, " ,.!"); //tokenizes the first word in the string
while (token != NULL) {
printf("%s\t\t%d\n", token, count[i]);
token = strtok(NULL, " ,.!"); //tokenizes subsequent words in the string
}
return 0;
}
int read_line(char *s1, int n) {
int ch, i = 0;
while ((ch = getchar()) != '\n') {
if (i < n) {
*s1++ = ch;
i++;
}
}
*s1 = '\0'; //terminates string
return i; //number of characters stored
}
You should use an array of strings instead of an array of characters for words:
char *words[50];
You should allocate copies of the words with strdup().
You main loop is inconsistent, you are not matching words, you lookup string fragments for each offset into the string. Move the tokenization code to the loop and match strings, not characters.

Infinite Loop when counting with an array [C]

I've been trying to get back into C lately (for work related purposes) and I've been to a C refresher workshop. I can't seem to get my head around why an infinite loop occurs in this code.
I'm trying to code a program which returns the number of words within an array of characters. Any help would be greatly appreciated. Thanks!
// ArrayWords.c
#include <stdio.h>
#include <ctype.h>
#define LENGTH 50
int word_count(char []);
int main(void) {
char sentence[LENGTH];
int i;
printf("Enter a sentence with at most %d characters:\n", LENGTH);
for(i = 0; i < LENGTH; i++)
scanf("%s", &sentence[i]);
printf("Sentence = %s\n", sentence);
printf("Word count = %d\n", word_count(sentence));
return 0;
}
// Count the number of words in str
int word_count(char str[]) {
int i, word = 1;
for(i = 0; i < LENGTH; i++)
while(str[i] != '\0')
if((isspace(str[i])))
{
word++;
}
return word;
}
Your use of scanf isn't good.
word_count cause infinite loop because i isn't updated in the while loop.
fixed code:
// ArrayWords.c
#include <stdio.h>
#include <ctype.h>
#define LENGTH 50
int word_count(char []);
int main(void) {
char sentence[LENGTH];
printf("Enter a sentence with at most %d characters:\n", LENGTH);
fgets(sentence, sizeof(sentence), stdin);
printf("Sentence = %s\n", sentence);
printf("Word count = %d\n", word_count(sentence));
return 0;
}
// Count the number of words in str
int word_count(char str[]) {
int i = 0, word = 1;
while(str[i] != '\0') {
if((isspace(str[i])))
{
word++;
}
i++;
}
return word;
}
for(i = 0; i < LENGTH; i++)
scanf("%s", &sentence[i]);
Here you are reading a char one by one. so it should have %c, like scanf(" %c", &sentence[i]);
However, this wont be the right way to read the string. Since, it wont put the \0 in the end.
Since the string to be read will contain spaces, best way to do this would be fgets()
Your counting loop also has an error, either you can change it to one of the answers above or simply use a single for loop, like this
for(i = 0; i < LENGTH && str[i] != '\0'; i++)
if((isspace(str[i])))
{
word++;
}
In your code,i isn't actually in the loop.Besides,array contains the sentence with a \0 in the end,so if the length of the sentence is 50,the space must be 51 since at the end of it there is an \0,and scanf is not so good as it judges " "as a stop sign,gets can't stop until enter key which may cause overflow,so I use fgets.
#include <stdio.h>
#include <ctype.h>
#define LENGTH 50
int word_count(char []);
int main(void) {
char sentence[LENGTH+1];
printf("Enter a sentence with at most %d characters:\n", LENGTH);
fgets(sentence, sizeof(sentence), stdin);
printf("Sentence = %s\n", sentence);
printf("Word count = %d\n", word_count(sentence));
return 0;
}
// Count the number of words in str
int word_count(char str[]) {
char* p=str;
int word=0;
while(*p!='\0'){
if((isspace(*p))) word++;
p++;
}
return word;
}
You should read data from stdin, not scanf but fgets or gets!
Maybe fgets( sentence, LENGTH, stdin ) is good.
And in the function word_count you may replace while with if.
This part of the program
for(i = 0; i < LENGTH; i++)
scanf("%s", &sentence[i]);
does not make sense. It tries to enter LENGTH number of words in the loop.
I think you mean format specifier %c instead of %s
scanf("%c", &sentence[i]);
but even in this case this snippet of code is wrong because the user can enter either less than LENGTH characters or even greater than LENGTH characters and the character array sentence will not be zero-terminated..
It is better to use standard function fgets instead of scanf in this situation.
And function word_count is also wrong. For example if str would be zero-terminated nevertheless the outer for loop will try to count words outside the string. And the function in fact counts the number of spaces. It is not the same as the number of words. A string can contain adjasted spaces. This mistake is made by all others in their answers.:)
And inside the while loop variable i is not increased. So it is an infinite loop.
int word_count(char str[]) {
int i, word = 1;
for(i = 0; i < LENGTH; i++)
while(str[i] != '\0')
if((isspace(str[i])))
{
word++;
}
return word;
}
The program can look the following way
// ArrayWords.c
#include <stdio.h>
#include <ctype.h>
#define LENGTH 50
size_t word_count( const char[] );
int main( void )
{
char sentence[LENGTH];
printf( "Enter a sentence with at most %d characters: ", LENGTH );
fgets( sentence, LENGTH, stdin );
printf( "Sentence = \"%s\"\n", sentence );
printf( "Word count = %zu\n", word_count( sentence ) );
return 0;
}
// Count the number of words in str
size_t word_count( const char s[] )
{
size_t words = 0;
while ( *s != '\0' )
{
// skip white spaces
while ( isspace( ( unsigned char )*s ) ) ++s;
if ( *s != '\0' ) ++words;
// skip the word
while ( *s != '\0' && !isspace( ( unsigned char )*s ) ) ++s;
}
return words;
}
Its output might look like
Enter a sentence with at most 50 characters: Hello, Unholy Wish
Sentence = "Hello, Unholy Wish"
Word count = 3
It's not an infinite loop.
Your program is trying to read 50 (or LENGTH) words (and saving them on top of each other).
for(i = 0; i < LENGTH; i++)
scanf("%s", &sentence[i]);
Put first word starting at sentence[0];
put second word starting at sentence[1] overwriting characters from the first word;
...

Replace multiple spaces by single space in C

I want to repace multiple spaces in a string by single space, however my following code doesn't work. What's the logical mistake?
#include<stdio.h>
#include<string.h>
main()
{
char input[100];
int i,j,n,z=0;
scanf("%d",&n);
z=n;
for(i=0;i<n;i++)
scanf("%c",&input[i]);
for(i=0;i<n;i++)
{
if(input[i]==' ' && (input[i+1]==' ' || input[i-1]==' '))
{
--z;
for(j=i;j<n;j++)
input[j]=input[j+1];
}
}
for(i=0;i<z;i++)
printf("%c",input[i]);
printf("\n");
}
I would do something like this:
void replace_multi_space_with_single_space(char *str)
{
char *dest = str; /* Destination to copy to */
/* While we're not at the end of the string, loop... */
while (*str != '\0')
{
/* Loop while the current character is a space, AND the next
* character is a space
*/
while (*str == ' ' && *(str + 1) == ' ')
str++; /* Just skip to next character */
/* Copy from the "source" string to the "destination" string,
* while advancing to the next character in both
*/
*dest++ = *str++;
}
/* Make sure the string is properly terminated */
*dest = '\0';
}
Of course, the above function requires you to properly terminate the string, which you currently do not.
What the function above does, is basically copy the string over itself. The exception is when there is a space, when multiple spaces are simply discarded.
Since the function modifies the source string, it can not be used on string literals.
The scanf is giving you some problem: it reads the \n you give after inputting the length n. So, you will miss the last character since for loop exits. The already given answers are good enough. But if you want to follow your own logic, try this:
void main()
{
char input[100];
int i = 0,j,n = 0;
while ((input[n] = getchar()) != '\n') {
n++;
}
input[n] = '\0';
while (i < n)
{
if(input[i]==' ' && (input[i+1]==' ' || input[i-1]==' '))
{
for(j=i;j<n;j++)
input[j]=input[j+1];
n--;
}
else
{
i++;
}
}
printf("%s\n",input);
printf("\n");
}
if(input[i]==' ' && (input[i+1]==' ' || input[i-1]==' '))
case " 1 3" : when i == 0 accses input[i-1] Out-of-Bounds
scanf("%d",&n);
remain newline, (input[0] <-- '\n')
fix to
scanf("%d%*c",&n);
#include <stdio.h>
char* uniq_spc(char* str){
char *from, *to;
int spc=0;
to=from=str;
while(1){
if(spc && *from == ' ' && to[-1] == ' ')
++from;
else {
spc = (*from==' ')? 1 : 0;
*to++ = *from++;
if(!to[-1])break;
}
}
return str;
}
int main(){
char input[]= " abc de f ";
printf("\"%s\"\n", uniq_spc(input));//output:" abc de f "
return 0;
}
Why make it more complicated than it needs to be? You can use strtok to check for single whitespaces and just ignore those. Then you can use strcat to concatenate the string into a full sentence and then you're done.
This is how I did it:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int main(void) {
char *pch;
char sentence[1000];
char without[1000];
printf("Sentence: ");
fgets(sentence,1000, stdin);
strtok(sentence, "\n"); // remove any newlines
pch = strtok(sentence, " ");
while(pch != NULL) {
strcat(without, pch);
strcat(without, " \0");
pch = strtok(NULL, " ");
}
without[strlen(without)-1] = '\0'; // remove extra whitespace at the end
printf("|%s|\n",without);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
void remove_blanks(char* s);
int main()
{
char const s[] = {'1',' ',' ','2',' ',' ','3'};
remove_blanks(s);
printf("%s",s);
return 0;
}
void remove_blanks(char* s){
int i=0, delta=0, cnt=0;
for (i=0;s[i];++i){
if (s[i]==' ') cnt++;
if (cnt>1){
delta+=1;
cnt=0;
}
s[i-delta]=s[i];
if(delta>0) s[i]='\0';
}
}
You cant try this simple code:
#include <stdio.h>
#define IN 1
#define OUT 0
int main() {
int c, spaces, state;
spaces = 0;
state = OUT;
while ((c = getchar()) != EOF) {
if ( c == ' ') {
++spaces;
state = OUT;
}
else if (state == OUT) {
state = IN;
spaces = 0;
}
if (c == ' ' && spaces > 1 && state == OUT)
c = 0;
putchar(c);
}
return 0;
}
You have to fix the following for loop. the limit of your for loop should be z and not n
for(j=i;j<n;j++)
input[j]=input[j+1];
by
for(j=i;j<z;j++)
input[j]=input[j+1];
BTW: the fist charachter get by your scanf() (which read charachters) is newline (\n). this newline come from the first scanf() of decimal(%d)
#include<stdio.h>
#include<string.h>
int main(void)
{
char input[1000];
int i=0;
gets(input);
for(i=0;input[i]!='\0';i++)
{
if(input[i]!=' ' || input[i+1]!=' ')
printf("%c",input[i]);
}
return 0;
}

Resources