Specified letter count with recursion - c

I'm trying to write a recursive algorithm that obtains to count specified a letter by user. But, I'm stuck in two cases. First, I think I must get 2 as result, I can't. Second, If there is no limit key, for instance the limit character specified as z by user , how the characters can be scanned up to end character here g ? The problem little bit complicated for me. I need your advices and ideas. Thank you all appreciated answers.
example string is: how are you i am testing
another examples:
#include <stdio.h>
int lettercount(char* str, char key, char limit);
int main(){
char test[]="how are you i am testing";
int num;
num=lettercount(test,'a','t');
printf("%d",num);
return 0;
}
int lettercount(char* str, char key, char limit)
{
int count = 0;
if(str[0] == limit)
{
return 0;
}
else if(str[0] == key)
{
lettercount(&str[1], key, limit);
count++;
}
else
lettercount(&str[1], key, limit);
return count;
}

as the code is unwinding from the recursion(s)
it needs to accumulate the count
the following code should work for your needs.
Note: this returns 0 if key and limit are the same char
int lettercount(char* str, char key, char limit)
{
int count = 0;
if(str[0] == limit)
{
return 0;
}
// implied else, more char in string to check
if(str[0] == key)
{
count++;
}
count += lettercount(&str[1], key, limit);
return count;
} // end function: lettercount

With a recursive function, you need 3 things. (1) set up in the function that prepares for the next call; (2) a recursive call; and (3) a way to terminate the recursion. Here is one approach. Note: the version in the code below is a long version for readability, a short version is included at the end:
#include <stdio.h>
/* recursively find the number of occurrences
of 'c' in 's' (n is provided as '0')
*/
int countchar (char *s, char c, int n)
{
char *p = s;
if (!*p)
return n;
if (*p == c)
n = countchar (p+1, c, n+1);
else
n = countchar (p+1, c, n);
return n;
}
int main (int argc, char **argv) {
if (argc < 3) {
fprintf (stderr, "\n error: insufficient input. Usage: %s <string> <char>\n\n", argv[0]);
return 1;
}
int count = countchar (argv[1], *argv[2], 0);
printf ("\n There are '%d' '%c's in: %s\n\n", count, *argv[2], argv[1]);
return 0;
}
output:
$ ./bin/rec_c_in_s "strings of s'es for summing" s
There are '5' 's's in: strings of s'es for summing
You can make the function shorter, but slightly less readable with:
int countchar (char *s, char c, int n)
{
char *p = s;
if (!*p) return n;
return countchar (p+1, c, (*p == c) ? n+1 : n);
}

Related

How do I make the strlen() function not count spaces?

#include <stdio.h>
#include <string.h>
int main(void) {
char string[1024];
int len = 0;
int i = 0;
while (fgets(string, sizeof(string), stdin) != 0);
len = strlen(string) - 1;
if (len % 2 == 0) {
printf("%s", string);
}
}
The aim of this code is to print out inputs that have an even number of characters and omit anything else (will not print it). The program works when there is no space in the string however once I place a space it counts it as the length which I'm trying to stop. How do I make this program omit spaces when counting the length of the string?
How do I make the strlen() function not count spaces?
The standard function strlen() simple does not do that. Easy to code a new function that does.
#include <ctype.h>
#include <stddef.h>
size_t spaceless_strlen(const char *s) {
size_t len = 0;
const unsigned char *us = (const unsigned char *) s;
while (*us) {
if (*us != ' ') len++;
// Or if not counting white-spaces
if (!isspace(*us)) len++;
us++;
}
return len;
}
Best to pass unsigned char values to is...() functions so a unsigned char * pointer was used.
The trick is to only count characters you want. strlen() counts all characters. Write yourself a function:
#include <string.h>
size_t count( const char * s, int (*f)( int ) )
//
// Return the number of elements in the c-string
// `s` that satisfy the predicate function `f()`.
// The function type matches the Standard Library
// character classification functions in <ctype.h>.
{
size_t result = 0;
while (*s) result += f( *s++ );
return result;
}
With that in hand, you need a predicate function that will return 1 for non-whitespace characters, and 0 for whitespace characters. Easy enough:
#include <ctype.h>
int not_isspace( int c )
{
return !isspace( c );
}
Now you can totally count the number of non-whitespace characters in your string:
int length = count( s, &not_isspace );
That’s it!
Regarding how you can achieve counting characters that are not spaces, you can try this.
#include <stdio.h>
#include <string.h>
int main(void) {
char string[1024];
int len;
int count=0;
int i;
while (fgets(string, sizeof(string), stdin) != 0){
len = strlen(string) ;
for (i=0; i<len;i++)
{
if (string[i]!=' ')
count++;
}
if (count % 2 == 0)
{
printf("%s", string);
}
}
return 0;
}
Note: In my opinion, this isn't the most optimal way to achieve so but I tried to keep it based on your code and logic!
This seems better :
EDIT : it is if you replace the get function with fgets as you initially did!
#include <stdio.h>
#include <stdlib.h>
int main()
{
char str[1024];
int i=0,count=0;
printf("Enter a String\n");
gets(str);
while(str[i]!='\0')
{
if(str[i]!=' ')
{
count++;
}
i++;
}
if(count% 2 ==0)
{
printf("%s ",str,);
}
return 0;
}
It is possible to make a dedicated function using fgetc() instead of calling fgets() which returns the read string and its length (without counting the spaces):
#include <stdio.h>
#include <string.h>
#include <ctype.h>
static int my_fgets(char *s, int size, FILE *stream)
{
char c;
int len;
char *in;
if (!s || (size <= 0)) {
return 0;
}
len = 0;
in = s;
do {
c = fgetc(stream);
if ((len < (size - 1)) && (c != EOF) && (c != '\n')) {
if (!isspace(c)) {
len ++;
}
*(in ++) = c;
}
} while ((len < (size - 1)) && (c != EOF) && (c != '\n'));
*in = '\0';
return len;
}
int main(void) {
char string[1024];
int len = 0;
int i = 0;
len = my_fgets(string, sizeof(string), stdin);;
if (len % 2 == 0) {
printf("%s, len=%d\n", string, len);
}
}
If you aren't super-concerned about performance, the easiest to read version might be to call strchr repeatedly in a loop, count the spaces and then subtract them from the string length. Example:
size_t spaceout (const char* original)
{
size_t spaces = 0;
for(char* str=strchr(original,' '); str!=NULL; str=strchr(str+1,' '))
{
spaces++;
}
return strlen(original) - spaces;
}
This only looks for ' ' and it actually iterates over the string twice because of the final strlen call. But the code is quite easy to read.
A possible micro-optimization would be to pass the string length as parameter in case the caller already knows it.

