Infinite Loop when counting with an array [C] - 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;
...

Related

Reading words and storing them in 2-D array in C

I am trying to write a program that reads lines word by word and puts each word in an array (later I want to do some operations on those words but this isn't an issue now) and in the output there should be a number of words in each line. For example:
input:
good morning my neighbors!
how are you?
output:
4
3
Here is my code:
#include <stdio.h>
#include <string.h>
int main()
{
char word[100];
char wordArray[100][100];
int count = 0;
for(;scanf("%s", word)!=EOF;)
{
strcpy(wordArray[count], word);
count++;
}
printf("%d", count);
return 0;
}
But it gives me just 7 in the output (number of all words on both lines). If I put printf function inside the for loop then I get 1234567 as an output. How do I make it count words on one line and print it then set the count to zero and start over on the next line?
You should use fgets or getline because scanf reads word by word not all words in one line.
The code:
#include <stdio.h>
#include <string.h>
#define SIZE 100
int main()
{
char wordArray[SIZE][SIZE];
int count[SIZE];
int c = 0;
while(fgets( wordArray[c], SIZE, stdin) && c < SIZE)
{
for(int i = 0; wordArray[c][i] != '\0' ; i++) {
// remove enter character at the end of each line, not necessary in this case but mabe later when you work with all works
wordArray[c][strcspn ( wordArray[c], "\n" )] = '\0';
if (wordArray[c][i] == ' ') {
count[c]++; // increase the number of words if we meet space character
}
}
c++;
}
for (int i = 0; i < c; i++) //print all the counts
printf("%d", count[i] + 1);
return 0;
}
Here I used fgets to get line by line from stdin.
The code actually count the spaces in the line and add 1 to them. I also did NOT used string.h.
#include <stdio.h>
#define SIZE 100
int main()
{
int i=0;
char lines[SIZE][SIZE];
int count[SIZE]={0};
while(i<SIZE){
fgets(lines[i], SIZE, stdin);
if (lines[i][0]=='\n') break;
i++;
}
for(int j=0; j<i; j++){
char *x=lines[j];
while(*x!='\0') {
if (*x==' ') count[j]++;
x++;
}
printf("%d\n", count[j]+1);
}
return 0;
}
It gives you 7 because count is never reseted. I would store the counts to print later, this could be done with an array, the 1234567 is normal if it's inside the cycle it will print count for every word scaned. If you use "%d " with a space you'll have 1 2 3 4 5 6 7.
The following program takes 5 lines from the user, counts the words in each line and stores the counts in an array, using scanf and strtok to count the words:
Demo
#include <stdio.h>
#include <string.h>
#define SIZE 5
#define LENGTH 100
int main()
{
char word[LENGTH];
char wordArray[SIZE][LENGTH];
int count[SIZE] = {0}; //array to store the counts
const char delimiter[] = " ";
char *token;
printf("Insert %d phrases:\n", SIZE);
// %99[^\n] specifier also to avoid buffer overflow and read till newline
for (int i = 0; i < SIZE && scanf(" %99[^\n]", wordArray[i]) == 1; i++)
{
strcpy(word, wordArray[i]);
token = strtok(word, delimiter);
while (token != NULL)
{
count[i]++;
token = strtok(NULL, delimiter);
}
}
for (int i = 0; i < SIZE; i++) {//print all the counts
printf("string %d - \"%s\" - ", i + 1, wordArray[i]);
printf("%d words\n", count[i]);
}
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.

Can't break a while loop. Reading undefined array size

I have this sequence of letters and numbers, in which the letters are always these four: s, S, m, M. The numbers can have any value. Since the size of the sequence is not given, I just can't use a for loop, so I decided to use a while loop, but I'm having issues on breaking the loop.
Some input examples are:
12 s 80 s 3 m 12 M 240 S 8 m 30 s 240 s 1440 S 8 m 18 s 60 M
5 m 120 s 30 s 360 S 6 M 5 s 42 S 36 M 8 m 66 M 3240 S 14 m
Here is my code so far:
#include <stdio.h>
int main () {
int n[100], i = 0;
char x[100];
while(x[i] != '\n')
{
scanf(" %d %c", &n[i], &x[i]);
printf("%d %c ", n[i], x[i]);
i++;
}
return 0;
}
Any toughts on how to break the loop, and have all this values saved correctly on the array?
like this
#include <stdio.h>
int main(void){
int n[100], i, j;
char x[100];
do {
for(i = 0; i < 100; ++i){
int ch;
while((ch = getchar()) != EOF && ch != '\n'){//check newline
if(ch == '-' || '0' <= ch && ch <= '9'){
ungetc(ch, stdin);//back to stream a character
break;
}
}
if(ch == EOF || ch == '\n')
break;
if(2 != scanf("%d %c", &n[i], &x[i])){
fprintf(stderr, "invalid format.\n");
i = 0;//End the outer do-while loop
break;
}
}
//print
for(j = 0; j < i; ++j){
printf("(%d, %c)", n[j], x[j]);
}
printf("\n");
} while(i != 0);//End with empty line
}
#include <stdio.h>
#define DATA_MAX_LEN 100
int main(void){
int n[DATA_MAX_LEN], i, len, loop_end;
char x[DATA_MAX_LEN], newline[2], ch;
while(scanf("%1[\n]", newline) != 1){//End with empty line(only newline), Need EOF check
for(loop_end = len = i = 0; i < DATA_MAX_LEN && !loop_end; ++i){
//format: integer character[space|newline]
if(scanf("%d %c%c", &n[i], &x[i], &ch) != 3)
loop_end = printf("invalid format.\n");
else if(ch == '\n')
loop_end = len = ++i;
else if(ch != ' ')
loop_end = printf("invalid format.\n");
}
for(i = 0; i < len; ++i){
printf("%d %c ", n[i], x[i]);
}
printf("\n");
}
}
scanf and fscanf have many problems so it's best to avoid them.
The general pattern for dealing with input is to create a large input buffer, and then process that into smaller chunks.
char line[4096];
fgets( line, sizeof(line), stdin );
Since line is reused it's ok to make it large enough to hold any reasonable input.
Now that you've read a line into memory, it's a string of known size to process as you like. sscanf (scanf on a string) doesn't have most of the problems of scanf, but it's also not suited to moving through a string. One approach is to split the string into tokens on whitespace with strtok, and process them alternately as letters and numbers.
const char sep[] = " \t\n";
bool expect_letter = false;
for(
char *token = strtok( line, sep );
token != NULL;
token = strtok( NULL, sep )
) {
if( expect_letter ) {
printf("Letter %s\n", token);
expect_letter = false;
}
else {
printf("Number %s\n", token);
expect_letter = true;
}
}
If you want to store them in an array, it's bad practice to allocate what you hope is enough memory. You'll have to use an array that grows as needed. C does not have these built in. You can write your own, and it's a good exercise, but it's easy to get wrong. For production use one from a library such as Glib.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <glib.h>
int main() {
// Read a single line of input into a buffer.
char line[4096];
fgets( line, sizeof(line), stdin );
// Create arrays to hold letters and numbers, these will grow as needed.
GArray *numbers = g_array_new( FALSE, TRUE, sizeof(int) );
GArray *letters = g_array_new( FALSE, TRUE, sizeof(char) );
// Split the string on whitespace into tokens.
const char sep[] = " \t\n";
gboolean expect_letter = FALSE;
for(
char *token = strtok( line, sep );
token != NULL;
token = strtok( NULL, sep )
) {
if( expect_letter ) {
// Need an error check to ensure that `token` is a single character.
g_array_append_val( letters, token[0] );
expect_letter = FALSE;
}
else {
// strtol is a better choice, it has error checking
int num = atoi(token);
g_array_append_val( numbers, num );
expect_letter = TRUE;
}
}
// Print the numbers and letters.
for( guint i = 0; i < letters->len; i++ ) {
printf(
"%d%c\n",
g_array_index( numbers, int, i ),
g_array_index( letters, char, i )
);
}
}
Note that GLib provides its own boolean, so I switched to that instead of stdbool to keep things consistent.
As noted in the comments, this does not include checks that the token is what you expect. It's also possible to have a number with no letter, so checking that letters and numbers are the same size would be good. Or you can make a struct to hold the letter/number pairs and have a single list of those structs.

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.

C: counting number of words (need help fixing)

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!!!

Resources