I have written this code for finding the character with the minimum frequency.
So, giving in input "Hi, how is the weather todayy Dori", the output should be
The letter with the minimum frequency is āsā and the frequency is 1.
But it shows
How to remove the that coma what is my mistake here
#include<stdio.h>
#include <string.h>
#include <ctype.h>
#define MAX 1000
int main()
{
char str[MAX];
int fre[MAX],i,q,r,co=0,num;
printf("The string : ");
gets(str);
for(q=0;str[q];q++);
r=num=q;
for(i=0;i<num;i++)
{
fre[i]=num;
co=1;
if(str[i])
{
for(q=i+1;q<num;q++)
{
if(tolower(str[i]) == tolower(str[q]))
{
{
co++;
str[q]='\0';
}
}
fre[i]=co;
if(co<=r)
r=co;
}
}
}
printf("The letter with the minimum frequency is");
for(q=0;q<num;q++)
{
if(fre[q]==r)
{
printf(" '%c' ",str[q]);
}
}
printf("and the frequency is %d \n ",r);
return 0;
}
For starters the function gets is unsafe and is not supported by the C Standard. Instead use the standard C function fgets.
As an entered string in general can be very big while letters in the string converted to the lower case can be in the range of ['a', 'z'] then there is no sense to declare such a big array as the array fre declared like.
int fre[MAX];
As you already included the header <string.h> then there is no sense manually to calculate the length of the entered string.
for(q=0;str[q];q++);
To exclude non-letters characters from counting you can use the standard C function isalpha declared in the header <ctype.h>.
Pay attention to that in general the entered string can have no letters.
Here is a demonstrative program that shows how your approach can be implemented.
#include <stdio.h>
#include <ctype.h>
int main(void)
{
enum { MAX = 1000 };
char s[MAX];
size_t frequency[ 'z' - 'a' + 1] = { 0 };
const size_t N = sizeof( frequency ) / sizeof( *frequency );
printf( "The string: " );
if ( fgets( s, MAX, stdin ) )
{
for ( const char *p = s; *p; ++p )
{
if ( isalpha( ( unsigned char )*p ) )
{
++frequency[tolower( ( unsigned char )*p ) - 'a'];
}
}
size_t min = 0;
for ( size_t i = 0; i < N; i++ )
{
if ( frequency[i] != 0 && ( min == 0 || frequency[i] < min ) )
{
min = frequency[i];
}
}
if ( min == 0 )
{
puts( "There ie no letters in the entered string." );
}
else
{
printf( "The letter with the minimum frequency is: " );
for ( size_t i = 0; i < N; i++ )
{
if ( frequency[i] == min ) printf( "%c ", ( int )('a' + i ) );
}
printf( "\nand the frequency is %zu\n ", min );
}
}
return 0;
}
The program output might look like
The string: Hi, how is the weather todayy Dor
The letter with the minimum frequency is: s
and the frequency is 1
There's really no reason to read more than one character at a time. In general, that's a good pattern to try and follow. eg:
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include <ctype.h>
int main(void)
{
int c;
int fre[26] = {0};
printf("The string : ");
while( (c = getchar()) != EOF ) {
putchar(c);
if( isalpha(c) ) {
fre[tolower(c) - 'a'] += 1;
}
}
printf("The letter with the minimum frequency is");
int idx = 0;
int m = INT_MAX;
for( int q = 0; q < 26; q++ ) {
if( fre[q] > 0 && fre[q] < m ) {
idx = q;
m = fre[q];
}
}
printf(" '%c', with frequency %d\n", idx + 'a', fre[idx]);
return 0;
}
Related
When I input The quick brown fox jumps over the lazy dog, the following program prints not a pangram. Yet, I expect s to be 26 and printf("pangram") to be executed. What am I doing wrong?
#include <ctype.h>
#include <stdio.h>
#include <string.h>
char findpan(char arr[]) {
int i, j, count = 0;
for (i = 0; i < strlen(arr); i++) {
if (isalpha(arr[i]))
count++;
}
for (i = 0; i < strlen(arr); i++) {
for (j = i + 1; j < strlen(arr); j++) {
if (arr[i] == arr[j])
count--;
}
}
return (count);
}
int main() {
int s;
char str[60];
fgets(str, 60, stdin);
s = findpan(str);
if (s == 26)
printf("pangram");
else
printf("not a pangram");
return 0;
}
If I have understood what you are trying to do then these nested loops
for (i = 0; i < strlen(arr); i++) {
for (j = i + 1; j < strlen(arr); j++) {
if (arr[i] == arr[j])
count--;
}
}
are incorrect. Let's assume that you have string "AAA". So after the preceding loop count will be equal to 3.
Now after these nested loops count will be equal to 0 instead of 1. That is when i = 0 then for j = 1 and j = 2 arr[j] is equal to arr[i]. So count will be decreased two times. When i = 1 then for j = 2 again arr[j] = arr[i] and count will be decreased one more.
Also it seems you should ignore cases of letters.
I can suggest the following function implementation as it is shown in the demonstrative program below.
#include <stdio.h>
#include <ctype.h>
size_t findpan( const char *s )
{
size_t count = 0;
for ( const char *p = s; *p; ++p )
{
if ( isalpha( ( unsigned char ) *p ) )
{
char c = tolower( ( unsigned char )*p );
const char *q = s;
while ( q != p && c != tolower( ( unsigned char )*q ) ) ++q;
if ( q == p ) ++ count;
}
}
return count;
}
int main(void)
{
printf( "%zu\n", findpan( "The quick brown fox jumps over the lazy dog" ) );
return 0;
}
The program output is
26
Without using pointers the function can look the following way
size_t findpan( const char *s )
{
size_t count = 0;
for ( size_t i = 0; s[i] != '\0'; i++ )
{
if ( isalpha( ( unsigned char ) s[i] ) )
{
char c = tolower( ( unsigned char )s[i] );
size_t j = 0;
while ( j != i && c != tolower( ( unsigned char )s[j] ) ) ++j;
if ( j == i ) ++count;
}
}
return count;
}
Simple Solution?
Here a Simple solution, I made the guess that you probably just want to know if it is or it isn't a pangram and so i've changed your function to a boolean one:
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
bool findpan(char arr[]) {
int i,j;
for (i = 'a'; i < 'z'; ++i) { // goes through the alphabet
for (j = strlen(arr); j > 0; j--) // goes through the arr[]
if (tolower(arr[j]) == i) // checks if the letter exists
break; // breaks the inner for-loop if letter found
if (j == 0) // if letter not found
return false;
}
return true;
}
int main() {
bool isPangram;
char str[60];
fgets(str, 60, stdin);
isPangram = findpan(str);
if (isPangram)
printf("pangram");
else
printf("not a pangram");
return 0;
}
Explanation
'a' to 'z' represent the range of the lowercase letters in Decimal numbers, in the ASCII table:
for (i = 'a'; i < 'z'; ++i)
tolower converts arr[j] character to lowercase and then compares it to i:
if (tolower(arr[j]) == i)
stdbool.h is introduced for the use of bool aka boolean:
#include <stdbool.h>
Limiting myself to plain ASCII you can create a simple array, with one element per letter and each element initialized to zero. Then loop over the string, and for each letter convert it to an index into the array and increase the corresponding elements value.
Once done with the input string, you loop over the array, and increase a counter for every non-zero value, and return that.
Perhaps something like this:
#include <stdio.h>
#include <ctype.h>
int main(void)
{
char input[512];
if (!fgets(input, sizeof input, stdin))
return 1; // Failed to read input
int letters[26] = { 0 }; // 26 letters in the English alphabet
for (unsigned i = 0; input[i] != '\0'; ++i)
{
if (isalpha(input[i]))
{
// Limiting myself to e.g. plain ASCII here
++letters[tolower(input[i]) - 'a'];
}
}
// Count the number of non-zero elements in the letters array
unsigned counter = 0;
for (unsigned i = 0; i < 26; ++i)
{
counter += letters[i] != 0;
}
// Print result
printf("Counter = %d\n", counter);
}
With your example input (The quick brown fox jumps over the lazy dog) it outputs
Counter = 26
This does only a single pass over the input string, and then a single pass over the letters array. No nested loop, no multiple passes over the input string.
If we assume 8 bit characters and can stand allocating 256 bytes on the stack temporarily, then this is both readable, compact and fairly efficient:
bool is_pangram (const char* str)
{
char used [256]={0};
for(; *str!='\0'; str++)
{
used[*str]=1;
}
return memchr(&used['a'], 0, 26)==NULL; // 26 letters in the alphabet
}
The 256 byte zero-out might seem inefficient, but the mainstream x86 compilers run that in 16 instructions. This function also makes no assumptions of adjacency of 'a' to 'z'. To add support for upper case, simply do used[tolower(*str)]=1; though that might introduce a lot of branching.
Test code:
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
bool is_pangram (const char* str)
{
char used [256]={0};
for(; *str!='\0'; str++)
{
used[*str]=1;
}
return memchr(&used['a'], 0, 26)==NULL;
}
int main (void)
{
const char* test_cases[] =
{
"",
"hello, world!",
"the quick brown fox jumps over the lazy dog",
"the quick brown cat jumps over the lazy dog",
"junk mtv quiz graced by fox whelps",
"public junk dwarves hug my quartz fox",
};
for(size_t i=0; i<sizeof test_cases/sizeof *test_cases; i++)
{
printf("\"%s\" is %sa pangram\n", test_cases[i], is_pangram(test_cases[i])?"":"not ");
}
return 0;
}
The sum of all odd digits of n.(eg. n is 32677, the sum would be 3+7+7=17)
Here is the code.
For this question, any of loop or function is acceptable, but not longer than this answer.
#include <stdio.h>
int main()
{
char n[20];
int m=0,i;
printf("Enter integers for the variable n: ");
for (i=0;i<20;i++)
{
scanf("%c",&n[i]);
if(n[i]=='\n')
{
break;
}
}
for (i=0;i<20;i++)// this is the part I would like to simplified
{
if (n[i]%2!=0)
{
if(n[i]==49)
m++;
if(n[i]==51)
m+=3;
if(n[i]==53)
m+=5;
if(n[i]==55)
m+=7;
else if(n[i]==57)
m+=9;
}
}
printf("The sum of odd digits of n is %d.",m);
}
Here are some tools/ideas you can use:
In ctype.h is a function isdigit() which tells you whether or not a character represents a digit.
Assuming the characters for the digits 0..9 are in sequence, the value represented by a character digit c is c-'0'
Here you are
#include <stdio.h>
int main( void )
{
enum { N = 20 };
char value[N];
printf( "Enter an unsigned integer: " );
size_t n = 0;
for ( char digit; n < N && scanf( "%c", &digit ) == 1 && digit != '\n'; ++n )
{
value[n] = digit;
}
unsigned int sum = 0;
for ( size_t i = 0; i < n; i++ )
{
if ( value[i] % 2 != 0 ) sum += value[i] - '0';
}
printf( "The sum of odd digits of the value is %u.\n", sum );
}
The program output might look like
Enter an unsigned integer: 0123456789
The sum of odd digits of the value is 25
Or you can add a check that an entered character is a digit. For example
#include <stdio.h>
#include <ctype.h>
int main( void )
{
enum { N = 20 };
char value[N];
printf( "Enter an unsigned integer: " );
size_t n = 0;
for ( char digit;
n < N && scanf( "%c", &digit ) == 1 && isdigit( ( unsigned char )digit );
++n )
{
value[n] = digit;
}
unsigned int sum = 0;
for ( size_t i = 0; i < n; i++ )
{
if ( value[i] % 2 != 0 ) sum += value[i] - '0';
}
printf( "The sum of odd digits of the value is %u\n", sum );
}
As for your code then in this loop
for (i=0;i<20;i++)
{
scanf("%c",&n[i]);
if(n[i]=='\n')
{
break;
}
}
you have to count how many digits were entered. And the new line character shall not be stored in the array. Otherwise this loop
for (i=0;i<20;i++)
can result in undefined behavior.
And you should not use magic numbers like for example 49.
I'm trying to split a string into chunks of 6 using C and I'm having a rough time of it. If you input a 12 character long string it just prints two unusual characters.
#include <stdio.h>
#include <string.h>
void stringSplit(char string[50])
{
int counter = 0;
char chunk[7];
for (unsigned int i = 0; i < strlen(string); i++)
{
if (string[i] == ' ')
{
continue;
}
int lastElement = strlen(chunk) - 1;
chunk[lastElement] = string[i];
counter++;
if (counter == 6)
{
printf(chunk);
memset(chunk, '\0', sizeof chunk);
counter = 0;
}
}
if (chunk != NULL)
{
printf(chunk);
}
}
int main()
{
char string[50];
printf("Input string. \n");
fgets(string, 50, stdin);
stringSplit(string);
return(0);
}
I appreciate any help.
Your problem is at
int lastElement = strlen(chunk) - 1;
Firstly, strlen counts the number of characters up to the NUL character. Your array is initially uninitialized, so this might cause problems.
Assuming your array is filled with NULs, and you have, let's say, 2 characters at the beginning and you are looking to place the third one. Remember that your 2 characters are at positions 0 and 1, respectively. So, strlen will return 2 (your string has 2 characters), you subtract one, so the lastElement variable has the value 1 now. And you place the third character at index 1, thus overwriting the second character you already had.
Also, this is extremely inefficient, since you compute the number of characters each time. But wait, you already know how many characters you have (you count them in counter, don't you?). So why not use counter to compute the index where the new character should be placed? (be careful not to do the same mistake and overwrite something else).
The function is wrong.
This statement
int lastElement = strlen(chunk) - 1;
can result in undefined behavior of the function because firstly the array chunk is not initially initialized
char chunk[7];
and secondly after this statement
memset(chunk, '\0', sizeof chunk);
the value of the variable lastElement will be equal to -1.
This if statement
if (chunk != NULL)
{
printf(chunk);
}
does not make sense because the address of the first character of the array chunk is always unequal to NULL.
It seems that what you mean is the following.
#include <stdio.h>
#include <ctype.h>
void stringSplit( const char s[] )
{
const size_t N = 6;
char chunk[N + 1];
size_t i = 0;
for ( ; *s; ++s )
{
if ( !isspace( ( unsigned char )*s ) )
{
chunk[i++] = *s;
if ( i == N )
{
chunk[i] = '\0';
i = 0;
puts( chunk );
}
}
}
if ( i != 0 )
{
chunk[i] = '\0';
puts( chunk );
}
}
int main(void)
{
char s[] = " You and I are beginners in C ";
stringSplit( s );
}
The program output is
Youand
Iarebe
ginner
sinC
You can modify the function such a way that the length of the chunk was specified as a function parameter.
For example
#include <stdio.h>
#include <ctype.h>
void stringSplit( const char s[], size_t n )
{
if ( n )
{
char chunk[n + 1];
size_t i = 0;
for ( ; *s; ++s )
{
if ( !isspace( ( unsigned char )*s ) )
{
chunk[i++] = *s;
if ( i == n )
{
chunk[i] = '\0';
i = 0;
puts( chunk );
}
}
}
if ( i != 0 )
{
chunk[i] = '\0';
puts( chunk );
}
}
}
int main(void)
{
char s[] = " You and I are beginners in C ";
for ( size_t i = 3; i < 10; i++ )
{
stringSplit( s, i );
puts( "" );
}
}
The program output will be
You
and
Iar
ebe
gin
ner
sin
C
Youa
ndIa
rebe
ginn
ersi
nC
Youan
dIare
begin
nersi
nC
Youand
Iarebe
ginner
sinC
YouandI
arebegi
nnersin
C
YouandIa
rebeginn
ersinC
YouandIar
ebeginner
sinC
I am attending the online course cs50 on Edx and I have an assignment in which I have to create a program where the user enters a keyword ( used then for encryption ) and a string that needs to be encrypted in Vigenere cipher.
Vigenere works by encrypting a text following a keyword: for example if my string is "Hello" and my keyword is "abc" : a is equal to 0 in alphabetical characters, b to 1, and c to 2; so the letter h in the string is encrypted without switching characters ( s letter a in the keyword is = 0), the letter e is switched by one position and is encrypted to f, and so on. If the keyword has a length less than that of the string (like in this case) the encryption has to use again the first character of the keyword and this is my problem.
In fact, I think I implemented well the whole program but I am not sure how to take into consideration if a keyword has less characters than the string entered.
The program is now returning only the first char of my string encrypted and the first char not encrypted and then it stops.
I do not ask for a complete solution, but I just want to understand how I can solve my program problem.
Here is my program:
#include <stdio.h>
#include <cs50.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
int vigenere_low( char c )
{
int v = c - 'a';
return v;
}
int vigenere_up( char c )
{
int v = c - 'A';
return v;
}
int keyword_low( char c )
{
int k = c - 'a';
return k;
}
int keyword_up( char c )
{
int k = c - 'A';
return k;
}
int main( int argc, string argv[] )
{
string p;
string keyword = argv[1];
if ( argc != 2 )
{
printf("Usage: ./vigenere keyword\n");
return 1;
}
for ( int i = 0, n = strlen(keyword); i < n; i++ )
{
if ( !isalpha( keyword[i]) )
{
printf("Usage: ./vigenere keyword(alphabetical) \n");
return 1;
}
}
p = GetString();
int j = 0;
for ( int i = 0, n = strlen( p ); i < n; i++ )
{
if ( isalpha( p[i]) )
{
if ( islower( p[i]) )
{
if ( islower( keyword[j]) )
{
int a = (( vigenere_low( p[i]) + keyword_low( keyword[j]) ) % 26 ) + 'a';
printf("%c", a);
j++;
}
else
{
int a = (( vigenere_low( p[i]) + keyword_up( keyword[j]) ) % 26 ) + 'a';
printf("%c", a);;
j++;
}
}
if ( isupper( p[i]) )
{
if ( islower( keyword[j]) )
{
int a = (( vigenere_up( p[i]) + keyword_low( keyword[j]) ) % 26 ) + 'A';
printf("%c", a);
j++;
}
else
{
int a = (( vigenere_up( p[i]) + keyword_up( keyword[j]) ) % 26 ) + 'A';
printf("%c", a);
j++;
}
}
else
{
printf("%c", p[i] );
}
}
return 0;
}
}
... not sure how to take into consideration if a keyword has less characters than the string entered.
Accessing keyword[j] beyond the end of keyword[] is bad. (Undefined behavior). This happens with OP's code when the key is shorter than the alpha part of the message.
Simply re-use the keyword[] string as needed. Hint: reset j.
Mouse over for answer.
int j_length = strlen(keyword);
...
j++;
if (j >= j_length) j = 0;
Im trying to read a char and number with the following:
char c;
char plus = '+';
int last;
if(scanf("%c%d",&c,&last)!=2 || last<0){
printf("fail\n");
return 1;
};
//trying to test it
if(plus==c){
// code
}
But when I start the program, and type + 100 it throws "fail", as scanf wasn't successful. But if I just type 100 it works. Why does "fail" get printed when there are one char (+) and number (100) and why it doesn't if I just type number.
Your code is fine except for a ; try this it works :
#include <stdio.h>
int main( )
{
test();
}
int test()
{
char c;
char plus = '+';
int last;
if ( scanf( "%c%d", &c, &last ) != 2 || last < 0 )
{
printf( "fail\n" );
return 1;
} ///////////// YOU HAD UNNEEDED ; HERE
else
{
printf( "\nyou entered:\n%c,%d", c, last );
getchar( );
}
//trying to test it
if ( plus == c )
{
// code
}
}