Number of smallest length of string, in C

I want to make a program, which prints the number of smallest length of string. I have a file of words, which I open from stdin and save it to buffer.
My code so far prints the length of each word. But I can't figure out how to compare these numbers.
For example in file are:
Hello
Hi
My program does:
6
3
The output should be:
3
I can't figure ou how to continue. Do you have any advice?
#include <stdio.h>
int min_stat(char str[])
{
int min=0;
for(int i=0; str[i] != '\0'; i++)
{
min++;
}
return min;
}
int main(int argc, char *argv[])
{
if(argc < 1){
fprintf(stderr,"Error\n");
return 1;
}
char param = argv[1][0];
int val=100;
char buffer[val];
if(param == '1')
{
while(fgets(buffer, val, stdin) != NULL)
{
int a = min_stat(buffer);
printf("%d\n", a);
}
}
return 0;
}
You need to save the minimum lenght of the string somewhere and update it if a shorter string is detected. Your min_stat function returns the number of characters of the string.
I would use something like this:
#define MAX_LENGHT 1000
int main(int argc, char *argv[])
{
if(argc < 1){
fprintf(stderr,"Error\n");
return 1;
}
char param = argv[1][0];
int val=100;
char buffer[val];
/* the maximum possible lenght */
int min_lenght = MAX_LENGHT;
if(param == '1')
{
while(fgets(buffer, val, stdin) != NULL)
{
int a = min_stat(buffer);
/* update the mimimum lenght if it is smaller
than the current value */
if (a < min_lenght) {
min_lenght = a;
}
printf("%d\n", a);
}
}
/* print the minimum lenght */
printf("Minimum: %d\n", min_lenght);
return 0;
}
You should not use a variable to initialize the char array, because you are using Variable Lenght Arrays (VLA) and not static arrays. If you are learning c you should use static arrays and so:
char buffer[MAX_LENGHT];
where MAX_LENGHT is a constant or a pre-processor definition.

Error when extracting sub-string from the start of source string in C

