Reading elements from a string in C - c

I am trying to print the first letter of a word at the position entered by the user. If there is a whitespace, then it will just stop searching. There is a warming message concerning funtion gets(). I have problems with the pointers and funtion, it just does not return the letter. I think the porblem might be on the while loop. Function firstLetter prints the first letter of a word. For instance, if the user enters index 5 of a previously entered string, and in str[5] corresponds to the 'e' of the word 'ice-cream' then the firstLetter will search for the first letter of that word, in this case it will return 'i'.
#include <stdio.h>
#include <string.h>
int firstLetter(int , char *);
int main()
{
char str[200];
printf("Insert line: ");
gets(str);
int pstn;
scanf("%i,&pstn");
firstLetter(pstn, str);
return 0;
}
int firstLetter(int i, char *str)
{
if(str[i]=' ')
{
printf("No letters at this position");
}
else
{
while(str[i]!=' ')
{
i--;
}
printf("First letter: %c ",str[i+1]);
}
return 0;
}

For starters in this line
scanf("%i,&pstn");
you have a typo. At least you need to rewrite it like
scanf("%i",&pstn);
Also within the function firstLetter there is also a typo in the if statement
if(str[i]=' ')
where you are using the assignment operator = instead of the comparison operator ==.
The function gets is unsafe and is not supported by the C Standard.
Instead use the function fgets
fgets( str, sizeof( str ), stdin );
The variable pstn should have the unsigned integer type size_t. Otherwise the user can enter a negative number.
Also you need to check that the entered position is not greater than the length of the string.
For example
size_t pstn = 0;
scanf("%zu", &pstn);
if ( pstn < strlen( str ) ) firstLetter(pstn, str);
The function parameter should have the qualifier const because the passed string is not changed within the function
Also the function has a bug because in this while loop
while(str[i]!=' ')
{
i--;
}
there is no check whether i is less than 0.
Also the return type int of the function is useless.
The function can be declared and defined the following way
void firstLetter( const char *str, size_t i )
{
if ( str[i] == ' ' )
{
printf("No letters at this position");
}
else
{
while( i != 0 && str[i-1] != ' ' )
{
i--;
}
printf("First letter: %c\n", str[i] );
}
}
So in main the function is called like
size_t pstn = 0;
scanf("%zu", &pstn);
if ( pstn < strlen( str ) ) firstLetter( str, pstn );
Or you can make the check that the specified position in the string is less than the length of the string within the function as for example
void firstLetter( const char *str, size_t i )
{
if ( !( i < strlen( str ) ) || str[i] == ' ' )
{
printf("No letters at this position");
}
else
{
while( i != 0 && str[i-1] != ' ' )
{
i--;
}
printf("First letter: %c\n", str[i] );
}
}
In this case the function is called like
size_t pstn = 0;
scanf("%zu", &pstn);
firstLetter( str, pstn );
Instead of the comparison with the space character ' ' you could compare with the space character ' ' and the tab character '\t' using the standard C function isblank declared in the header <ctype.h>. For example
#include <string.h>
#include <ctype.h>
void firstLetter( const char *str, size_t i )
{
if ( !( i < strlen( str ) ) || isblank( ( unsigned char )str[i] ) )
{
printf("No letters at this position");
}
else
{
while( i != 0 && !isblank( ( unsigned char )str[i-1] ) )
{
i--;
}
printf("First letter: %c\n", str[i] );
}
}

Related

What is the data type of text[i]?

