Digit Frequency Program (HackerRank) - c

I'm trying to compare each character of the given string with numbers 0 to 9, and on successful comparison, increment the count variable. Finally, printing the value of count variable for each of the numbers.
But these method isn't working out. Can't figure out why.
int main() {
char *s;
s = malloc(1024 * sizeof(char));
scanf("%[^\n]", s);
int i,j,count=0;
for(i=0;i<=9;i++)
{
for(j=0;j<strlen(s);j++)
{
if(s[j]==i)
{
count++;
}
}
printf("%d ",count);
}
return 0;
}

Finally, printing the value of count variable for each of the numbers.
So you need an array to store counters for each digit. It is strange that zero is excluded from counted digits.
In this if statement
if(s[j]==i)
you have to write at least
if( s[j] - '0' == i )
And moreover this loop
for(i=0;i<=9;i++)
also tries to count zeroes though you wrote that to count only digits 1-9 inclusively.
Your approach is inefficient because you are traversing the same character array several times.
And there is no sense to allocate a character array dynamically.
The program can look the following way
#include <stdio.h>
int main(void)
{
enum { M = 9, N = 1024 };
char s[N];
s[0] = '\0';
size_t counter[M] = { 0 };
fgets( s, N, stdin );
for ( const char *p = s; *p; ++p )
{
if ( '0' < *p && *p <= '9' )
{
++counter[*p - '0' - 1];
}
}
for ( size_t i = 0; i < M; i++ )
{
printf( "%zu ", counter[i] );
}
putchar( '\n' );
return 0;
}
If to enter for example a string like
12345678987654321246897531
then the output will be
3 3 3 3 3 3 3 3 2
In fact the character array is redundant for this task. Moreover it restricts the length of the entered sequence of digits. You could write the program without using a character array. For example
#include <stdio.h>
int main(void)
{
enum { M = 9, N = 1024 };
size_t counter[M] = { 0 };
for ( int c; ( c = getchar() ) != EOF && c != '\n'; )
{
if ( '0' < c && c <= '9' )
{
++counter[c - '0' - 1];
}
}
for ( size_t i = 0; i < M; i++ )
{
printf( "%zu ", counter[i] );
}
putchar( '\n' );
return 0;
}

if(s[j]==i) <<<<<<<<<
{
count++;
}
You are comparing the ordinal value of the character to an integer in the range 0 to 9. Which is not what you want.
You can convert a digit to int with this method:
char c = '5';
int x = c - '0';
So in your case it would be:
if(s[j] -'0' ==i)
{
count++;
}

