Cant read number char frequency - c

#include <stdio.h>
int main() {
FILE *fb;
char data[255];
int c=0;
int count[75] = {0};
fb = fopen("Input.txt", "r");
fgets(data, 255, fb);
/* Start finding frequency*/
while (data[c] != '\0')
{
if( data[c] >= '0' && data[c] <= 'z')
count[data[c] - 'a']++;
c++;
}
for (c = 0; c < 75; 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;
}
Example input file: "Fred Fish 12345678"
I am able to handle space from the input file, but the program does not read Frequency of capital letter as well as number character. What can I change in the program help fixing the problem. After reading the freq, my plan is to save the file so that I can compress using HUffman

#include <stdio.h>
int main() {
FILE *fb;
char data[255];
int c = 0;
int count[75] = { 0 };
fb = fopen("Input.txt", "r");
fgets(data, 255, fb);
/* Start finding frequency*/
while (data[c] != '\0')
{
if (data[c] >= 'a' && data[c] <= 'z') // here you check normal letters
count[data[c] - 'a']++;
else if (data[c] >= 'A' && data[c] <= 'Z')
count[data[c] - 'A' + 26]++; // Capital letters will be stored after lower cases
else if (data[c] >= '0' && data[c] <= '9')
count[data[c] - '0' + 51]++; // Numbers will be stored after capital letters
c++;
}
// count[] is initialized as following :
// From count[0] to count[25] == Occurence of low case characters
// From count[26] to count[51] == Occurence of capital characters
// From count[52] to count[61] == Occurence of numbers from 0 to 9
for (c = 0; c < 61; c++)
{
/** Printing only those characters
whose count is at least 1 */
if (count[c] != 0) {
if (c < 26)
printf("%c occurs %d times in the entered string.\n", c + 'a', count[c]);
// Starting from 'a', iterating until 'z'
else if (c < 52)
printf("%c occurs %d times in the entered string.\n", c + 'A' - 26, count[c]);
// Same as for low case characters
// Substracting 26 because we already have iterated through the first 26 low case characters
// Starting from 'A' until 'Z'
else if (c >= 52)
printf("%c occurs %d times in the entered string.\n", c + '0' - 51, count[c]);
// Same as for characters
// Substracting 51 because we already have iterated through low cases and capital characters
// Starting from '0' until '9'
}
}
return 0;
}
The problem is that, considering the ascii table, you were storing the capital letters and numbers in a negative indice of your array countby substracting 'a'which is equal to 97in ASCII. This should work but I couldn't test it yet so be careful with it.
For the printing, we do the same thing for low case characters, then capital characters and then numbers : we start from the first one : 'a', then 'A', then '0', iterate until the last one using c and printing them all. We use the fact that in C, 'a' + 1 = 'b', 'A' + 1 = 'B' etc.
For the input Fred Fish 12345678 the output with this code is :
d occurs 1 times in the entered string.
e occurs 1 times in the entered string.
h occurs 1 times in the entered string.
i occurs 1 times in the entered string.
r occurs 1 times in the entered string.
s occurs 1 times in the entered string.
F occurs 2 times in the entered string.
1 occurs 1 times in the entered string.
2 occurs 1 times in the entered string.
3 occurs 1 times in the entered string.
4 occurs 1 times in the entered string.
5 occurs 1 times in the entered string.
6 occurs 1 times in the entered string.
7 occurs 1 times in the entered string.
8 occurs 1 times in the entered string.

I guess chaning the code
count[data[c] - 'a']++;
to
count[data[c] - '0']++;
if data[c] is less than 75, then count[data[c] - 'a'] does not work

You should modify the 'a' to '0' in your code to take all capital letters and numerics into account.
#include <stdio.h>
int main() {
...
/* snippet */
...
while (data[c] != '\0')
{
if( data[c] >= '0' && data[c] <= 'z')
count[data[c] - '0']++;
c++;
}
for (c = 0; c < 75; 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+'0',count[c]);
}
return 0;
}

