Adding scanf and EOF to program - c

#include <stdio.h>
#include <string.h>
int main()
{
char string[100];
int c = 0, count[26] = {0};
int accum = 0;
printf("Enter a string\n");
gets(string);
while ( string[c] != '\0' )
{
if ( string[c] >= 'a' && string[c] <= 'z' ){
count[string[c]-'a']++;
accum++;
}
else if (string[c] >= 'A' && string[c] <= 'Z'){
count[string[c]-'A']++;
accum++;
}
c++;
}
for ( c = 0 ; c < 26 ; c++ )
{
if( count[c] != 0 )
printf( "%c %f\n", c+'a', ((double)count[c])/accum);
}
return 0;
}
This should be an easy question, but I can't seem to get it to work. Right now, I have the print statement "Enter a string". I want to change it so that the user can keep inputting a string using scanf instead of printf until EOF is reached. Basically I want to remove the "Enter a string" statement and just have input a string until EOF and then have the letter frequency run once on all the strings inputted. How would I do that?

To do this using scanf() for input.
scanf() returns EOF when the EOF condition or IO error occurs.
// printf("Enter a string\n");
char ch;
while (scanf("%c", &ch) == 1) {
if ( ch >= 'a' && ch <= 'z' ){
count[ch-'a']++;
accum++;
}
...
}
Using int ch = fgetc(stdin) would make more sense.
"The fscanf function returns the value of the macro EOF if an input failure occurs
before the first conversion (if any) has completed. Otherwise, the function returns the
number of input items assigned, which can be fewer than provided for, or even zero, in
the event of an early matching failure." C11dr ยง7.21.6.2 16

Add your printf and gets statements inside the while loop
printf("Enter a string\n");
gets(string);
while ( string[c] != '\0' )
{
...//remaining code inside while loop
printf("Enter a string\n");
gets(string);
}
... //for loop code and return 0;

Here you go. I zeroed the variables for each loop. And I treated a blank entry (just press Enter) as EOF. But if you wanted the statistics for all the strings, don't zero the values at the start of the while loop
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char string[100];
int c = 0, count[26] = {0};
int accum = 0;
do {
c = 0;
accum = 0;
memset (count, sizeof count, 0);
gets(string);
if (strlen (string) < 1)
break; // terminate
while ( string[c] != '\0' ) {
if ( string[c] >= 'a' && string[c] <= 'z' ) {
count[string[c]-'a']++;
accum++;
}
else if (string[c] >= 'A' && string[c] <= 'Z') {
count[string[c]-'A']++;
accum++;
}
c++;
}
for ( c = 0 ; c < 26 ; c++ ) {
if( count[c] != 0 )
printf( "%c %f\n", c+'a', ((double)count[c])/accum);
}
}
while (1);
return 0;
}

Related

How to have a function output a string, not just the first word

I'm writing a function to capitalize every lowercase character in a string. It takes a string from the user and that is the input to the function. My program works if the user doesn't enter spaces, but when there is a space in the string, the function ends.
#include <stdio.h>
char *uppercase(char *c) {
int i = 0;
while (c[i] != '\0') {
if (123 > c[i] && c[i] > 96)
c[i] = c[i] - 'a' + 'A';
i++;
}
return c;
}
int main() {
char input[100];
printf("Enter the phrase: ");
scanf("%s", input);
printf("%s", uppercase(input));
return 0;
}
Examples:
Input: test test
Output: TEST
Input: Hello
Output: HELLO
Input: How are you
Output: HOW
I think it has to do with the while statement? Thanks for the help.
The problem is not in the while statement, but rather due to the scanf() format: %s reads a single word from the input, leaving the rest of the line in the stdin buffer. Note also that typing a word with more than 99 characters will cause undefined behavior because scanf() will write beyond the end of the input array. Using %99s would prevent this problem, but not solve your issue.
You should use fgets() to read a full line of input from stdin.
Furthermore, instead of using hard coded ASCII values, you should use character constants such as 'a' and 'z' or the functions from <ctype.h>.
Here is a modified version using ASCII:
#include <stdio.h>
char *uppercase(char *s) {
int i = 0;
while (s[i] != '\0') {
if (s[i] >= 'a' && s[i] <= 'z')
s[i] = s[i] - 'a' + 'A';
i++;
}
return s;
}
int main() {
char input[100];
printf("Enter the phrase: ");
if (fgets(input, sizeof input, stdin)) {
fputs(uppercase(input), stdout);
}
return 0;
}
Here is a more portable one using <ctype.h>:
#include <ctype.h>
#include <stdio.h>
char *uppercase(char *s) {
int i = 0;
unsigned char c;
while ((c = s[i]) != '\0') {
if (islower(c))
s[i] = toupper(c);
i++;
}
return s;
}
This can be further simplified as toupper() can be called for all byte values from 0 to UCHAR_MAX:
#include <ctype.h>
#include <stdio.h>
char *uppercase(char *s) {
for (size_t i = 0; s[i] != '\0'; i++) {
s[i] = toupper((unsigned char)c);
}
return s;
}
Either use
scanf ("%99[^\n]", input);
or
fgets( input, sizeof( input ), stdin );
Also it is a bad practice to use magic numbers like 123 or 96
if (123 > c[i] && c[i] > 96)
The code will be more readable if you will write at least
if ( 'a' <= c[i] && c[i] <= 'z' )
Also instead of the while loop it is better to use the for loop like
for ( char *p = c; *p; ++p )
{
if ( 'a' <= *p && *p <= 'z' )
{
*p = *p - 'a' + 'A';
}
}

