Program to find the longest word in a string - c

I wrote a program to find the longest word in a string and print the number of letters in the longest word. But the code is not printing. I analyzed the program many times but I could not find the solution.
#include <stdio.h>
#include <string.h>
int main() {
char string[100] = "Hello Kurnool";
int i = 0, letters = 0, longest = 0;
start:
for (; string[i] !=' '; i++) {
letters++;
}
if (letters >= longest)
longest = letters;
if (string[i] == ' ') {
letters = 0;
i++;
goto start;
}
printf("%d", longest);
return 0;
}

Using goto is highly discouraged. You should convert your code to use a loop.
The main problem in your code is you do not stop the scan when you reach the end of the string.
Here is a modified version:
#include <stdio.h>
int main() {
char string[100] = "Hello Kurnool";
int i, letters, longest = 0, longest_pos = 0;
for (i = 0; string[i] != '\0'; i++) {
for (letters = 0; string[i] != '\0' && string[i] != ' '; i++) {
letters++;
}
if (letters > longest) {
longest = letters;
longest_pos = i - longest;
}
}
printf("longest word: %d letters, '%.*s'\n",
longest, longest, string + longest_pos);
return 0;
}
Note that the implementation can be simplified into a single loop:
#include <stdio.h>
int main() {
char string[100] = "Hello Kurnool";
int i, start = 0, longest = 0, longest_pos = 0;
for (i = 0; string[i] != '\0'; i++) {
if (string[i] == ' ') {
start = i + 1;
} else {
if (i - start > longest) {
longest = i - start;
longest_pos = start;
}
}
}
printf("longest word: %d letters, '%.*s'\n",
longest, longest, string + longest_pos);
return 0;
}

Below is my approach. You should use C's string manipulation functions. This is the correct way to deal with strings in C.
In the code below, first I acquire the required bytes to store the input string in heap. Then I use strtok to split the string into tokens based on a delemeter and get the length of each sub string. Finally I free the space that I have allocated with malloc.
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define phrase "Hello Kurnool"
int main()
{
char* string = malloc(strlen(phrase)+1);
strcpy(string,phrase);
int longest=0;
char *token;
char delimeter[2] = " ";
/* get the first token */
token = strtok(string, delimeter);
/* walk through other tokens */
while( token != NULL ) {
printf( " %s\n", token );
if(longest < strlen(token)){
longest = strlen(token);
}
token = strtok(NULL, delimeter);
}
printf("%d",longest);
free(string);
return 0;
}