Related

Counting how many letters were repeated in the entered word

Your program should read a word from the input and then sort the letters of the word alphabetically (by their ASCII codes). Next, your program should iterate through the letters of the word and compare each letter with the one following it. If these equal each other, you increase a counter by 1, making sure to then skip ahead far enough so that letters that occur more than twice are not counted again. You may assume that the word you read from the input has no more than 50 letters, and that the word is all lowercase.
I wrote a program and get these results:
apple gives me 1
erroneousnesses gives 5,
but taylor should give me 0 however it gives 1.
How can I make yup, taylor and other words with non-repeating alphabets give me 0?
Here is my code:
#include <stdio.h>
int main(void) {
char string[51];
int c = 0, count[26] = { 0 }, x = 0;
scanf("%s", string);
while (string[c] != '\0') {
if (string[c] >= 'a' && string[c] <= 'z') {
x = string[c] - 'a';
count[x]++;
}
c++;
}
printf("%d", count[x]);
return 0;
}
There are multiple problems in your code:
scanf("%s", string); may cause a buffer overflow if the input is longer than 50 bytes.
Furthermore, you do not test the return value to check for invalid or missing input.
counting the number of occurrences of each letter is an alternative approach to the stated problem, and OK if you are only graded based on the program output. However be aware that the program does not implement what the assignment explicitly mandates and the value you output is incorrect anyway.
the output value should be the number of counts that are >= 2. Printing the value of count[x] is meaningless.
Here is a modified version:
#include <stdio.h>
int main() {
char str[51];
int dup = 0;
int count['z' - 'a' + 1] = { 0 };
if (scanf(" %50[a-z]", str) == 1) {
for (int i = 0; str[i] != '\0'; i++) {
if (++count[str[i] - 'a'] == 2)
dup++;
}
printf("%d\n", dup);
}
return 0;
}
to answer your specifc question
printf("%d", count[x]);
prints the count of number of appearances of the last letter.
taylor => 1 (r occurs 1 time)
apple => 1 (e once)
erroneousnesses => 5 (s count)
you need to loop over count array adding all counts > 1

How does this program in C sum all the digits in the string?

I went to this website: https://www.sanfoundry.com/c-program-sum-all-digits-string/
and they have a funciton that adds up all the digits in a string array. I'm wondering how it's doing this.
/*
* C program to find the sum of all digits present in the string
*/
#include <stdio.h>
void main()
{
char string[80];
int count, nc = 0, sum = 0;
printf("Enter the string containing both digits and alphabet \n");
scanf("%s", string);
for (count = 0; string[count] != '\0'; count++)
{
if ((string[count] >= '0') && (string[count] <= '9'))
{
nc += 1;
sum += (string[count] - '0');
}
}
printf("NO. of Digits in the string = %d\n", nc);
printf("Sum of all digits = %d\n", sum);
}
This is the program^
So, correct me if I am wrong, but the for loop is going through each element in the string array until the null character appears, using count to represent the element number, right?
And the if statement is doing this: if the element is a number between 0 and 9...
But, I genuinely don't understand what this line does: sum += (string[count] - '0');
so that line is basically:
sum = sum + (string[count] - '0');
but what does this part do: (string[count] - '0');
Why do you subtract 0 from the digit in the string array?
Or am I looking at this wrong?
sum += (string[count] - '0');
This is a trick to convert a single character digit like '5' into the integer 5.
'0' is the character for 0. All characters are numbers interpreted as characters; you can just use them as numbers. If we look at an ASCII table we see that '0' is the number 48. '1' is 49, '2' is 50... up to '9' at 57. They're all in order and one can take advantage of this. So '9' - '0' is 57 - 48 which is... 9!
Similarly, if you want to know the position of a letter in the alphabet (starting from 0) you can do letter - 'a' or letter - 'A' depending on if it's lower or upper case. (There are some character sets where this is not true but you are very unlikely to encounter these.)

