Pangram in C using functions - c

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;
}

Related

I am writing C function that convert lowercase char to upper case char with using ASCII but Output is not correct

Okay, So I start working on this, I have code below;
+I also have strlen("any string here") func that return len of any str in decimal just keep in your mind.
I take a lover case let's say a, then a will be equal some decimal num in ASCII table then I subtract 32 to get A.
Sadly this is not working, any idea for this?
Thank you for all help and your time!
int uppercase(char sent[]) {
for(int i=0; i <= strlen(sent); ++i) {
if(sent[i]>='a' && sent[i]<='z')
sent[i] -= 32;
}
The function is declared as having the return type int but returns nothing.
int uppercase(char sent[]) {
for(int i=0; i <= strlen(sent); ++i) {
if(sent[i]>='a' && sent[i]<='z')
sent[i] -= 32;
}
In general for a function that deals with strings the condition of the for loop should look at least like
for(int i=0; i < strlen(sent); ++i) {
Though it is better to write the loop like
for( size_t i = 0, n = strlen(sent); i < n; ++i ) {
However there is no great sense to use the function strlen in the function uppercase. Its call is redundant.
Pay attention to that you may not change a string literal. Any attempt to change a string literal results in undefined behavior.
From the C Standard (6.4.5 String literals)
7 It is unspecified whether these arrays are distinct provided their
elements have the appropriate values. If the program attempts to
modify such an array, the behavior is undefined.
Also it is better not to use the magic number 32.
The function can be written the following way as it is shown in the demonstrative program below.
#include <stdio.h>
char * uppercase( char *s )
{
for ( char *p = s; *p; ++p )
{
if ( 'a' <= *p && *p <= 'z' ) *p = *p & ~' ';
}
return s;
}
int main(void)
{
char s[] = "hello world!";
puts( s );
puts( uppercase( s ) );
return 0;
}
The program output is
hello world!
HELLO WORLD!
As for the function strlen then it is better to use another name for the function because it will conflict with the standard C function strlen. And the function itself can be defined the following way
size_t string_len( const char *s )
{
const char *p = s;
while ( *p ) ++p;
return p - s;
}
This code can help you
#include <stdio.h>
#include <string.h>
void uppercase(char T[],int k)
{
int i=0;
while(i<k)
{
if(T[i]>='a'&&T[i]<='z')
{
T[i]=(char)((int)T[i]-32);
}
i++;
}
i=0;
while(i<k)
{
printf("%c",T[i]);
i++;
}
printf("\n");
}
int main()
{
char T[]="good morning !";
int k=sizeof(T);
uppercase(T,k);
}
This one will work:
#include <stdio.h>
#include <string.h>
void uppercase(char sent[]) {
for (int i = 0; i < (int)strlen(sent); i++) {
if (sent[i] >= 'a' && sent[i] <= 'z') {
sent[i] -= 32;
}
}
}
int main(int argc, char* argv[]) {
if (argc > 1){
uppercase(argv[1]);
puts(argv[1]);
}
return 0;
}
It compiles without any errors and warnings (using clang), even with options -pedantic -Wall -Wextra.
/*
Parsing the string, then making the letters to uppercase.
*/
#include <stdio.h>
#include <limits.h>
int strlen(char s[]){ //String length function
int i;
for (i = 0; s[i] != '\0'; i++);
return i;
}
void uppercase(char sent[]) {
for(int i=0; i < strlen(sent); ++i) {
if(sent[i]>='a' && sent[i]<='z')
sent[i] += 32;
}
printf("%s", sent);
}
this is a whole tab of my whole work. when i try uppercase("hello world"); it giving me core dumped console problem.

How to append characters to a string array in C

I'm very new to C and I'm trying to write a program that checks if a string contains any uppercase letters, and if it does, prints them out. I'm using https://www.onlinegdb.com/online_c_compiler# as my compiler (cause I don't have access to my personal computer right now) and after a test run, the results are (p.s. I know gets isn't safe):
main.c:16:5: warning: ‘gets’ is deprecated [-Wdeprecated-declarations]
/usr/include/stdio.h:638:14: note: declared here
main.c:(.text+0x26): warning: the `gets' function is dangerous and should not be used.
sTrInG
Contains Uppercase!
Uppercase Letters:0
...Program finished with exit code 0
Press ENTER to exit console.
In this case, I expect an output something like this:
Contains Uppercase!
Uppercase Letters: TIG
My script:
#include <stdio.h>
#include <ctype.h>
#include <string.h>
int main()
{
char str[100];
gets(str);
int containsUpper = 0;
char upperLetters[100] = {0};
for (int i=0; i < strlen(str); i++) {
if (islower(str[i])) {
continue;
} else {
containsUpper = 1;
upperLetters[i] = str[i]; // is this the bad line?
}
}
if (containsUpper) {
printf("Contains Uppercase!\n");
printf("Uppercase Letters:");
printf("%zu\n", strlen(upperLetters)); // prints 0 so upperLetters is empty..?
for (int i=0; i < strlen(upperLetters); i++) {
printf("%c", upperLetters[i]);
}
} else {
printf("Does not contain Uppercase!");
}
return 0;
}
This loop
for (int i=0; i < strlen(str); i++) {
if (islower(str[i])) {
continue;
} else {
containsUpper = 1;
upperLetters[i] = str[i]; // is this the bad line?
}
}
1) is incorrect and 2) suffers from a bad style of programming.
You should append upper case letters to the character array upperLetters
consistently that you are not doing. Also if a character is not a lower case character it does not mean that the character is an upper case character. For example in general it can be a digit or a punctuation.
Also there is no need to call the function strlen. An argument of the function call should be cast to unsigned char. Otherwise it can occur that a call of the function will invoke undefined behavior.
The part of the loop with the continue statement is redundant.
The loop can look for example the following way
for ( size_t i = 0, j = 0; str[i] != '\0'; i++ )
{
if ( isupper( ( unsigned char )str[i] ) )
{
upperLetters[j++] = str[i];
}
}
containsUpper = upperLetters[0] != '\0';
If you need the number of uppercase letters in other part pf the program then the loop can look like
size_t n = 0;
for ( size_t i = 0; str[i] != '\0'; i++ )
{
if ( isupper( ( unsigned char )str[i] ) )
{
upperLetters[n++] = str[i];
}
}
if ( n )
{
printf( "Contains Uppercase!\n" );
printf( "Uppercase Letters: " );
printf("%zu\n", n );
for ( size_t i = 0; i < n; i++ )
{
printf( "%c", upperLetters[i] );
}
//…
Or instead of the loop
for ( size_t i = 0; i < n; i++ )
{
printf( "%c", upperLetters[i] );
}
you could just write
printf( "%s\n", upperLetters );
because the array was zero-initialized and as such it contains a string.
As the compiler reported the function gets is unsafe and is not supported by the C Standard. Instead use the function fgets.
For example
fgets( str, sizeof( str ), stdin );
I wouldn't consider numbers or characters like !?#%& to be uppercase letters, yet your program counts them as such. You absolutely must not use gets, but there is no reason in this case to replace it with fgets since your program is not fundamentally line-oriented. You simply don't care about lines. Just do:
#include <stdio.h>
#include <ctype.h>
#include <string.h>
int
main(void)
{
int c;
char upperLetters[100] = {0};
unsigned k = 0;
while( ( c = getchar()) != EOF && k < sizeof upperLetters ) {
if( isupper(c)) {
upperLetters[k++] = c;
}
}
if (k) {
puts("Contains Uppercase!");
printf("Uppercase Letters: %u\n%s\n", k, upperLetters);
} else {
fprintf(stderr, "Does not contain Uppercase!");
}
return k != 0;
}
(Note that the original program only looks at the first line of input. Whether that is a bug or intentional is not clear. If it is intentional, add a check and break out of the loop when after the first newline character is read.)
You want the loop to be:
int i, j=0;
for (i=0; i < strlen(str); i++) {
if (isupper((unsigned char)str[i])) {
upperLetters[j++] = str[i];
}
}
upperLetters[j]= '\0';
containsUpper = (j>0);
That is, keep a separate index of the upper letters array. And don't forget to terminate it.
A better way for the loop is:
int i, j, k;
for (i=0, j=0, k=strlen(str); i < k; i++) {
as this calls strlen only once.
EDIT: As user LxerLx pointed out, a character which is not a lower case letter does not have to be an upper case letter. I updated the loop for this.

%s not working properly with my return value, in C

As the title says %s is not working properly This is for a code wars so %s needs to be able to work with the array to pass the sample test cases; Cannot change function declaration of playPass. Using Ascii table. Also the for loop to print in main() works and gives me correct output.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
// takes a string and shifts letter n value;
// lower cases every other element if it contains a letter
// replaces number with a 9 complement
// returns array with values reversed.
char* playPass(char* s, int n)
{
int length = strlen(s);
char *pass= (char *)malloc(length*sizeof(char)+1);
char a;
int letter, i;
for(i=0; i< length; i++)
{
a = s[i];
letter = a;
if( letter >= 65 && letter <=90 )
{
letter +=n;
if(letter >90)
{
letter -=90;
letter +=64;
}
if((i+1) % 2 == 0 )
{
letter += 32;
}
a = letter;
}
else if(letter >= 48 && letter <= 57)
{
letter -= 48;
letter = 9 - letter;
a = letter + '0';
}
pass[length - i] = a;
}
return pass;
}
// answer should be
int main (){
char* s ={"I LOVE YOU!!!"};
int length = strlen(s);
int k = 1;
s =playPass( s,k );
int i;
printf(" %s", s);
for(i = 0; i <= length; i++)
{
printf(" %c", s[i]);
}
}
%s works only with null terminated char *
char* playPass(char* s, int n) {
…
for() {
…
}
pass[i] = '\0'; //Null terminate here.
return pass;
}
so figured it out.
the end where i assined the new value to the new array
pass[length - i] = a;
made it to where it never wrote a value to the first element so
pass[0]= NULL;
had to change it to
pass[length - (i-1)] = a;
thanks for the help everyone, I also cleaned up the code from the magic numbers Great tip #phuclv!

Check if substring in string, and make string's chars uppercase (when found a substring there

What I need to write:
1.Get a main string from user.
2.Get a subString from a user.
Every match of the subString in the main string, change its letters to uppercase.
Do not use string's functions like strstr.
For example:
main string: abcdeffghfhkfff
sub string: ff
outut: abcdeFFghfhkFFf
Problem: Well, I'm having troubles to continue writing the code after I found one match. for example after I found the first 'f' in the main string, how can I continue check if the second 'f' is adjacent to the found 'f', if not, then try to find another 'f' and check subsequent matches of the subarray until we've found that the length of the substring matches the number of subsequent matches in the string? Here's what I've tried, and in writing the logic of the for loop in 'replaceSubstring' function
#include <stdio.h>
#include <stdlib.h>
#include<conio.h>
#include <string.h>
#define N 101
void replaceSubstring(char *str, char *subStr);
void main()
{
char str[N], subStr[N];
while (strlen(str) != 0 || strlen(subStr) != 0)
{
str[0] = 0;
printf("Enter text: ");
gets(str);
printf("Enter substring: ");
scanf("%s", subStr);
replaceSubstring(str, subStr);
}
}
void replaceSubstring(char *str, char *SubStr)
{
int i, count = 0, j = 0, k = 0;
for (i = 0; i <= strlen(str); i++)
{
if (str[i] == SubStr[k])
{
k++;
count++;
if (count == strlen(SubStr))
{
str[i] -= 32;
}
}
}
puts(str);
getchar();
}
You can use strstr() function to do this more easly, like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 101
void replaceSubstring(char *str, char *subStr);
void main()
{
char str[N], subStr[N];
while (strlen(str) != 0 || strlen(subStr) != 0)
{
str[0] = 0;
printf("Enter text: ");
gets(str);
printf("Enter substring: ");
scanf("%s", subStr);
replaceSubstring(str, subStr);
}
}
void replaceSubstring(char *str, char *SubStr)
{
int i;
char *tmp;
while((tmp = strstr(str, SubStr)) != NULL)
{
for (i = 0; i < strlen(SubStr); i++)
{
tmp[i] -= 32;
}
}
puts(str);
getchar();
}
Here another version of replaceSubstring() function without using strstr() function:
void replaceSubstring(char *str, char *SubStr)
{
int i = 0, found = 1, j = 0, k = 0;
while (i < strlen(str))
{
if (str[i] == SubStr[0])
{
found = 1;
for(k = 0; k < strlen(SubStr); k++)
{
if(str[i+k] != SubStr[k])
{
found = 0;
break;
}
}
if(found)
{
for(k = 0; k < strlen(SubStr); k++)
{
str[i+k] -= 32;
}
i += strlen(SubStr);
}
else
i++;
}
else
i++;
}
puts(str);
getchar();
}
To solve this without using strstr(), i would do something like this:
void replaceSubstring(char *str, char *SubStr)
{
int i = 0, equals = 0, j = 0, k = 0;
for(i=0;i<strlen(str);i++){
j = i;
equals = 1;
k=0;
while(k<strlen(SubStr)&&(equals == 1)){
if(SubStr[k] != str[j]){
equals = 0;
}
k++;
j++;
}
if(equals == 1){
for(j=i;j<i+k;j++){
str[j] -= 32;
}
}
}
puts(str);
getchar();
}
I'm pretty sure this works correctly.
input: abcdeffghfhkfff
substring: ff
output: abcdeFFghfhkFFf
Here is a demonstrative program that shows how the function can be written
#include <stdio.h>
#include <string.h>
#include <ctype.h>
char * replaceSubstring( char *s1, const char *s2 )
{
char *p = s1;
size_t n = strlen( s2 );
while ( ( p = strstr( p, s2 ) ) != NULL )
{
for ( size_t i = 0; i < n; ++i, ++p ) *p = toupper( ( unsigned char )*p );
}
return s1;
}
int main( void )
{
char s[] = "abcdeffghfhkfff";
puts( s );
puts( replaceSubstring( s, "ff" ) );
}
Its output is
abcdeffghfhkfff
abcdeFFghfhkFFf
Take into account that according to the C Standard function main without parameters shall be declared like`
int main( void )
Also it is a bad idea to use "magic" numbers like 32 like in this statement
tmp[i] -= 32;
For example if in the environment there are used EBCDIC characters then this statement will be simply wrong.
Moreover even for ASCII characters this statement is invalid because it is not necessary that original characters are in lower case.

I need to write a C program that calls a given function to count the number of characters and digits in a file

I need to write a C program that counts the number of characters and digits in a file. I believe my best attempt is close, but the program must call a given function, mostfrequent(), and I cannot figure out how to implement it into my main so that they work together. Any help would be greatly appreciated. Thank you.
// this is the function my program is required to use.
int mostfrequent(int *a, int length) {
int index = 0;
int max = a[0];
int i;
for (i = 1; i < length; i++) {
if (a[i] > max) {
max = a[i];
index = i;
}
}
return index;
}
// this is my closest attempt at a working program so far, but it does
// not call mostfrequent() which I need it to do.
int main() {
typedef FILE *ptr_file;
int x, i, j;
int length;
char c;
char ch[1000];
int a = 65;
c = getc(ptr_file);
ptr_file = fopen("file.txt", "r");
if (!ptr_file)
return 1;
while (c != EOF) {
scanf(ptr_file, "%s", ch[i]);
i++;
fclose(ptr_file);
}
for (i = 0; i < length; i++) {
for (j = 0; j < length; j++) {
if (a < 116) {
if (char(a) == 'ch[j]')
char max_char_temp=(char)a
count_temp++;
}
if (count_temp > count) {
count = count_temp;
max_char = max_char_temp;
}
return 0;
}
regarding the question: when to call the most_frequent() function.
After you have created an array (which would be 36 entries long of integers), initialize that array to all zeros, then incremented the appropriate entry for each character read from the input file. (note 36 entries allows for a...z + 0...9 so all other characters read from the file should be discarded.
Then pass the array and 36 to the most_frequent() function
then code similar to the following could do the job:
#include <stdio.h>
#include <stdlib.h>
#include <ctypes.h> // isalpha(), isdigit(), toupper()
#define NUM_ALPHA (26)
int main( void )
{
int array[36] = {'\0'};
//...open file, etc
//then assure all processed characters are upper case or numeric
// and update the count in the array
int ch;
while( ch = getc( file ) != EOF && '\n' != ch)
{
if ( isalpha(ch) )
{
ch = toupper(ch);
array[ch - 'A']++;
}
else if (isdigit(ch) )
{
array[ (ch-'0') + NUM_ALPHA ]++;
}
}
int index = mostfrequent( array, sizeof(array)/sizeof(array[0]);
//... do what is needed with 'index' for instance
printf( "the highest occurring char is:" );
if( index < NUM_ALPHA )
{
printf( "%c\n", index+'A' );
}
else
{
printf( "%d\n", (index-NUM_ALPHA)+'0');
}
fclose( file );
return 0;
}
however, note that mostfrequent() only returns the index to the first entry encountered with the max value, when there are multiple entries with the same max value.

Resources