I'm trying to count the number of words in a string entered by the user with this custom function:
int count_words(char* text)
{
int wc = 0;
for(int i = 0,k = strlen(text); i<k;i++)
{
if(strcmp(" ",text[i]) ==0 || strcmp(".",text[i]) ==0 || strcmp("!",text[i]) ==0 || strcmp("?",text[i]) ==0 || strcmp(",",text[i]) ==0)
{
wc++;
}
}
return wc+1;
}
but I keep getting this error:
re.c:59:21: error: incompatible integer to pointer conversion passing 'char' to parameter of type 'const char *'; take the address with & [-Werror,-Wint-conversion]
if(strcmp(" ",text[i]) ==0 || strcmp(".",text[i]) ==0 || strcmp("!",text[i]) ==0 || strcmp("?",text[i]) ==0 || strcmp(",",text[i]) ==0)
^~~~~~~
&
re.c:59:48: error: incompatible integer to pointer conversion passing 'char' to parameter of type 'const char *'; take the address with & [-Werror,-Wint-conversion]
if(strcmp(" ",text[i]) ==0 || strcmp(".",text[i]) ==0 || strcmp("!",text[i]) ==0 || strcmp("?",text[i]) ==0 || strcmp(",",text[i]) ==0)
^~~~~~~
&
What is really happening?
strcmp takes char * (string) not a single char. It's better if you use strtok` to count the number of words in a string.
Here's a simple example
#include <stdio.h>
#include <string.h>
int main(void) {
char arr[] = "Temp hello bye! No way. Yes";
char *delimeters = " !.";
char *token = strtok(arr, delimeters);
int count = 0;
while (token != NULL) {
count++;
token = strtok(NULL, delimeters);
}
printf("Words = %d", count);
return 0;
}
You can use strpbrk instead of strtok as well.
strcmp takes an array of char which is end with NULL '\0'.
For your question, you need to increment number of words when you find your special characters.
and you should check there is no repeated special char respectively.
/*const special_char[] = {' ','.','!','?',','};*/
int count_words(char* text)
{
uint32_t idx = 0;
int wc = 0;
/*if the first char equal one of special char, don't count that as word*/
for (int i = 1; i < strlen(text); i++)
{
/*Special char shouldn't be repeated respectively otherwise, don't count that as word*/
if (
((' ' == text[i]) || ('.' == text[i]) || ('!' == text[i]) || ('?' == text[i]) || (',' == text[i]))
&&
((' ' != text[i - 1]) && ('.' != text[i - 1]) && ('!' != text[i - 1]) && ('?' != text[i - 1]) && (',' != text[i - 1]))
)
{
wc++;
}
}
/*For the last word*/
wc++;
return wc;
}
The function strcmp is declared the following way
int strcmp(const char *s1, const char *s2);
As you can see the both parameters of the function have the pointer type const char *.
But in this call of the function used by you
strcmp(" ",text[i])
the second argument has the type char. So the compiler issues the error message.
error: incompatible integer to pointer conversion passing 'char' to
parameter of type 'const char *';
Also your function has logical bugs. For example for an empty string it returns the number of words equal to 1.
return wc+1;
And each separator it counts as a word. So for a string that contains only separators the function interprets it as containing several words.
Apart from this the function count_words shall not change the passed string. It should be declared like
size_t count_words( const char *text );
The function can be defined the following way as it is shown in the demonstration program below.
#include <stdio.h>
#include <string.h>
size_t count_words( const char *text )
{
const char *separators = " \t.,!?";
size_t n = 0;
while ( *text )
{
text += strspn( text, separators );
if ( *text )
{
++n;
text += strcspn( text, separators );
}
}
return n;
}
int main(void)
{
const char *text = "We, beginners, should help each other!";
printf( "There are %zu words in the text \"%s\".", count_words( text ), text );
return 0;
}
The program output is
There are 6 words in the text "We, beginners, should help each other!".
A more general approach is when the user of the function can call it specifying by himself required separators of words. For example
#include <stdio.h>
#include <string.h>
size_t count_words( const char *text, const char *separators )
{
size_t n = 0;
while ( *text )
{
text += strspn( text, separators );
if ( *text )
{
++n;
text += strcspn( text, separators );
}
}
return n;
}
int main(void)
{
const char *text = "We, beginners, should help each other!";
printf( "There are %zu words in the string \"%s\".", count_words( text, " \t.,!?" ), text );
return 0;
}
The program output is the same as shown above
There are 6 words in the text "We, beginners, should help each other!".

Make a c program that will tell if a string is a palindrome(read the same way both ways) until BYE is encountered