This is from an exercise in Chapter 9 of Programming in C 4th Edition. The programme is to read in characters into a string and extract a portion of the string into a sub-string by specifying a start position and number of characters.
The programme compiles and runs well except when the zeroth position of the source is stated as the start. Nothing is then displayed.
This is my code.
/* Programme to extract a portion from a string using function
sub-string (source, start, count, result) ex9.4.c
ALGORITHM
Get text input into a char array (declare to be fixed size);
Determine length of source string;
Prepare result array to be dynamic length using desired count + 1;
Copy from source array into result array
*/
#include <stdio.h>
#include <stdbool.h>
#define MAX 501
void read_Line (char buffer[]);
int string_Length (char string[]);
void sub_String (char source[], int start, int count, char result[]);
int main(void)
{
char strSource[MAX];
bool end_Of_Text = false;
int strCount = 0;
printf("This is a programme to extract a sub-string from a source string.\n");
printf("\nType in your text (up to 500 characters).\n");
printf("When you are done, press 'RETURN or ENTER'.\n\n");
while (! end_Of_Text)
{
read_Line(strSource);
if (strSource[0] == '\0')
{
end_Of_Text = true;
}
else
{
strCount += string_Length(strSource);
}
}
// Declare variables to store sub-string parameters
int subStart, subCount;
char subResult[MAX];
printf("Enter start position for sub-string: ");
scanf(" %i", &subStart);
getchar();
printf("Enter number of characters to extract: ");
scanf(" %i", &subCount);
getchar();
// Call sub-string function
sub_String(strSource, subStart, subCount, subResult);
return 0;
}
// Function to get text input
void read_Line (char buffer[])
{
char character;
int i = 0;
do
{
character = getchar();
buffer[i] = character;
++i;
}
while (character != '\n');
buffer[i - 1] = '\0';
}
// Function to count determine the length of a string
int string_Length (char string[])
{
int len = 0;
while (string[len] != '\0')
{
++len;
}
return len;
}
// Function to extract substring
void sub_String (char source[], int start, int count, char result[])
{
int i, j, k;
k = start + count;
for (i = start, j = 0; i < k || i == '\0'; ++i, ++j)
{
result[j] = source[i];
}
result[k] = '\0';
printf("%s\n", result);
}
I am using Code::Blocks on Linux Mint.
Being someone that just started learning programming recently with CS50 and 'Programming in C' books, I did not know how to setup the debugger in Code::Blocks. But thanks to the push by #paulsm4, I managed to get the debugger working. Using the watches window of the debugger, I could see that the while loop in the main function was overwriting the first character in the source array with a null character. The fix was to add a break statement. Thanks to #WhozCraig and #Pascal Getreuer for pointing out other errors that I had missed. This is the corrected code now:
/* Programme to extract a portion from a string using function
sub-string (source, start, count, result) ex9.4.c
ALGORITHM
Get text input into a char array (declare to be fixed size);
Determine length of source string;
Prepare result array to be dynamic length using desired count + 1;
Copy from source array into result array
*/
#include <stdio.h>
#include <stdbool.h>
#define MAX 501
void read_Line (char buffer[]);
int string_Length (char string[]);
void sub_String (char source[], int start, int count, char result[]);
int main(void)
{
char strSource[MAX];
bool end_Of_Text = false;
int strCount = 0;
printf("This is a programme to extract a sub-string from a source string.\n");
printf("\nType in your text (up to 500 characters).\n");
printf("When you are done, press 'RETURN or ENTER'.\n\n");
while (! end_Of_Text)
{
read_Line(strSource);
if (strSource[0] == '\0')
{
end_Of_Text = true;
}
else
{
strCount += string_Length(strSource);
}
break;
}
// Declare variables to store sub-string parameters
int subStart, subCount;
char subResult[MAX];
printf("Enter start position for sub-string: ");
scanf(" %i", &subStart);
getchar();
printf("Enter number of characters to extract: ");
scanf(" %i", &subCount);
getchar();
// Call sub-string function
sub_String(strSource, subStart, subCount, subResult);
return 0;
}
// Function to get text input
void read_Line (char buffer[])
{
char character;
int i = 0;
do
{
character = getchar();
buffer[i] = character;
++i;
}
while (character != '\n');
buffer[i - 1] = '\0';
}
// Function to count determine the length of a string
int string_Length (char string[])
{
int len = 0;
while (string[len] != '\0')
{
++len;
}
return len;
}
// Function to extract substring
void sub_String (char source[], int start, int count, char result[])
{
int i, j, k;
k = start + count;
// Source[i] == '\0' is used in case count exceeds source string length
for (i = start, j = 0; i < k || source[i] == '\0'; ++i, ++j)
{
result[j] = source[i];
}
result[j] = '\0';
printf("%s\n", result);
}

How to compare an array to a reversed one and check if their values match?