Can C presume which array I want to store my characters?

I'm writing code which checks if an array is palindrome or not:
Write a program that reads a message, then checks whether it's a palindrome
(the letters in the message are the same from left to right as from right to left):
Enter a message: He lived as a devil, eh?
Palindrome
Enter a message: Madam, I am Adam.
Not a palindrome
When I have entered He lived as a devil, eh?,
it gives me the output Not a palindrome,
but the real output should be palindrome.
Below code is what I have tried so far.
#include <stdio.h>
#include <ctype.h>
#define MAX_LEN 100
int main(void) {
char message[MAX_LEN];
char c, *p = message, *q;
printf("Enter a message: ");
while ((c = toupper(getchar())) != '\n' & p < message + MAX_LEN) {
if (isalpha(c))
*p++ = c;
}
p--;
for (q = message; q < p; q++, p--) {
if (*p != *q) {
printf("Not a palindrome\n");
return 0;
}
}
printf("Palindrome\n");
return 0;
}
For starters you should declare the variable c as having the type int. The user can interrupt the input process in which case the function getchar returns integer value EOF and you should check whether this occurred.
char *p = message, *q;
int c;
There is a bug in the condition of the while statement
while ((c = toupper(getchar())) != '\n' & p < message + MAX_LEN) {
Instead of the bitwise operator & you have to use the logical AND operator &&.
As I already have said you should check in the condition of the while statement whether the user interrupted the input. For example
while ( p < message + MAX_LEN && ( c = toupper(getchar())) != EOF && c != '\n') {
if (isalpha(c))
*p++ = c;
}
The argument of a call of toupper or isalpha should be converted to the type unsigned char. Otherwise in general without the casting such a call can invoke undefined behavior.
It is desirable not to exclude from an entered string numbers. SO it is better at least to call the function isalnum instead of the function isalpha.
The user can enter an empty string in this case this decrement of the pointer
p--;
also can invoke undefined behavior.
And it is better when a program has one point to exit.
The program can look the following way
#include <stdio.h>
#include <ctype.h>
#define MAX_LEN 100
int main(void)
{
char message[MAX_LEN];
printf( "Enter a message: " );
char *p = message;
for ( int c; p < message + MAX_LEN && ( c = getchar() ) != EOF && c != '\n'; )
{
if( isalnum( ( unsigned char )c ) )
{
*p++ = toupper( ( unsigned char )c );
}
}
int palindrome = 1;
if ( p != message )
{
for ( char *q = message; palindrome && q < --p; ++q )
{
palindrome = *q == *p;
}
}
printf( "The entered message is %spalindrome\n",
palindrome ? "" : "not " );
return 0;
}
Its output might look for example like
Enter a message: He lived as a devil, eh?
The entered message is palindrome
or like
Enter a message: Madam, I am Adam
The entered message is not palindrome
Pay attention to that instead of using a loop with numerous calls of the function getchar you could use only one call of the function fgets
fgets( message, sizeof( message ), stdin );
or
if ( fgets( message, sizeof( message ), stdin ) != NULL )
{
// check whether the entered string is a palindrome
}
Before check the palindrome you have to remove white spaces and punctuation marks. For an example if you use civic?, it is not palindrome because of ?. In the other hand if you use civ ic, it is not palindrome because of white space. There for
Convert all letters to uppercase or lowercase.
Remove white spaces.
remove punctuation marks.
Check palindrome or not.
You can do it by using # include <string.h>
First thing is you have to use scanf() which accept string with white space.
printf("Enter a string = ");
scanf("%[^\n]%*c", word);
Then you have to convert that string to Uppercase or Lowercase because a != A. We know civic is a palindrome but Civic is not a palindrome('Civic != civiC) because Uppercase letters have different ASCII values and Lowercase letters have different ASCII values.
(a - z) -: 97 - 122
(A - Z) -: 65 - 90
In my case I have converted lowercase to uppercase.
while(strlen(word) >= i)
{
if(word[i] >= 97 && word[i] <= 122)
{
word[i] = word[i] - 32;
}
i++;
}
Another case is your if you enter civ ic with white space, it's palindrome word is ci vic. You can see civ ic != ci vic. There for you have to remove white spaces in your program. And also you have to remove punctuation marks because if you use civic, it's reversed word is ,civic'. You can seecivic, != ,civic`.
int len = strlen(word);
while(a < len)
{
for(i = 0; i < len; i++)
{
if(word[i] == ' ' || !(word[i] >= 'A' && word[i] <= 'Z'))
{
for(j = i; j < len; j++)
{
word[j] = word[j+1];
}
len--;
}
}
a++;
}
Final thing is we have to revers our string and need to check if our reversed string is equal to our original string. If it is true our String is palindrome. If it is false our String is not a palindrome.
for(i = 0; i < len; i++)
{
if(word[i] == word[len - 1])
{
len--;
}
else
{
printf("%s is not a palindrome\n", word);
return 0;
}
}
printf("%s is a palindroeme\n", word);
This the full code after you merging above parts
# include <stdio.h>
# include <string.h>
int main (void)
{
char word[100];
int i = 0;
int j, x = 0;
int a = 0;
printf("Enter a string = ");
scanf("%[^\n]%*c", word);
while(strlen(word) >= i)
{
if(word[i] >= 97 && word[i] <= 122)
{
word[i] = word[i] - 32;
}
i++;
}
printf("After converting it to uppercase = %s\n", word);
int len = strlen(word);
while(a < len)
{
for(i = 0; i < len; i++)
{
if(word[i] == ' ' || !(word[i] >= 'A' && word[i] <= 'Z'))
{
for(j = i; j < len; j++)
{
word[j] = word[j+1];
}
len--;
}
}
a++;
}
printf("After removing spaces = %s\n", word);
for(i = 0; i < len; i++)
{
if(word[i] == word[len - 1])
{
len--;
}
else
{
printf("%s is not a palindrome\n", word);
return 0;
}
}
printf("%s is a palindroeme\n", word);
return 0;
}
First test Output -:
Enter a string = He lived as a devil, eh?
After converting it to uppercase = HE LIVED AS A DEVIL, EH?
After removing spaces = HELIVEDASADEVILEH
HELIVEDASADEVILEH is a palindroeme
Second test Output -:
Enter a string = Madam I am Adam.
After converting it to uppercase = MADAM I AM ADAM.
After removing spaces = MADAMIAMADAM
MADAMIAMADAM is not a palindrome

Calculating the Character frequency in a String using C

I have written a program to calculate the character frequency in a string entered by the user. It's giving correct output for all lower case letters but it's not working for upper case letters. I am unable to find the problem in the code:
#include <stdio.h>
#include <string.h>
int main()
{
char string[100];
int c = 0, count[26] = {0};
printf("Enter a string\n");
fgets(string,100,stdin);
while(string[c] != '\n') {
c++;
}
string[c] = '\0';
c = 0;
while (string[c] != '\0')
{
/** Considering characters from 'a' to 'z' only
and ignoring others */
if (string[c] >= 'a' && string[c] <= 'z')
count[string[c]-'a']++;
else if(string[c] >= 'A' && string[c]<= 'Z')
count[string[c]-'A']++;
c++;
}
for (c = 0; c < 26; c++)
{
/** Printing only those characters
whose count is at least 1 */
if (count[c] != 0)
printf("%c occurs %d times in the entered string.\n",c+'a',count[c]);
}
return 0;
}
Please Help!
Here is the screenshot. Hopefully you will understand what problem I am facing:
It's not counting the upper case letters.
The only issue that I can see is bounds...
EDIT
This can be entirely skipped since fgets() ensures a trailing '\0' and you handle '\n' gracefully later in your checks.
while(string[c] != '\n') {
c++;
}
string[c] = '\0';
To remove the '\n' it should be
while(string[c] && string[c] != '\n') {
c++;
}
string[c] = '\0';
and
while (string[c] != '\0')
is good because of the semantics of fgets().
It works fine, but the output may be confusing you!
For the input string "Foo", the output is this:
f occurs 1 times in the entered string.
o occurs 2 times in the entered string.
Lower and uppercase are counted together, so you don't see "F occurs 1 times".
http://ideone.com/ACJnPD
IGuessing that the problem is to separate count of Upper and Lower case character you could use different arrays to count frequencies:
#include <stdio.h>
#include <string.h>
int main()
{
char string[100];
int c = 0, countLower[26] = {0};
int countUpper[26] = {0};
printf("Enter a string\n");
fgets(string,100,stdin);
while((string[c] != '\0') && (string[c] != '\n')) {
c++;
}
string[c] = '\0';
c = 0;
while (string[c] != '\0')
{
/** Considering characters from 'a' to 'z' only
and ignoring others */
if (string[c] >= 'a' && string[c] <= 'z')
countLower[string[c]-'a']++;
else if(string[c] >= 'A' && string[c]<= 'Z')
countUpper[string[c]-'A']++;
c++;
}
for (c = 0; c < 26; c++)
{
/** Printing only those characters
whose count is at least 1 */
if (countLower[c] != 0)
printf("%c occurs %d times in the entered string.\n",c+'a',countLower[c]);
if (countUpper[c] != 0)
printf("%c occurs %d times in the entered string.\n",c+'A',countUpper[c]);
}
return 0;
}

Program that counts Uppercase and Lowercase letters in a String in C

so I want to make a code where you can find the number of upper and lowercase letters in a string (no spaces)
So I want something like this:
input:
HEllO
Output:
2 3
So what I have of code is this:
#include<stdio.h>
int main() {
int upper = 0, lower = 0;
char ch[80];
int i;
printf("\nEnter The String : ");
gets(ch);
i = 0;
while (ch[i] != '') {
if (ch[i] >= 'A' && ch[i] <= 'Z')
upper++;
if (ch[i] >= 'a' && ch[i] <= 'z')
lower++;
i++;
}
printf("%d %d", upper, lower);
return (0);
}
There is a problem with the code, but I cannot find the mistake. Can someone please fix it? Thanks.
Corrected code-
#include <stdio.h>
int main(void)
{
int upper = 0, lower = 0;
char ch[80];
int i = 0;
printf("\nEnter The String : ");
fgets(ch, sizeof(ch), stdin);
while (ch[i] != '\0')
{
if (ch[i] >= 'A' && ch[i] <= 'Z')
upper++;
if (ch[i] >= 'a' && ch[i] <= 'z')
lower++;
i++;
}
printf("\nuppercase letter(s): %d \nlowercase letter(s): %d", upper, lower);
return 0;
}
Note: I have used fgets() instead of gets() as the latter suffers from a buffer overflow issue.
In C a string always terminates with '\0'. The empty string '' and the escape null character are not identical.
while (ch[i] != '') should be while (ch[i] != '\0')
Your program should work then.
The problem is the expression ''. A character constant must have something between the single quotes. In this case, you want to test for end of string, so you would use the null character constant: '\0'.
#include <stdio.h>
int main(void) {
int upper = 0, lower = 0;
char ch[80];
int i;
printf("\nEnter The String : ");
fgets(ch, sizeof(ch), stdin);
i = 0;
while (ch[i] != '\0') {
if (ch[i] >= 'A' && ch[i] <= 'Z')
upper++;
if (ch[i] >= 'a' && ch[i] <= 'z')
lower++;
i++;
}
printf("%d %d\n", upper, lower);
return 0;
}
Note that I also replaced gets with fgets. You should never use gets(). It doesn't get passed the length of your buffer, so if the input is more than 79 characters long, it will overflow the ch array, causing undefined behavior. fgets takes a size argument and stops reading once it's read size - 1. It also includes the newline in the resulting string if one is present in the input, which gets does not.
A better approach that works properly for all input lengths is to read the string in one character at a time, and not bother storing it, since all you care about is the count of upper and lower.
#include <stdio.h>
int main(void) {
unsigned upper = 0, lower = 0;
printf("\nEnter The String : ");
int c;
while (EOF != (c = getchar())) {
if ('\n' == c) break;
if (c >= 'A' && c <= 'Z')
upper++;
if (c >= 'a' && c <= 'z')
lower++;
}
printf("%u %u\n", upper, lower);
return 0;
}

Checking if string is only letters and spaces

I wrote this simple code to check if a string is letters and spaces only
#include<stdio.h>
#include<conio.h>
#include<math.h>
#include<stdlib.h>
#include<string.h>
#define N 100
int checkString(char str1[]);
void main()
{
char str1[N];
scanf("%s", str1);
printf("%d",checkString(str1));
getch();
}
int checkString(char str1[])
{
int i, x=0, p;
p=strlen(str1);
for (i = 0; i < p ; i++)
{
if ((str1[i] >= 'a' && str1[i] <= 'z') || (str1[i] >= 'A' && str1[i] <= 'Z') || (str1[i] == ' '))
{
continue;
}
else{ return 0; }
}
return 1;
}
This works fine when I type something like :
hello asds //returns 1
hello1010 sasd // return 0
but if I type anything after space it returns 1, like this :
hello 1220 //returns 1
blabla 11sdws // returns 1
Can someone please tell me why?
The function can be written more simpler and correctly if to use standard C functions isalpha and isblank declared in header <ctype.h> For example
#include <ctype.h>
//...
int checkString( const char s[] )
{
unsigned char c;
while ( ( c = *s ) && ( isalpha( c ) || isblank( c ) ) ) ++s;
return *s == '\0';
}
If you want to check whether a string contains white spaces then instead of function isblank you should use function isspace.
Take into account that it is not a good idea to use statement continue in such simple loops. It is better to rewrite the loop without the continue statement.
And instead of function scanf it is better to use function fgets if you want to enter a sentence The function allows to enter several words as one string until the Enter will be pressed.
For example
fgets( str1, sizeof( str1 ), stdin );
Take into account that the function includes the new line character. So after entering a string you should remove this character. For example
size_t n = strlen( str1 );
if ( n != 0 && str1[n-1] == '\n' ) str1[n-1] = '\0';
You forgot about the numbers
int checkString(char str1[]) {
int i, x=0, p;
p=strlen(str1);
for (i = 0; i < p ; i++)
if ((str1[i] >= 'a' && str1[i] <= 'z') || (str1[i] >= 'A' && str1[i] <= 'Z') || (str1[i] == ' ') || (str1[i] >= '0' && str1[i] <= '9')) {
continue;
} else return 0;
return 1;
}
Or better
#include <ctype.h>
...
int checkString(char str1[]) {
int i, x=0, p;
p=strlen(str1);
for (i = 0; i < p ; i++)
if (isalnum(str1[i]) || (str1[i] == ' '))
continue;
else return 0;
return 1;
}
This is happening because you are taking input with scanf(%s,&str). In this way of input only characters before space \n or other whitespace characters are stored. So your when you enter space the input is stored only upto space.
eg, you input helloo 1234
Your str stores only helloo and 1234 remains in buffer. Try using getchar().
#include<stdio.h>
#include<conio.h>
#include<math.h>
#include<stdlib.h>
#include<string.h>
#define N 100
int checkString(char str1[]);
void main()
{
char str1[N];
int i=0;
while(1)
{
str1[i++]=getchar();
if(str1[i-1]=='\n') break;
}
printf("%d",checkString(str1));
getch();
}
int checkString(char str1[])
{
int i, x=0, p;
p=strlen(str1);
for (i = 0; i < p ; i++)
{
if ((str1[i] >= 'a' && str1[i] <= 'z') || (str1[i] >= 'A' && str1[i] <= 'Z') || (str1[i] == ' '))
{
continue;
}
else{ return 0; }
}
return 1;
}
When you use scanf("%s",str1);,you input hello 112,what str1 gets is hello.So you can use fgets(str1,N,stdin); to get the string.I think it will work.
There is a problem with your input String
scanf() which will take your input up to space only as it is whitespace
So when you input as hello 1234 actual input it is checking is hello . Check this by printing what you are taking input (that is print str1). Then you will come to know mistake in this code.
You can use gets or fgets to solve the problem.
if you print back the string you just scanf()ed you will notice that it only gets the first portion of all inputs. i.e. anything after the white space including the white space is ignored.
you could use getch() (windows) or getchar() (linux) to get every char input and terminate when you have a "\n" (newline)
source: http://www.cplusplus.com/reference/cstdio/scanf/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#define N 100
int checkString(char str1[]);
void main()
{
int i = 0;
int c;
char str1[N];
memset(str1, 0, sizeof(str1));
do {
c = getchar();
str1[i++] = c;
} while ((c != '\n') && (i < (N - 1))); // (i < N - 1) reserves one place for null char
// last char is '\n' - remove it.
str1[i-1] = 0;
printf("Result: %s\n", checkString(str1) ? "letters and/or spaces only" : "other characters other than spaces and/or letters present");
}
// expects a null terminated string
int checkString(char str1[])
{
char* p = str1;
while (*p) {
if (!isalpha(*p) && !isspace(*p)) {
return 0;
}
p++;
}
return 1;
}

Resources