People say - dont use goto but there is nothing inherently wrong with goto. Only thing is if goto is not used judiciously, it makes code more difficult to understand and maintain. For example, the way you have used it in your program ( instead of goto, a loop is perfect fit in such cases). Check this:
To use goto or not?
What is wrong with using goto?
Coming to your code, the for loop condition does not have check for terminating null character
for (; string[i] !=' '; i++) {
Hence it will not stop at the end of string.
To find the number of letters in longest word of string, you can do:
#include <stdio.h>
#include <string.h>
int main() {
char string[100] = "Hello Kurnool";
int i, letters = 0, longest = 0;
for (i = 0; string[i] != '\0'; i++) {
if (string[i] != ' ') {
letters++;
if (letters > longest) {
longest = letters;
}
} else {
letters = 0;
}
}
printf("longest : %d\n", longest);
return 0;
}

First of all,Please avoid using Goto, it is not a good practice.
Secondly, your loop will run infinite times when it iterates the second time because:
for(;string[i]!=' ';i++) // Here String[i] will never be equal to ' ' As there is no white space after your last word.

You can never expect what might be going wrong with your program if you are using
goto statement
which is never advisable to use rather it's bad programming if you use it. Secondly it looks like you are stuck in an infinite loop so her is a solution to your problem:
#include<stdio.h>
#include<string.h>
void main()
{
char s[1000];
scanf("%s",s);
int i=0;
int letters;
int longest=0;
while(s[i]!=NULL)
{
if(s[i]==' ')
{
if(longest>=letters)
{longest=letters;}
letters=0;
}
else
{letters++;}
}
printf("%d\n",longest);
}
So, what I have done is assuming a string s which is the input given by the user. You itterate through s till the last input given by the user after which it encounters a NULL character. Now you are searching for the length of the longest word, so you create a variable letters for counting the no. of letters in each word of the string. And if the string s encounters a space indicating the end of a word, then you check if the variable longest is greater than or less than the word count. And again you initialize letters to 0, so that it can start counting the next word from 0 again.So, by this method at the end i.e. after the while loop terminates we get our required output which is stored in the variable longest.
So, I guess this will print the no. of letters in the longest word.

Related

Why does strlen() not represent the actual length of my string?

basically I have a string composed of multiple words like this: "Hello world test".
Either if I try to print it with a structure like this
printf("%s", string);
or like this
for (int i = 0; i < strlen(string); ++i) {
printf("%c", string[i];
}
I always get this as an output: Hello world and I get a strlen of 11 instead of 16 too.
If I try to print out the same exact string with an int counter that previously counts the single chars in the string
for (int i = 0; i < counter; ++i) {
printf("%c", string[i];
}
I actually get the correct output Hello world test, which leads be to believe that the elements are correctly assigned in the string but for some reason %s and strlen just ignores the ones after the last space.
Why would that happen? What is going on? How can I fix this?
EDIT:
Actual code as requested:
#include <stdio.h>
#include <string.h>
typedef int BOOL;
#define TRUE 1
#define FALSE 0
int main() {
char sentence[64] = " ", reversal[64] = " ", reversal_copy[64] = " ";
int index = 0, counter = 0;
BOOL reset = TRUE, last_cycle = FALSE;
printf("Enter a sentence: ");
for (int i = 0; sentence[strlen(sentence) - 1] != '\n'; i++) {
scanf("%c", &sentence[i]);
}
/* Copies the input in a string reversing it */
for (int h = strlen(sentence) - 2, k = 0; h >= 0; h--, k++) {
reversal[k] = sentence[h];
}
/* Detects the first character of a word and the last character of the same word before a space,
switching the first char with the last, the second with the pre-last and so on*/
for (int i = 0; i < strlen(reversal); i++) {
if (reset == TRUE) {
index = i;
reset = FALSE;
}
if (i == strlen(reversal) - 1) {
last_cycle = TRUE;
counter++;
}
if (reversal[i] != ' ') {
counter++;
if (last_cycle == TRUE) {
goto reversing;
}
}
else {
reversing:
for (int h = index, z = counter; h < counter; h++, z--) {
reversal_copy[h] = reversal[z - 1];
reversal_copy[z - 1] = reversal[h];
}
if (last_cycle == FALSE) {
reversal_copy[i] = ' ';
}
reset = TRUE;
counter++;
}
}
printf("%lu ", strlen(reversal_copy));
for (int i = 0; i < counter; i++) {
printf("%c", reversal_copy[i]);
}
printf("%s\n\n", reversal_copy);
return 0;
}
if strlen() returns 11 then you have a \0 char after the world "world".
strlen and printf both determine "what is a string" by using the 0 terminator, so no surprise that they behave the same.
While this is difficult to answer without a Minimal, Complete, and Verifiable example, I will explain the most likely reason for the behavior you're observing.
Both printf with the %s format specifier and strlen give you the length of the null-terminated string pointed to by the relevant argument. If they are printing/reporting a length of 11, but iterating through the entire char array with a hard-coded value of 16 gives you the output "hello world test", then the character after world is clearly the null character, '\0'.
Try running your program with the input "A" as an example - see that even a single word exhibits the problem.
Something is going wrong when you reverse the last word. You are putting the trailing '\0' in front of it. It probably has to do with the special casing and the goto around the last_cycle logic, which is very hard to follow.
I think it's probably related to the fact that you have two counter++s in that code path.
Consider using some functions to make the code cleaner:
len = strlen(reversal);
for (start=0; start<len; start++) {
end = find_space_or_null(reversal, start);
if (end > start) {
reverse_chars(reversal, start, end-1);
start = end;
}
}
the program takes a string inputted by the user like "the sky is blue" and prints out "blue is sky the"
That's a perfect job for strtok():
#include <stddef.h>
#include <stdio.h>
#include <string.h>
enum { MAX_LINE = 120 };
int main()
{
char buffer[MAX_LINE];
fgets(buffer, MAX_LINE, stdin);
size_t length = strlen(buffer);
if (length && buffer[length - 1] == '\n') // get rid of the newline
buffer[--length] = '\0';
char *tokens[MAX_LINE] = { 0 }; // there can't be more than 60 tokens, but hey
if ((tokens[0] = strtok(buffer, " ")) == NULL) // no tokens? nothing to do.
return 0;
size_t i = 1;
for (; tokens[i - 1] && i < sizeof(tokens); ++i)
tokens[i] = strtok(NULL, " "); // tokenize the buffer
--i; // the very last was NULL anyway.
while (--i) // print it reverse
printf("%s ", tokens[i]);
puts(buffer);
}
Sample Output:
The quick brown fox jumps over the lazy dog
dog lazy the over jumps fox brown quick The

If loop in C not iterating properly

Writing a word counter on C. I'm counting the number of spaces in the string to determine the number of words. I'm guessing there's something wrong with my if statement. Sometimes it counts the number of words and other times it's throwing up random numbers? For instance "my red dog" has three words but "I drink rum" has one word and "this code makes no sense" has three. It's printing the length of the strings fine for each.
Here's the part of the code in question:
void WordCounter(char string[])
{ int counter = 1;
int i = 0;
int length = strlen(string);
printf("\nThe length of your string is %d", length);
for( i=0;i<length;i++){
if (string[i] == ' ')
{
counter+=1;
++i;
}
else
{
counter +=0;
++i;
}
}
printf("There are %d words in this sentence and i is equal to: %d", counter, i);
}
The i++ part of the for loop means that i is incremented at every loop, you should not do it again inside the loop. Also, your else is not necessary here. You'll want to remove bits to have:
for( i=0;i<length;i++) {
if (string[i] == ' ')
{
counter+=1;
}
}
The biggest problem with your posted code is that it incorrectly increments i where it should not.
for( i=0;i<length;i++){
if (string[i] == ' ')
{
counter+=1;
++i; // here
}
else
{
counter +=0;
++i; // here
}
}
Neither of the //here lines above are needed for what you appear to be trying to do. Furthermore, the entire else-block is pointless, as it modifies nothing except i, which it shouldn't be doing. Therefore, a more correct approach would be simply:
for(i=0; i<length; ++i)
{
if (string[i] == ' ')
++counter;
}
This increments counter whenever you index a space ' ' character. For a trivial algorithm, this will probably suffice to what you were trying.
Counting Spaces, Not Words
Your algorithm really doesn't count words, it simply counts the number of space characters encountered, plus one. This mean some inputs, such as those below (quotes used to note content in the string, not actually present), will not return an accurate word-count:
// shoud be zero, but returns one
""
// should be zero, but returns four (three spaces)
" "
// should be one, but returns five (two spaces, either side)
" word "
// should be two, but returns three (two spaces between)
"word word"
etc.
A more robust algorithm is required. Note this does NOT solve everything, but it makes great leaps in getting you closers to counting what we call "words". That is, non-whitespace characters separated by whitespace characters and potentially buttressing up to the end of the string.
This uses pointers rather than indexes. In my opinion it is simply easier to read, and declutters the code from indexing syntax, thereby amplifying what is really going on: consuming whitespace, then consuming non-whitespace that we call a "word". Comments inline should explain what is going on:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int WordCounter(const char *s)
{
int counter = 0;
// while we haven't reached terminating nullchar
while (*s)
{
// discard all whitespace until nullchar or non-whitespace found
for (; *s && isspace((unsigned char)*s); ++s);
// if not nullchar, we have the start of a "word"
if (*s)
{
++counter;
// discard all text until next whitespace or nullchar
for (; *s && !isspace((unsigned char)*s); ++s);
}
}
return counter;
}
int main()
{
const char *s1 = "There should be eight words in this string";
printf("\"%s\"\nwords: %d\n", s1, WordCounter(s1));
const char *s2 = " There should\t\t\tbe eight\n in\n this\n string too\n ";
printf("\"%s\"\nwords: %d\n", s2, WordCounter(s2));
const char *s3 = "One";
printf("\"%s\"\nwords: %d\n", s3, WordCounter(s3));
const char *s4 = "";
printf("\"%s\"\nwords: %d\n", s4, WordCounter(s4));
return 0;
}
Output
"There should be eight words in this string"
words: 8
" There should be eight
in
this
string too
"
words: 8
"One"
words: 1
""
words: 0
Not Perfect; Just Better
The prior algorithm still isn't perfect. To accurately extract single words would require knowledge of punctuation, potentially hyphenation, etc. But it is much, much closer to what appears to be the goal. Hopefully you get something out of it.
Your code has increment i in 3 different places. The increment needs only the loop.
Try this code:
for( i=0;i<length;i++){
if (string[i] == ' ')
{
counter++;
}
}
You´re incrementing i 2 times in the same loop. One in the for statement and one in the loop. It means you´re checking only one character on two. It can explain why all pair spaces are not in the count:
I put in Bolt all pair characters:
"my red dog": Both spaces are unpair numbers
"I drink rum": Both spaces are unpair numbers
Here is your corrected source code:
void WordCounter(char string[]){
int counter = 1;
int i = 0;
int length = strlen(string);
printf("\nThe length of your string is %d", length);
for( i=0;i<length;i++){
if (string[i] == ' ')
{
counter+=1;
}
}
printf("There are %d words in this sentence and i is equal to: %d", counter, i);
}
You even do not need the i variable
counter = 0;
while(*str)
counter += *str++ == ' ' ? 1 : 0;
printf("There are %d spaces (not words as you may have more spaces between words) in this sentence and length of the string is: %d", counter, length);
int isDelimeter(int ch, const char *delimiters)
{
return strchr(delimiters, ch) != NULL;
}
const char *skipDelimiters(const char *str, char *delimiters)
{
while (*str && isDelimeter(*str, delimiters)) str++;
return str;
}
const char *skipWord(const char *str, char *delimiters)
{
while (*str && !isDelimeter(*str, delimiters)) str++;
return str;
}
const char *getWord(const char *str, char *buff, char *delimiters)
{
while (*str && !isDelimeter(*str, delimiters)) *buff++ = *str++;
*buff = 0;
return str;
}
int countWords(const char *str, char *delimiters)
{
int count = 0;
while (*str)
{
str = skipDelimiters(str, delimiters);
if (*str) count++;
str = skipWord(str, delimiters);
}
return count;
}
int printWords(const char *str, char *delimiters)
{
char word[MAXWORDLENGTH];
int count = 0;
while (*str)
{
str = skipDelimiters(str, delimiters);
if (*str)
{
count++;
str = getWord(str, word, delimiters);
printf("%d%s word is %s\n", count, count == 1 ? "st" : count == 2 ? "nd" : count == 3 ? "rd" : "th", word);
}
}
return count;
}

Program that checks if an array is a palindrome

I'm trying to create a program that checks if a given array/string is a palindrome or not and its not working. The program just prints "0" on every given array, even on palindromes.
int main()
{
char string[100]= {0};
char stringReverse[100]= {0};
int temp = 0;
int firstLetter = 0;
int lastLetter = 0;
printf("Please enter a word or a sentence: ");
fgets(string, 100, stdin);
strcpy(stringReverse , string); // This function copies the scanned array to a new array called "stringReverse"
firstLetter = 0;
lastLetter = strlen(string) - 1; //because in array, the last cell is NULL
// This while reverses the array and insert it to a new array called "stringReverse"
while(firstLetter < lastLetter)
{
temp = stringReverse[firstLetter];
stringReverse[firstLetter] = stringReverse[lastLetter];
stringReverse[lastLetter] = temp;
firstLetter++;
lastLetter--;
}
printf("%s %s", stringReverse, string);
if ( strcmp(stringReverse , string) == 0)
{
printf("1");
}
else
{
printf("0");
}
}
Lets say we implement a simple fun to do that
int check_palindrome (const char *s) {
int i,j;
for (i=0,j=strlen(s)-1 ; i<j ; ++i, --j) {
if (s[i] != s[j]) return 0; // Not palindrome
}
return 1; //Palindrome
}
I think this is far more simpler ;)
For the code posted in question:
Be aware of fgets(). It stops in the first '\n' or EOF and keeps the '\n' character.
So if you give radar for ex, the result string will be "radar\n", which doesn't match with "\nradar"
The Problem:
Let's say you enter the string RACECAR as input for your program and press enter, this puts a newline character or a '\n' in your buffer stream and this is also read as part of your string by fgets, and so your program effectively ends up checking if RACECAR\n is a palindrome, which it is not.
The Solution:
After you initialize lastLetter to strlen(string) - 1 check if the last character in your string (or the character at the lastLetter index is the newline character (\n) and if so, decrease lastLetter by one so that your program checks if the rest of your string (RACECAR) is a palindrome.
lastLetter = strlen(string) - 1; //because in array, the last cell is NULL
// Add these 2 lines to your code
// Checks if the last character of the string read by fgets is newline
if (string[lastLetter] == '\n')
lastLetter--;
fgets adds a '\n' at the end.
So if the user entered "aba", string contains "aba\n".
reverseString contains "\naba".
So it doesn't match.
After the fgets, add this code
int l = strlen(string) - 1;
string[l] = 0;
This will strip out the '\n' at the end before copying it to reverseString.
That aside, you can do this whole program inplace without the need of a second buffer or strcpy or strlen calls.
You have several issues in your code:
first you forgot the last closing brace };
then you forgot to remove the trailing \n (or maybe also \r under Windows) in string;
you don't need to revert the string into a new string; a one-pass check is enough:
Here is a working code:
#include <stdio.h>
#include <string.h>
int main()
{
char string[100]= {0};
int temp = 0;
int firstLetter = 0;
int lastLetter = 0;
printf("Please enter a word or a sentence: ");
fgets(string, 100, stdin);
firstLetter = 0;
lastLetter = strlen(string) - 1; //because in array, the last cell is NULL
while ((string[lastLetter]=='\n')||(string[lastLetter]=='\r')) {
lastLetter--;
}
// This while reverses the array and insert it to a new array called "stringReverse"
temp = 1;
while(firstLetter < lastLetter)
{
if (string[firstLetter] != string[lastLetter]) {
temp = 0;
break;
}
firstLetter++;
lastLetter--;
}
if ( temp )
{
printf("1");
}
else
{
printf("0");
}
}
You can do it by this simpleway also.
#include <stdio.h>
#include <string.h>
int main()
{
char string[10], revString[10];
printf("Enter string for reversing it...\n");
scanf("%s", string);
int stringLength = strlen(string);
for(int i = 0; string[i] != '\0'; i++, stringLength--)
{
revString[i] = string[stringLength - 1];
}
if(strcmp(string, revString) == 0)
printf("Given string is pelindrom\n");
else
printf("Given string is not pelindrom\n");
}
#include<stdio.h>
#include<string.h>`enter code here`
void fun(char *a);
int main ()
{
char p[100];
char *s=p;
printf("enter the string");
scanf("%[^\n]",s);
fun(s);
}
void fun(char *a)
{
if(*a && *a!='\n')
{
fun(a+1);
putchar(*a);
}
}
// use this approach better time complexity and easier work hope this helps

C Programming: Counting word length occurences in a string

How would you be able to count word lengths and output their occurrences from a string using gets() or fgets()? For example, here is code doing so but using getchar()below. I think writing it in gets() would make it easier to incorporate all of the delimiters in the program rather than having to manually set if statements for each one of those would it not?
#include <string.h>
#include <ctype.h>
const char delim[] = ", . - !*()&^%$##<> ? []{}\\ / \"";
#define SIZE 100
int main(void){
int length[SIZE] = { 0 };
int name[SIZE];
int i = 0, ch, word_len = 0;
int count = 0;
printf("enter sentence: ");
while (1){
ch = getchar();
if (isalpha(ch)){
++word_len;
}
else if (ch == ' ' || ch == '.'){
if (word_len)
length[word_len - 1]++;//-1: to 0 origin
if (ch == '.')
break;
word_len = 0;
}
}
printf("Word Length \tCount \n");
for (i = 0; i<sizeof(length) / sizeof(*length); ++i){
if (length[i])
printf(" %d \t\t%d\n", i + 1, length[i]);
}
return 0;
}
You can build your custom delimiter detection function.
// globals
const char *delim = " .,;:!?\n\0";
const int n_delim = 9;
int is_delim(int c)
{
register int i;
for (i = 0; i < n_delim; i++)
if (c == delim[i]) return 1;
return 0;
}
This function will return 1 every time it can match c with delim. So you can use it like this:
fgets(buffer, 200, stdin);
for (i = 0; i < strlen(buffer); i++) {
if (is_delim(buffer[i])) {
wl[words++] = length;
length = 0;
continue;
}
length++;
}
I'm assuming you're familiar with the fgets function.
You basically will loop through your buffer, making comparisons with each character. Every loop iteration you check if the current character is a word delimiter, if it is, you save the current length and set length=0 for a new word, and at every iteration you increment the length.
You'll need to come up with a way of either not inserting the zero length values due to double delimiters or just ignore them when you're printing the results.
Basically you want to split a string into words, based on some delimiters, and compute their length. The C standard library provides the strtok function, which does exactly what you need: it splits the given string into multiple tokens.

Word length frequency in C Program

I am trying to write a simple C program to output the length of words and output their frequencies. For example, if the user inputs "hey" my program would output Length of word: 3 Occurrences 1, and so on with a larger string inputted. I just cannot seem to loop it properly. I thought of setting both counters when a delimiter is seen to count both the length of the word at the time and its occurrence but I have not found a way for it to work. How can I fix my loop? My code is below. I'd appreciate any help. I should include my program only runs correctly for one word inputted but not a whole sentence or multiple sentences.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
const char delim[] = ", . - !*()&^%$##<> ? []{}\\ / \"";
const int n_delim = 31;
#define SIZE 1000
int is_delim(int c);
int main(){
char string[SIZE];
int wordlength = 0, wl[SIZE];
int word = 0, i;
printf("Enter your input string:");
fgets(string, SIZE, stdin);
string[strlen(string) - 1] = '\0';
printf("Word Length\tCount\n");
int seen = 0;
int l;
for (i = 0; i < strlen(string); i++){
if (is_delim(string[i])){
wl[word++] = wordlength;
l = wordlength;
seen++;
printf("%d\t\t%d\n", l, seen);
wordlength = 0;
}
wordlength++;
}
return 0;
}
int is_delim(int c){
register int i;
for (i = 0; i < n_delim; i++)
if (c == delim[i]) return 1;
return 0;
}
The trick is that wl[n] holds the count of words
of length n. Also, you don't need to keep calling strlen()
on every iteration, just check for the zero byte at the end.
The optimizer will do this for you, if you enable it.
The odd-looking for(;1;) is so that the loop counts
the final word, which is terminated by the zero byte.
memset(wl,0,sizeof(wl));
for(wordStart=maxLength=i=0;1;i++) {
if(is_delim(string[i]) || string[i]==0) {
int wordLength= i-wordStart;
if(wordLength>0)
wl[wordLength]++;
if(wordLength>maxLength)
maxLength= wordLength;
wordStart= i+1;
}
if(string[i]==0)
break;
}
for(i=1;i<=maxLength;i++) {
if(wl[i]>0) {
printf("%d words of length %d.\n",wl[i],i);
}
}
You really should use strtok for this. Right now, you never compare the last string with the current one so you can't tell them apart. You can use strcmp for this. Finally instead of manually testing the length of the string you should use strlen. Here is how your loop could look like
int seen = 0;
pch = strtok(string, delim);
last = pch;
while(pch != NULL) {
if(strcmp(last, pch) != 0) {
printf("%s:\t%d\t\t%d\n", last, (int)strlen(last), seen);
seen = 1;
}else {
seen++;
}
last = pch;
pch = strtok(NULL, delim);
}
printf("%s:\t%d\t\t%d\n", last, (int)strlen(last), seen);
Note, you should set the variable seen to 0 before the loop.

Resources