How to write a program that reads a message and counts the number of alph and digits then, replaces lower case by upper case characters?

i want to use the same inputed message for the second part of the code but i can't. the first part is to count the number of alphabets and digits and the second part is to replace lower case by upper case characters. help me please!!
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#define MESSAGE 100
int main()
{
char message[MESSAGE];
int alphabet, digit, i;
alphabet = digit = i = 0;
printf("Please enter your message:\n");
fgets(message, sizeof message, stdin);
while (message[i] != '\0')
{
if ((message[i] >= 'a' && message[i] <= 'z')
|| (message[i] >= 'A' && message[i] <= 'Z'))
{
alphabet++;
}
else if (message[i] >= '0' && message[i] <= '9')
{
digit++;
}
else
{
i++;
}
printf("Number of Alphabets in the string is : %d\n", alphabet);
printf("Number of Digits in the string is : %d\n", digit);
scanf("%i", message);
int count, ch, i;
for (i = 0; (message[i] = getchar()) != '\n'; i++)
{
;
}
message[i] = '\0';
count = i;
printf("The given message is:%s\n", message);
printf("Case changed message is:\n");
for (i = 0; i < count; i++)
{
ch = islower(message[i]) ? toupper(message[i]) : tolower(message[i]);
putchar(ch);
}
return 0;
}
}
The following proposed code:
cleanly compiles
performs the desired operation(s)
produces the expected output
follows the axiom: only one statement per line and (at most) one variable declaration per statement.
minimizes the scope of the variable i
since the numbers can never be less than 0, uses size_t rather than int in the variable definitions
properly checks for I/O errors and when an error occurs, passes the error message and the text reason the system thinks the error occurred to stderr
and now, the proposed code:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#define MESSAGE 100
int main( void )
{
char message[MESSAGE];
size_t alphabet = 0;
size_t digit = 0;
printf("Please enter your message:\n");
if( ! fgets(message, sizeof message, stdin) )
{
perror( "fgets failed:" );
exit( EXIT_FAILURE );
}
printf( "The given message is:%s\n", message );
for( size_t i = 0; message[i]; i++ )
{
if ( isalpha( message[i] ) )
{
alphabet++;
message[i] = (islower(message[i]) ) ? (char)toupper(message[i]) : (char)tolower(message[i]);
}
else if ( isdigit( message[i] ))
{
digit++;
}
}
printf("Number of Alphabets in the string is : %zu\n", alphabet);
printf("Number of Digits in the string is : %zu\n", digit);
printf("Case changed message is: %s\n", message );
}
Just coded again:
#include <stdio.h>
#include <ctype.h>
#define MESSAGE 100
int main(void) {
char msg[MESSAGE];
int alphabet = 0;
int digit = 0;
printf("Enter a message: ");
fgets(msg, sizeof msg, stdin); // accepting the text
for (int i = 0; msg[i]; i++) { // msg[i] says -> msg[i] != '\0'
if (isalpha(msg[i])) alphabet++; // counting if alphabet occurs
if (isdigit(msg[i])) digit++; // counting if a digit occurs
}
for (int i = 0; msg[i]; i++)
msg[i] = (isupper(msg[i])) ? tolower(msg[i]) : toupper(msg[i]);
// converting from upper to lower and vice versa
// printing the details of the given text
printf("There are %d letters and %d digits in the message.\n", alphabet, digit);
// printing the converted text
printf("The converted text is: %s\n", msg);
return 0;
}
In the aforementioned code, the program will ask to get an input from the user and count both alphabet and digit wherever they're occurred and notice that here we've used isdigit() just to count if the letter given was a digit until the null-terminator occurs in the first For loop.
In the second loop, we've just converted each of the letter from upper to lower and vice versa and assigned them again into the same variable and printed them when the loop is exited successfully.
Also, notice that the punctuation marks ain't the member of either alphabet letters or digit, so they're not counted anywhere.
As a sample output:
Enter a message: Hello world, how are you 1234 doing?
There are 24 letters and 4 digits in the message.
The converted text is: hELLO WORLD, HOW ARE YOU 1234 DOING?
Do you have a clear question?
For the second part an easy trick is to look at an ASCII table and notice that 'A' is decimal 65 and 'a' is decimal 97. There is a difference of 32 between these so you can do a bitwise operation on all letters to convert to uppercase without converting the uppercase letters to lower.
This will mess up your numbers though, so you need to make sure you don't run this on those.
If you want to convert the same message then you don't need to input that again inside the while loop. Also, you have to increment 'i' for every case, if the current character is alphabet or digit, so don't put it in the else part.
Try the following implementation:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#define MESSAGE 100
int main()
{
char message[MESSAGE];
int alphabet, digit, i;
alphabet = digit = i = 0;
printf("Please enter your message:\n");
fgets(message, sizeof message, stdin);
while (message[i] != '\0')
{
if ((message[i] >= 'a' && message[i] <= 'z')
|| (message[i] >= 'A' && message[i] <= 'Z'))
{
alphabet++;
}
else if (message[i] >= '0' && message[i] <= '9')
{
digit++;
}
i++;
}
printf("Number of Alphabets in the string is : %d\n", alphabet);
printf("Number of Digits in the string is : %d\n", digit);
scanf("%s", message);
int count, ch;
message[i] = '\0';
count = i;
printf("The given message is:%s\n", message);
printf("Case changed message is:\n");
for (i = 0; i < count; i++)
{
ch = islower(message[i]) ? toupper(message[i]) : tolower(message[i]);
putchar(ch);
}
return 0;
}
"Don't tell me there's not one bit of difference between uppercase and lowercase letters, because that's exactly the difference."
In ASCII, you can toggle case by toggling the 6th least-significant bit.
'A' == 0x41 <-> 0x61 == 'a'
'B' == 0x42 <-> 0x62 == 'b'
'C' == 0x43 <-> 0x63 == 'c'
...
'Z' == 0x5A <-> 0x7A == 'z'
That provides an easy of changing the case, and we can do it all in one pass.
if (
( message[i] >= 'A' && message[i] <= 'Z' )
|| ( message[i] >= 'a' && message[i] <= 'z' )
) {
++letters;
message[i] ^= 0x20;
}
else if ( message[i] >= '0' && message[i] <= '9' ) {
++digits;
}
This, like your original program, makes the following assumptions:
The program will be compiled on an ASCII-based machine.
The program will be compiled for an ASCII-based machine.
You are only interested in the letters and digits in the ASCII character set.