Everything is working in my code but as soon as user inputs "BYE" my program is not ending i don't know why while loop is not responding to that code
#include "stdio.h"
#include <string.h>
int main(void)
{
char ch[20];
while (ch != "bye")
{
scanf("%s", ch);
int i;
int n = strlen(ch);
int c = 0;
for (i = 0; i < n / 2; i++)
{
if (ch[i] == ch[n - i - 1])
c++;
}
if (c == i)
{
printf("1");
}
else
{
printf("0");
}
}
return 0;
}
For starters the array ch was not initialized that is initially it does not contain a string
char ch[20];
Secondly in the condition of the while loop
while (ch != "bye")
there are compared two addresses: the address of the first element of the array ch and the address of the first element of the string literal "bye". As the array and the string literal occupy different extents of memory the addresses always will be unequal. So as a result you have an infinite loop that does not contain a break statement.
If you want to compare strings then you need to use the standard string function strcmp as for example
if ( strcmp( ch, "bye" ) == 0 )
{
//...
}
In this case the array ch shall already contain a string.
So instead of the while statement it is better to use do-while statement or an infinite while statement that will be interrupted through the break statement if strcmp will return 0.
For example
while ( 1 )
{
char ch[20];
scanf("%19s", ch );
if ( strcmp( ch, "bye" ) == 0 ) break;
size_t n = strlen(ch);
size_t i = 0;
while ( i < n / 2 && ch[i] == ch[n - i - 1] ) ++i;
if ( i == n / 2 )
{
printf("1");
}
else
{
printf("0"); }
}
}

pallindrome program not working please check attached the code and the output

i have tried to make a program to check the pallindrome manually on paper it should work
but it doesnt.
i have attached the output with the code
#include <stdio.h>
#include <string.h>
#include <conio.h>
#include <stdlib.h>
void main()
{
char str[100];
int i,l,k;
printf("type the desired to string to check pallindrome\n");
gets(str);
l=strlen(str);
printf("%d\n", l);
k=l-1;
char temp[100];
for(i=0;i<l;i++)
{
temp[k]=str[i];
--k;
}
if(strcmp(temp, str)==0)
{
printf("pallindrome\n");
}
else
{
printf("not a pallindrome\n");
}
}
here is the output
[1]: https://i.stack.imgur.com/dERFQ.png
You need to append the NUL terminator at the end of temp right after the for loop:
for(i=0;i<l;i++)
{
temp[k]=str[i];
--k;
}
temp[i] = '\0';
Otherwise, the strcmp function will cause UB.
For starters according to the C Standard the function main without parameters shall be declared like
int main( void )
The array temp does not contain a string because you forgot to append it with the terminating zero character '\0'.
So the call of the strcmp
if(strcmp(temp, str)==0)
results in undefined behavior.
Also the function gets is unsafe and is not supported by the C Standard. Instead use the function fgets.
Also to check whether a string is a palindrome there is no need to declare an auxiliary array.
The code can look like
printf("type the desired to string to check pallindrome\n");
fgets(str, sizeof( str ), stdin );
str[strcspn( str, "\n" )] = '\0'; // to remove the new line character '\n'
size_t n = strlen( str );
printf( "%zu\n", n );
size_t i = 0;
while ( i < n / 2 && str[i] == str[n-i-1] ) ++i;
if( i == n / 2 )
{
printf("pallindrome\n");
}
else
{
printf("not a pallindrome\n");
}
You could write a separate function that checks whether a string is a palindrome.
Here you are.
#include <stdio.h>
#include <string.h>
int is_palindrome( const char *s )
{
size_t n = strlen( s );
size_t i = 0;
while ( i < n / 2 && s[i] == s[n-i-1] ) ++i;
return i == n / 2;
}
int main(void)
{
enum { N = 100 };
char s[N];
printf( "Type a desired string to check whether it is a palindrome: " );
fgets( s, sizeof( s ), stdin );
s[ strcspn( s, "\n" ) ] = '\0';
if ( is_palindrome( s ) )
{
printf( "\"%s\" is a palindrome.\n", s );
}
else
{
printf( "\"%s\" is not a palindrome.\n", s );
}
return 0;
}
The program output might look like
Type a desired string to check whether it is a palindrome: abcdedcba
"abcdedcba" is a palindrome

Find the length of the longest word in a string. C language