In C a character value is a number, but it is not the number you are expecting here. When we have the character '2' and we check what it is equal to as a number we are really asking what the ASCII code of '2' is which in this case would be 50. You need to adjust your code so it converts the ASCII code into a numeric representation so 50 becomes 2. It is quite simple simply change your code so it looks like this
if((s[j] - '0') == i){
This works because the ASCII code of 0 is 48, the ASCII code of 1 is 49, etc etc.
TL;DR In C a character value is not equal to it's numeric value. You need to convert '5' to 5. To do this you adjust your code so you subtract the '0' character from your numeric character.

Related

Checking whether a string consists of two repetitions

I am writing a function that returns 1 if a string consists of two repetitions, 0 otherwise.
Example: If the string is "hellohello", the function will return 1 because the string consists of the same two words "hello" and "hello".
The first test I did was to use a nested for loop but after a bit of reasoning I thought that the idea is wrong and is not the right way to solve, here is the last function I wrote.
It is not correct, even if the string consists of two repetitions, it returns 0.
Also, I know this problem could be handled differently with a while loop following another algorithm, but I was wondering if it could be done with the for as well.
My idea would be to divide the string in half and check it character by character.
This is the last function I tried:
int doubleString(char *s){
int true=1;
char strNew[50];
for(int i=0;i<strlen(s)/2;i++){
strNew[i]=s[i];
}
for(int j=strlen(s)/2;j<strlen(s);j++){
if(!(strNew[j]==s[j])){
true=0;
}
}
return true;
}
The problem in your function is with the comparison in the second loop: you are using the j variable as an index for both the second half of the given string and for the index in the copied first half of that string. However, for that copied string, you need the indexes to start from zero – so you need to subtract the s_length/2 value from j when accessing its individual characters.
Also, it is better to use the size_t type when looping through strings and comparing to the results of functions like strlen (which return that type). You can also improve your code by saving the strlen(s)/2 value, so it isn't computed on each loop. You can also dispense with your local true variable, returning 0 as soon as you find a mismatch, or 1 if the second loop completes without finding such a mismatch:
int doubleString(char* s)
{
char strNew[50] = { 0, };
size_t full_len = strlen(s);
size_t half_len = full_len / 2;
for (size_t i = 0; i < half_len; i++) {
strNew[i] = s[i];
}
for (size_t j = half_len; j < full_len; j++) {
if (strNew[j - half_len] != s[j]) { // x != y is clearer than !(x == y)
return 0;
}
}
return 1;
}
In fact, once you have appreciated why you need to subtract that "half length" from the j index of strNew, you can remove the need for that temporary copy completely and just use the modified j as an index into the original string:
int doubleString(char* s)
{
size_t full_len = strlen(s);
size_t half_len = full_len / 2;
for (size_t j = half_len; j < full_len; j++) {
if (s[j - half_len] != s[j]) { // x != y is clearer than !(x == y)
return 0;
}
}
return 1;
}
This loop
for(int j=strlen(s)/2;j<strlen(s);j++){
if(!(strNew[j]==s[j])){
true=0;
}
}
is incorrect. The index in the array strNew shall start from 0 instead of the value of the expression strlen( s ) / 2.
But in any case your approach is incorrect because at least you are using an intermediate array with the magic number 50. The user can pass to the function a string of any length.
char strNew[50];
The function can look much simpler.
For example
int doubleString( const char *s )
{
int double_string = 0;
size_t n = 0;
if ( ( double_string = *s != '\0' && ( n = strlen( s ) ) % 2 == 0 ) )
{
double_string = memcmp( s, s + n / 2, n / 2 ) == 0;
}
return double_string;
}
That is the function at first checks that the passed string is not empty and its length is an even number. If so then the function compares two halves of the string.
Here is a demonstration program.
#include <stdio.h>
#include <string.h>
int doubleString( const char *s )
{
int double_string = 0;
size_t n = 0;
if (( double_string = *s != '\0' && ( n = strlen( s ) ) % 2 == 0 ))
{
double_string = memcmp( s, s + n / 2, n / 2 ) == 0;
}
return double_string;
}
int main( void )
{
printf( "doubleString( \"\" ) = %d\n", doubleString( "" ) );
printf( "doubleString( \"HelloHello\" ) = %d\n", doubleString( "HelloHello" ) );
printf( "doubleString( \"Hello Hello\" ) = %d\n", doubleString( "Hello Hello" ) );
}
The program output is
doubleString( "" ) = 0
doubleString( "HelloHello" ) = 1
doubleString( "Hello Hello" ) = 0
Pay attention to that the function parameter should have the qualifier const because the passed string is not changed within the function. And you will be able to call the function with constant arrays without the need to defined one more function for constant character arrays.
it's better to do it with a while loop since you don't always have to iterate through all the elements of the string but since you want the for loop version here it is (C++ version):
int doubleString(string s){
int s_length = s.length();
if(s_length%2 != 0) {
return 0;
}
for (int i = 0; i < s_length/2; i++) {
if (s[i] != s[s_length/2 + i]){
return 0;
}
}
return 1;
}

How to add a sequence of numbers in a string to an integer array in c?

What I have is a string with some numbers (unknown amount but has a maximum), for example char string[] = "12 13 14 123 1234 12345"; and I wanna add each number to an array. So let's say I have an array int numbers[50]; and I want to add it to the array so it's like {12, 13, 14, 123, 1234, 12345}.
I've tried a loop through the string that uses a variable as a state machine to detect if it is reading a number but the code ended up looking like spaghetti so I just lost the way I was thinking. I cannot use malloc() or anything that allocates memory for this exercise.
Any ideas?
Here you are.
#include <stdio.h>
int main(void)
{
enum { N = 50 };
int numbers[N];
char *s = "12 13 14 123 1234 12345";
size_t n = 0;
char *p = s;
for ( int value, pos = 0; n < N && sscanf( p, "%d %n", &value, &pos ) == 1; p += pos )
{
numbers[n++] = value;
}
for ( size_t i = 0; i < n; i++ )
{
printf( "%d ", numbers[i] );
}
putchar( '\n' );
return 0;
}
The program output is
12 13 14 123 1234 12345
The state machine idea is good (albeit overkill; you only have three or four states after all).
You could use both this and Horner's Algorithm to parse the integer.
- set Horner accumulator to 0 and HaveNumber to 0 (false).
- loop:
- read character
- if digit:
- multiply Horner by 10
- add the value of the digit to Horner
- set HaveNumber to 1
- continue
- if HaveNumber:
push Horner onto array
set HaveNumber to 0
- set Horner to 0
- if character was a 0 instead of a space:
break
This does not need memory and does not necessarily use any function call (the digit check may be done verifying the ASCII value of the digit between 0x30 and 0x39)
You can use strtok to split string into substrings and then use atoi to convert that into ints.
#include <stdlib.h>
#include <string.h>
int main()
{
char my_string[] = "12 23 234 2345";
int my_array[50] = {0};
char* token = strtok(my_string, " ");
int i = 0;
while (token)
{
my_array[i] = atoi(token);
token = strtok(NULL, " ");
i++;
}
return 0;
}

Converting value from a string into an int

I have read this question ( Convert a string into an int ) before posting but I still have doubts.
I am very new to C and I'am trying to write a function which takes a string as parameter , something like this :
"99Hello" or "123ab4c"
And then returns the first the numbers it found into an int. So the result would be :
99 or 123
I'am trying to do this by finding the characters in the string(which correspond to numbers in the ASCII table) and then store them in the int I have created and returned by the function.
I'am having trouble though because when I find those character ( which correspond to numbers) I don't know how to save them to an int data type variable or how to convert them. I know there is a function called atoi which does this automatically but I would like to know how to do this by myself.
This is what I wrote so far :
int ReturnInt(char *str)
{
int i;
int new;
i = 0;
new = 0;
while (str[i] != '\0')
{
if( str[i] >= '0' && str[i] <= '9')
{
str[i] = new - '0';
}
i++;
}
return (new);
}
I think you should be able to form the desired integer from digits by multiplying them by 10 and adding them while iterating. Moreover, I think your loop's terminating condition should also include isDigit check
For example, for input 99Hello
i = 0, new = 0 -> new = 0 * 10 + 9 (9)
i = 1, new = 9 -> new = 9 * 10 + 9 (99)
i = 2, condition not satisfied as it's not a digit
int ReturnInt(char str[]) {
int i;
int new;
i = 0;
new = 0;
while (str[i] != '\0' && (str[i] >= '0' && str[i] <= '9'))
{
int currentDigit = str[i] - '0';
new = new * 10 + currentDigit;
i++;
}
return (new);
}
You just have to take a place holder , and that has to be multiplied by 10 for every iteration so that we get 10, 100, 1000 place holders and we can add that quantity to remaining numbers.
#include <stdio.h>
#include <ctype.h>
int str2num(char*strnum);
int main()
{
char *num1 = "122AB";
char *num2 = "2345AB9C";
char *num3 = "A23AB9C";
printf("num1 = %d\n", str2num(num1));
putchar('\n');
printf("num2 = %d\n", str2num(num2));
putchar('\n');
printf("num3 = %d\n", str2num(num3));
return 0;
}
int str2num(char*strnum)
{
int num = 0;
int ph = 10;// for getting tens,100s etc
while(strnum && *strnum && isdigit(*strnum))
{
num = num * ph + ( (*strnum) - '0');
strnum++;
}
return num;
}

Wanted to do caesar's cipher but couldn't change the last two characters

I wrote a code for caesar's cipher and the code works except I can't cipher more than 8 letters and I also can't handle spaces. It shows ">>" this symbol instead of spaces. Also, I wanted to do binary search in the second function of my code but I don't know whether I have done that or not.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char caesar (char x, char alphabets[]);
int j;
int main()
{
char* plain_text = malloc (10 * sizeof(char) + 1);
int key, num;
char* cipher_text = malloc (10 * sizeof(char) + 1);
printf("Plain text: ");
gets(plain_text);
printf("\nThe plain text is: ");
puts(plain_text);
printf("\nKey: ");
scanf("%d", &key);
num = (int)key;
if (key != num)
{
return 1;
}
int i;
char alphabets[] = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};
for (i=0;i<=strlen(plain_text);i++)
{
char x = plain_text[i];
caesar(x, alphabets);
cipher_text[i] = alphabets[j+key];
printf("%c", cipher_text[i]);
}
free(plain_text);
}
char caesar (char x, char alphabets[])
{
if(x == alphabets[13])
{
return 13;
}
for(j = 1; j <= 13; j++)
{
if(x == alphabets[j])
{
return j;
}
}
for(j = 13; j <= strlen (alphabets); j++)
{
if(x == alphabets[j])
{
return j;
}
}
}
caesar() appears to simply return the position of characters b to z in the array in a remarkably over complex manner and omits a altogether! Moreover since alphabets is not a null terminated string strlen() is not a valid operation in any case. The "encryption" is done (incorrectly) by alphabets[j+key] in main() making caesar() particularly poorly named - since that is not what it does at all.
The following function will return the the cipher of any character in alphabet, and leave any other character unmodified:
char caesar( char x, int key )
{
const char alphabet[] = {'a','b','c','d','e','f','g','h',
'i','j','k','l','m','n','o','p',
'q','r','s','t','u','v','w','x',
'y','z'};
char cipher = x ;
for( int i = 0;
cipher == x && i < sizeof( alphabet );
i++ )
{
if( alphabet[i] == x )
{
cipher = alphabet[(i + key) % sizeof( alphabet )] ;
}
}
return cipher ;
}
It makes far more sense to pass key to ceasar() that to pass the constant alphabet, and to do the encryption where is alphabet is "known". Splitting the cipher steps between caesar() and main() as you had done is a poor design and lacks cohesion and has unnecessary coupling.
If the character x appears in alphabet it is modified by alphabet[(i + key) % sizeof( alphabet )] ;. This adds the key as you had, but also "wraps-around" (the % modulo operation), so that for example for key = 1, z wraps around to a rather then referencing a byte beyond the end of the alphabet array as your code had. Critically, if it does not appear in alphabet, it is unmodified - that is why cipher is initialised with x. The loop exits when cipher is modified (cipher != x), or when the end of alphabet is reached.
Then in the iteration of plain_text:
for (i = 0; i <= strlen(plain_text); i++ )
{
cipher_text[i] = caesar( plain_text[i], key ) ;
}
The <= strlen() here is unusual, but here it ensures the nul terminator is copied to cipher_text - it will not be modified by caesar().
Note that the the above solution only encrypts lower case text (as does your original code). There are other issues and ill-advised practices in your code, discussed in the comments but not perhaps directly relevant to your question, but using the above function, the following complete implementation addresses most of the issues:
#include <stdio.h>
#include <string.h>
char caesar( char x, int key ) ;
#define MAX_TEXT 128
int main()
{
char plain_text[MAX_TEXT] = "" ;
char cipher_text[MAX_TEXT] = "" ;
printf( "Plain text: " );
fgets( plain_text, MAX_TEXT, stdin ) ;
printf( "\nThe plain text is: %s\n", plain_text ) ;
printf( "Key: " ) ;
int key = 0 ;
scanf( "%d", &key );
for( size_t i = 0; i <= strlen( plain_text ); i++ )
{
cipher_text[i] = caesar( plain_text[i], key ) ;
}
printf( "\nThe cipher text is: %s\n", cipher_text ) ;
return 0 ;
}
Example:
Plain text: abc, xyz
The plain text is: abc, xyz
Key: 1
The cipher text is: bcd, yza
Modification to allow capital letters:
#include <ctype.h>
char caesar( char x, int key )
{
const char alphabet[] = {'a','b','c','d','e','f','g','h',
'i','j','k','l','m','n','o','p',
'q','r','s','t','u','v','w','x',
'y','z'};
char cipher = x ;
for( int i = 0;
cipher == x && i < sizeof( alphabet );
i++ )
{
if( alphabet[i] == tolower( x ) )
{
cipher = alphabet[(i + key) % sizeof( alphabet )] ;
if( isupper( x ) )
{
cipher = toupper( cipher ) ;
}
}
}
return cipher ;
}
Here the test alphabet[i] == tolower( x ) ignores the case, and then when a match is fount the application of cipher = toupper( cipher ) if x is upper case, yields the upper case cipher.
Example output:
Plain text: aBc, XyZ 123
The plain text is: aBc, XyZ 123
Key: 1
The cipher text is: bCd, YzA 123
Note that instead of testing cipher = x in the for loop, you could break after cipher is assigned in the loop - reducing the number of tests - but that arguably breaks structured programming "rules" - I would not criticise its use by others, but it is not my preference. You might also use isalpha(x) in this case to skip the loop altogether, but that has implementation defined behaviours for accented characters for example, so if you were to extend the supported "alphabet", it might fail to work as intended.
If you only ever use the characters a to z in the alphabet as you have, then a further simplification is possible where the cipher can be determined arithmetically using character code values:
char caesar( char x, int key )
{
char cipher = tolower( x ) ;
if( isalpha( x ) )
{
cipher = ((cipher - 'a') + key) % ('z' - 'a' + 1) + 'a' ;
if( isupper( x ) )
{
cipher = toupper( cipher ) ;
}
}
return cipher ;
}
Strictly this assumes that the characters a to z are contiguous in the target character set, but that is universally true for any system you are likely to run this code on (i.e. not an IBM Z series mainframe or various antique mainframe/mini computers), and if not the alphabet array solution remains valid. I point this out only because otherwise someone will place a comment about it as if it is really an issue.
To explain the expression: cipher = ((cipher - 'a') + key) % ('z' - 'a' + 1) + 'a' :
(cipher - 'a') - subtract the code for 'a' to get a value 0 to 25 for characters a to z.
... + key - add the key "shift"
... % ('z' - 'a' + 1) - this constant expression resolves to % 26 in practice, to "wrap-around".
... +a- transform the range 0 to 25 back into character codesatoz`.

getting the length of initiated values in a character array

So lets say I have a character array called str of size 12, and I input 1000110 in the array, with str[0] = 1, str[1] = 0 etc... I tested the array by printing it in a for loop, it works.
I then want to count how many integers are initiated in the array. In this case, the value should be: 7
Here is my code, for whatever reason, the output is 1, not 7.
int length;
length = 12;
int actual_length()
{
int act_length = 0;
int i;
for (i = 0; i < length; i++)
{
if ( str[i] == 0 || str[i] == 1 )
{
act_length++;
}
}
printf("TEST ACTUAL LENGTH: %d\n", act_length);
return act_length;
}
I also tried
(int)str[i]
for the comparisons, but that did not change the outcome.
You have a string that consists of characters.
You need to compare against the character value:
if ( str[i] == '0' || str[i] == '1' )

Resources