I wrote a program that reverses an array with the strrev() function and checks if its values matches the original one, sort of a palindrome. When the values match, it prints Palindrome, else, Not a palindrome.
But when I compare them, and the values don't match, it still prints Palindrome.
Here is the code:
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <time.h>
#include <string.h>
#define MAX_LEN 100
void palindrom(char string[]);
int main()
{
char string[MAX_LEN] = { 0 };
printf("Enter string (max length 100 chars): ");
fgets(string, MAX_LEN, stdin);
if(string[strlen(string)-1] == '\n') { string[strlen(string)-1] = 0; }
palindrom(string);
return (0);
}
void palindrom(char string[])
{
int check = 0;
check = strcmp(strrev(string), string);
if (check == 0)
{
printf("Palindrome");
}
else
{
printf("Not a palindrome");
}
}
What's my problem? Thanks.
From what I can tell strrev may modify the original string as well, so you need to copy it.
The key is strrev.
Here's a program in C that will do what you're testing for:
#include <stdio.h>
#include <string.h>
int main()
{
char a[100], b[100];
printf("Enter the string to check if it is a palindrome\n");
fgets(a, 100, stdin);
strcpy(b,a);
strrev(b);
if (strcmp(a,b) == 0)
printf("Entered string is a palindrome.\n");
else
printf("Entered string is not a palindrome.\n");
return 0;
}
Since others have clarified what the problem is, I would like to point that it would be faster to check if s[0] == s[len-1], s[1] == s[len-2], until half (rounded up) of the string has been checked.
This would require no extra memory, no copy and half as many comparisons.
Something along the lines of:
void palindrom(char string[])
{
int len = strlen(string) - 1;
int i, limit = len/2 + (len % 2);
for (i = 0; i < limit; i++){
if (string[i] != string[len-i]){
printf("Not a palindrome\n");
return;
}
}
printf("Palindrome\n");
}
Your function fails because strrev modifies the string. You effectively always compare the reversed string to itself.
Here is an alternate function that does not modify the string:
void palindrom(const char *str) {
for (size_t i = 0, j = strlen(str); i < j; i++, j--) {
if (str[i] != str[j - 1]) {
printf("Not a palindrome\n");
return;
}
}
printf("Palindrome\n");
}
You don't need to use strrev to test for a palindrome the following function detects a palindrome just fine without using non-standard C functions:
int ispalindrome(char *str, int len)
{
char *p = &str[0];
char *q = &str[len - 1];
do
{
if(p >= q)
{
return 1;
}
} while (*p++ == *q--);
return 0;
}

Determine if two strings are anagram?

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
static int comp(const void *a, const void *b);
int main(int argc, char ** argv)
{
char s1[]="";
char s2[]="";
char *fmt = "%[^\n]%*c";
printf("Enter the first word? ");
scanf(fmt,&s1);
printf("Enter the second word? ");
scanf(fmt,&s2);
qsort(s1, strlen(s1), 1, comp);
qsort(s2, strlen(s2), 1, comp);
printf("%s : %s - %s\n", s1, s2, strcmp(s1, s2) ? "No" : "Yes");
return 0;
}
static int comp(const void *a, const void *b)
{
const char *pa = (char*)a;
const char *pb = (char*)b;
return
(*pa > *pb) ? 1 :
(*pa < *pb) ? -1 :
0;
}
When I key in 'smartest' as my first string and 'mattress' as my second string , my output becomes
emrsstt : aemrsstt - No
Why is the first character of the string missing?
Been sitting on this for hours. Gladly appreciate if someone could point out the silly mistake I may have made.
A smart way of doing this is to first check for a probable anagram. You do this by
Comparing the string lengths.
XORing every char from the total set; drawn from both strings.
If the result of (2) is not zero then the strings cannot possibly be anagrams. The advantage of doing this is that (2) is extremely fast in c and most strings are not anagrams, even if they are the same length. If your feeling particularly ambitious, you could combine (1) and (2) into a single O(N) algorithm!
Once you've done that, call your main code body. Your problem is in not allowing for the null terminator on each string. Your need to allocate enough space for the string characters plus one extra element for the null terminator.
Basically when you have to check whether any 2 set of values are same or not XOR operation is helpful.
Input Output
A B
0 0 0
0 1 1
1 0 1
1 1 0
So using this we can solve your problem as done below:
#include <stdio.h>
#include<stdlib.h>
#include <string.h>
int main()
{
int i=0,j=0,f;
char a[30] = "gooo";
char b[30] = "ooog";
if(strlen(a) == strlen(b))
{
while(a[i] != '\0')
{
j = 0;
f =0;
while(b[j] != '\0')
{
if( !(a[i] ^ b[j]) )
{
f =1;
break;
}
j++;
}
if(f)
i++;
else
break;
}
printf("%d\n",i);
if(i == strlen(a))
printf("Yes\n");
else
printf("No\n");
}
return 0;
}
Please check and the below solution for the anagram problem. This solution checks if two strings have identical counts for each unique char
bool anagram (char s[], char t[])
{
if (strlen(s) != strlen(t)){
return false;
}
int letters[256];
memset(letters,(int)0,sizeof(letters));
int numUniqueChars = 0;
int numCompletedT = 0;
int i;
for (i=0; i < strlen(s); i++){
if (letters[(int)s[i]]==0){
++numUniqueChars;
}
letters[s[i]]=letters[s[i]]+1;
}
for (i=0; i < strlen(t); i++){
int c = (int)t[i];
if (letters[c] == 0){
return false;
}
letters[c]=letters[c]-1;
if (letters[c] == 0){
numCompletedT++;
if (numUniqueChars==numCompletedT){
return i == strlen(t)-1;
}
}
}
return false;
}

Resources