Problem: I can't seem to get my test case 4 to work.
Question:
Write a C function that accepts an English sentence as a parameter, and returns the length of the longest word in the sentence. For example, if the sentence is "I am Tim.", then the length of the longest word "time" in sentence 3 will be returned.
Test Case 1:
Enter a string: I am lee.
longWordLength(): 3
Test Case 2:
Enter a string: There are two disciples in the class.
longWordLength(): 9
Test Case 3:
Enter a string: Good night!
longWordLength(): 5
Test Case 4:
Enter a string: Jovial
longWordLength(): 6
This is the code I have so far:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int longWordLength(char *s);
int main()
{
char str[80], *p;
printf("Enter a string: \n");
fgets(str, 80, stdin);
if (p=strchr(str,'\n')) *p = '\0';
printf("longWordLength(): %d\n", longWordLength(str));
return 0;
}
int longWordLength(char *s)
{
int i, count, max;
max = 0;
count = 0;
while( *(s) != '\0' )
{
if ( *(s) != '\0' && *(s) != ' ' && *(s) != '.' )
{
count++;
printf("current count is %d\n", count);
}
else
{
if(count>max)
{
max = count;
printf("There is a new max! It is %d\n", max);
count = 0;
}
count = 0;
printf("count is resetted!\n");
}
s++;
printf("reach the end of the while loop\n");
}
printf("current max outside while loop is: %d\n", max);
printf("exited\n");
return max;
}
Problem:
Your code does not work when the key word is at the end of a line.
That is because your max is updated inside that while loop and the while loop terminates when the null character is found. Since the null character is always appended to the end of your input string, the last word in a string does not contribute to the output. In this edge case, the loop does not give a chance to execute that else block in the final iteration.
In fact, your code will pass only Test Case 2 because all other cases contain the key word at the end of the input string.
Solution:
Even if you rectify that, your code may still fail if the sentence contains a punctuation mark other than the period.
For example: "Test Case!"
The new code will count "Case!" as a word of length 5 which is greater than the length of "Test" or "Case", and give a wrong answer.
You may look into some library functions that C has to offer in order to help you pass all edge cases.
If you need more assistance, I have made the required modifications to your code:
while( *(s) != '\0' )
{
// if ( *(s) != '\0' && *(s) != ' ' && *(s) != '.' )
// Why check the null character again?
// Spaces and period will not be the only punctuation marks
// You can check for all punctuation marks using ispunct() from <ctype.h>
if (!isspace(*s) && !ispunct(*s))
{
count++;
printf("current count is %d\n", count);
// You can update max here
if(count > max)
{
max = count;
printf("There is a new max! It is %d\n", max);
}
}
/*
Now you can eliminate this block of code
else
{
if(count>max)
{
max = count;
printf("There is a new max! It is %d\n", max);
count = 0;
}
count = 0;
printf("count is resetted!\n");
}
*/
// You can reset count after all that
else
{
count = 0;
printf("count is resetted!\n");
}
s++;
printf("reach the end of the while loop\n");
}
The code assumes that the input will be a proper English sentence.
P. S. This answer earned me the 1K reputation :)
For starters the function parameter should be declared with the qualifier const because within the function the passed string is not being changed. And the function return type should be size_t. It is the return type of the function strlen or the type of the value returned by the sizeof operator.
size_t longWordLength( const char *s);
The last word of a string does not take part in the calculation of the maximum word because the loop stops its iterations as soon as the next character is the terminating zero character '\0'.
It will be a bad idea to process the size of the last word outside the loop. All processing should be done within the loop.
Also your function does not take into account punctuation characters except the point.
For example for a sentence like this "How are you?" your function will give incorrect result.
Instead of checking each character whether it is for example a blank or not you could use standard C functions like strspn and strcspn.
Here is a demonstrative program that shows how the function can be implemented.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
size_t longWordLength( const char *s )
{
const char *delim = " \t";
size_t max = 0;
while ( *s )
{
s += strspn( s, delim );
if ( *s )
{
const char *first = s;
s += strcspn( s, delim );
const char *last = s;
while ( last != first && ispunct( ( unsigned char )*( last - 1 ) ) )
{
--last;
}
if ( max < last - first ) max = last - first;
}
}
return max;
}
int main(void)
{
const char *s = "Why are not you using string functions?!";
printf( "The size of the longest word is %zu\n", longWordLength( s ) );
return 0;
}
The program output is
The size of the longest word is 9
Another approach is to write two functions similar to strspn and strcspn that deal with blank and punctuation symbols.
Here is a demonstrative program.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
size_t count_non_alpha( const char *s )
{
size_t n = 0;
while ( isblank( ( unsigned char )s[n] ) || ispunct( ( unsigned char )s[n] ) )
{
++n;
}
return n;
}
size_t count_alpha( const char *s )
{
size_t n = 0;
while ( s[n] && !isblank( ( unsigned char )s[n] ) && !ispunct( ( unsigned char )s[n] ) )
{
++n;
}
return n;
}
size_t longWordLength( const char *s )
{
size_t max = 0;
while ( *s )
{
s += count_non_alpha( s );
if ( *s )
{
const char *first = s;
s += count_alpha( s );
if ( max < s - first ) max = s - first;
}
}
return max;
}
int main(void)
{
const char *s = "Why are not you using string functions?!";
printf( "The size of the longest word is %zu\n", longWordLength( s ) );
return 0;
}
The program output is the same as shown above.
Please refer to my comment to your original question.
You can resolve your problem by adding the following code, after your while loop.
if (*(s - 1) != ' ' && *(s - 1) != '.' )
{
if(count>max)
{
max = count;
printf("There is a new max! It is %d\n", max);
}
}
The code checks the last character in the input string. If it is not a word terminating character, then you didn't compare the last word with the current max in the loop and hence you do it after the loop completes.
use isalpha() to check the kind of character
don't forget to count the final word if it is followed by a '\0'
#include <stdio.h>
#include <ctype.h>
unsigned longest_word(char *str)
{
unsigned length,longest;
for(longest=length = 0; ; str++) {
if (isalpha(*str)) { length++; continue; }
if (length > longest) longest = length;
length = 0;
if (!*str) break;
}
return longest;
}
int main(void)
{
char * string1 = "The longest word is short";
char * string2 = "The longest word is unbelievable";
printf("%s: %u\n", string1, longest_word( string1) );
printf("%s: %u\n", string2, longest_word( string2) );
return 0;
}