why is printf prints just once in a loop, only for the first input?

void hexToDec(){
char numHex, numDec;
int isNum, isLowAf, isHighAf;
printf("Enter a reversed number in base 16:\n");
scanf("%c", &numHex);
while(numHex != '\n'){
isNum = isHighAf = isLowAf = 0;
if(numHex >= 48 && numHex <= 57)
isNum = 1;
if(numHex >= 65 && numHex <= 70)
isHighAf = 1;
if(numHex >= 97 && numHex <= 102)
isLowAf = 1;
if(!isNum && !isLowAf && !isHighAf)
printf("Error! %c is not a valid digit in base 16\n", numHex);
//else - Hexadecimal to Decimal converter
fflush(stdin);
scanf("%c", &numHex);
}
}
I can't use string.h or arrays[] this task and I need to check every input I get and print every char that isn't digit in base 16. The problem is that it only check the first letter I enter and print not valid for it.
for example:
input:
lds
output:
Error! l is not a valid digit in base 16
expected:
Error! l is not a valid digit in base 16
Error! s is not a valid digit in base 16
Also I can't figure out why the while loop doesn't stop after I click Enter.
fflush(stdin) is not standard C. But on systems where it works (Windows), it will discard all the buffered input that hasn't yet been. So after scanning the first character l, this will cause ds to be discarded, and it will wait for you to type a new line of input.
Get rid of that call if you want it to process the remaining characters of the line.
The while loop is not exiting because of the space in the second scanf.
Would be a tad nicer if character constants are used instead of hard coded numbers.
while(numHex != '\n'){
isNum = isHighAf = isLowAf = 0;
if(numHex >= '0' && numHex <= '9')
isNum = 1;
else if(numHex >= 'A' && numHex <= 'F')
isHighAf = 1;
else if(numHex >= 'a' && numHex <= 'f')
isLowAf = 1;
if(!isNum && !isLowAf && !isHighAf)
printf("Error! %c is not a valid digit in base 16\n", numHex);
//else - Hexadecimal to Decimal converter
//fflush(stdin);//undefined behavior
scanf("%c", &numHex);
}

Check whether the input is digit or not in C programming

I am currently reading this book: The C Programming Language - By Kernighan and Ritchie (second Edition) and one of the examples I am having trouble understanding how to check whether the input is digit or not. The example is on Page 22, explaining under the array chapter.
Below is the example.
#include <stdio.h>
/* count digits, white space, others */
main()
{
int c, i, nwhite, nother;
int ndigit[10];
nwhite = nother = 0;
for (i = 0; i < 10; ++i)
{
ndigit[i] = 0;
}
while ((c = getchar()) != EOF)
{
if (c >= '0' && c <= '9')
{
++ndigit[c-'0'];
}
else if (c == ' ' || c == '\n' || c == '\t')
{
++nwhite;
}
else
{
++nother;
}
printf("digits =");
for (i = 0; i < 10; ++i)
{
printf(" %d", ndigit[i]);
}
printf(", white space = %d, other = %d\n",nwhite, nother);
}
For this example, what confused me is that the author mentioned that the line ++ndigit[c-'0'] checks whether the input character in c is a digit or not. However, I believe that only the if statement ( if (c>= '0' && c<= '9') ) is necessary, and it will check if c is digit or not. Plus, I do not understand why [c-'0'] will check the input(c) is digit or not while the input variable (c) is subtracted from the string-casting ('0').
Any suggestions/explanations would be really appreciated.
Thanks in advance :)
The if statement checks whether the character is a digit, and the ++ndigit[c-'0'] statement updates the count for that digit. When c is a character between '0' and '9', then c-'0' is a number between 0 and 9. To put it another way, the ASCII value for '0' is 48 decimal, '1' is 49, '2' is 50, etc. So c-'0' is the same as c-48, and converts 48,49,50,... to 0,1,2...
One way to improve your understanding is to add a printf to the code, e.g. replace
if (c >= '0' && c <= '9')
++ndigit[c-'0'];
with
if (c >= '0' && c <= '9')
{
++ndigit[c-'0'];
printf( "is digit '%c' ASCII=%d array_index=%d\n", c, c, c-'0' );
}
I would try to explain with an example
suppose the input is abc12323
So the frequency of 1=1
frequency of 2=2
frequency of 3=2
if (c >= '0' && c <= '9') //checks whether c is a digit
++ndigit[c-'0'];
Now if you do printf("%d",c) then you will get the ascii value of the
character
for c='0' the ascii value will be 48,c='1' ascii value will be 49 and it goes
till 57 for c='9'.
In your program you are keeping a frequency of the digits in the input so you need to update the index of the digit in the array every time you get it
if you do ndigit[c]++ then it will update ndigit[48] for c='0',ndigit[49] for c='1'
So either you can do ndigit[c-'0']++ as ascii value of '0'=48 in decimal
or you can simply do ndigit[c-48]++ so for c='0' ndigit[0] is updated,c=1'
ndigit[1] is updated
you can check the re factored code here http://ideone.com/nWZxL1
Hope it helps you,Happy Coding

Resources