Understanding that scanf is doing in this code

Please help me in understanding the below code.
The function get_digit takes a character argument by address. I am unable to get what
scanf("%1[0123456789]", ch) does here.
If I give 1234 on the terminal then it takes only the first digit. Same is if I give 2345 it takes 2. I have never came across such usage of scanf. Please help me in understanding this feature.
int get_digit ( char *ch )
{
int rc;
printf ( "Enter a single digit: " );
fflush ( stdout );
if ( rc = scanf ( "%1[0123456789]", ch ) == 1 ) {
jsw_flush();
}
return rc;
}
void jsw_flush ( void )
{
int ch;
do
ch = getchar();
while ( ch != '\n' && ch != EOF );
clearerr ( stdin );
}
void fill_table ( char table[] )
{
char ch;
while ( get_digit ( &ch ) ) {
unsigned i = ch - '0';
if ( table[i] != 0 ) {
printf ( "That index has been filled\n" );
}
else {
table[i] = ch;
}
}
}
void show_table ( const char table[], size_t size )
{
size_t i;
for ( i = 0; i < size; i++ ) {
printf ( "%c\n", table[i] != 0 ? table[i] : '~' );
}
}
scanf ( "%1[0123456789]", ch ) scans 1 character (%1) which is a decimal digit ([0123456789]) int the characer pointed to by ch.
The number immediately following the % is the field width, how many characters (maximally) to scan. The characters inside the square brackets are the characters scanf will accept. The scan ends when a character not listed is encountered.
An extremely simple example to scan two-digit numbers:
#include <stdlib.h>
#include <stdio.h>
int main(void) {
char chs[2] = {0}; // space for two digits, zero-initialized
unsigned u = 0, i;
if (scanf("%2[0123456789]",&chs[0]) == 1) {
// parse the number
for(i = 0; i < 2 && chs[i]; ++i) {
u = 10*u + chs[i] - '0';
}
printf("Got %u\n",u);
} else {
puts("Scan failed.");
}
return EXIT_SUCCESS;
}
Of course, instead of parsing ourselves, we could make the character array one longer than we expect digits (zero-initialise!, scanf doesn't add a 0-terminator with that format) and leave the parsing to strtoul(chs,NULL,10).

Resources