problem in comparing string to a integer i guess - c

This code is not working, how many times the number 0 to 9 is repeated in a given string.
This is the question, itis from hackerrank:
Given a string, S, consisting of alphabets and digits, find the frequency of each digit in the given string.
I can't find any error in my logic.
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
int main()
{
/* Enter your code here. Read input from STDIN. Print output to STDOUT */
char s[1000];
int count[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
char temp;
scanf("%s", s);
for (int i = 0; i < 10; i++)
{
temp = i;
for (int j = 0; j < strlen(s); j++)
{
if (s[j] == i)
{
count[i] = count[i] + 1;
continue;
}
else
{
continue;
}
}
}
for (int k = 0; k < 10; k++)
{
printf("%d ", count[k]);
}
return 0;
}

At least you need to write
if (s[j] == i + '0')
Otherwise you are trying to compare a character like '0' that can have the ASCII code 48 with integer 0.
But in any case the for loops are inefficient.
It is better to write:
for (const char *p = s; *p; ++p)
{
if ('0' <= *p && *p <= '9') ++count[*p - '0'];
}

You are comparing a character to an integer. Now, char is a numeric type, so you can do this, but the results are not what you expect. The character '0' in ASCII is 48, for example.
You can convert 0 or 1 or any other single digit to its ASCII representation, by adding it to '0'.

if (s[j] == i) => here s is defined as a character and i is defined as an integer. So to solve this problem you have to convert your integer to a character. sprintf() could work or a simple +'0'.

Related

C language: How to find the largest number created by digits from n using string

Question:Find the largest number and smallest created by digits from n (n<10 ^50) .
I have tried like the below but in some cases, it's wrong
For example:
Case 1: Input 2015 Output 5210
Case 2: Input 47356359122 Output(Wrong answer)
Help me please, I don't know why I got the wrong answer!!!
#include <stdio.h>
#include <string.h>
void max(char s[]) {
int l = strlen(s);
int i, key, j;
for (i = 1; i < l; i++) {
key = s[i];
j = i - 1;
while (j >= 0 && s[j] > key) {
s[j + 1] = s[j];
j = j - 1;
}
s[j + 1] = key;
}
s[l - 1] = '\0';
printf("%s\n", s);
}
int main() {
char s[100];
fgets(s, sizeof(s), stdin);
max(s);
}
Your approach is correct: sorting the digits in decreasing order produces the largest number from these digits.
Your implementation is flawed:
you actually sort them in increasing order. You should change while (j >= 0 && s[j] > key) to
while (j >= 0 && s[j] < key)
the null terminator is set at the wrong position: you clear the last character in s. If the line read from stdin ends with a newline, this may erase it, unless the user typed a TAB character, but if the input consists only of digits, the last one will be removed. Change the code to:
s[l - 1] = '\0';
Here is an alternative using counting sort:
#include <stdio.h>
void max_number(char s[]) {
/* array to store the number of occurrences of each digit */
int count[10] = { 0 };
int i, d, c;
/* enumerate all characters from the string, stop at the null terminator */
for (i = 0; s[i]; i++) {
/* only count digits from '0' to '9' */
if (s[i] >= '0' && s[i] <= '9') {
/* increase the digit count for this digit */
count[s[i] - '0']++;
}
}
/* output the digits from highest to lowest */
for (i = 0, d = 10; d --> 0;) {
for (c = count[d]; c --> 0;)
s[i++] = '0' + d;
}
if (i == 0) {
/* there were no digits in the string: store a 0 */
s[i++] = '0';
}
if (s[0] == '0') {
/* there were only zeroes in the string: keep a single 0 */
i = 1;
}
/* set the null terminator */
s[i] = '\0';
printf("%s\n", s);
}
int main() {
char s[100];
if (fgets(s, sizeof(s), stdin))
max_number(s);
return 0;
}
User chqrlie already provided an excellent general answer. Here is an addition with a simpler, slightly less efficient approach.
Observing that it is not necessary to actually store the result in a new string, you could also print the digits - high to low - as you find them. This program loops over the input string 10 times, first printing all 9s, then all 8s, etc.
#include <stdio.h>
void max(char *str) {
for (char digit = '9'; digit >= '0'; --digit) // Assume ASCII
for (char *strCp = str; *strCp != '\0' ; ++strCp)
if (*strCp == digit)
putchar(digit);
putchar('\n');
}
int main(void) {
char s[100];
if (fgets(s, sizeof(s), stdin) != NULL)
max(s);
}
Note:
No strlen function is used, so the string.h header is no longer needed.
Changed the main signature to int main(void), which is suggested by the standard in case the parameters are not used.
Checking the return value of fgets, so the program can handle empty input and input failure.
For starters the function should not output any message. It is the caller if the function that decides whether to output a message.
The function should return a modified string characters of which are sorted as digit in the descending order.
Your function can invoke undefined behavior when an empty string is passed to the function
void max(char s[]) {
int l = strlen(s);
int i, key, j;
//...
s[l - 1] = '\0';
printf("%s\n", s);
}
because in this statement
s[l - 1] = '\0';
there is an attempt to access memory beyond the passed string. And in general the statement is wrong because the terminating zero must be present in the position l .
There is no need to set the terminating zero character '\0' because it is already present in the string. So the above statement is just redundant.
In fact you are trying to sort characters of the string using the insertion sort method in the ascending order due to the condition in this if statement.
while (j >= 0 && s[j] > key) {
In this case the new line character '\n' that is present in the string after calling the function fgets will be moved at the beginning of the string.
You have to sort the string in the descending order.
And the new line character '\n' should be removed from the string before calling the function.
The function can be declared and defined for example the following way as it is shown in the demonstrative program below.
#include <stdio.h>
#include <string.h>
char * max_number( char *s )
{
if ( *s )
{
for ( char *p = s + 1; *p; ++p )
{
char c = *p;
char *q = p;
for ( ; q != s && *( q - 1 ) < c; --q )
{
*q = *( q - 1 );
}
if ( q != p ) *q = c;
}
}
return s;
}
int main(void)
{
char s[100];
fgets( s, sizeof( s ), stdin );
s[ strcspn( s, "\n" ) ] = '\0';
puts( max_number( s ) );
return 0;
}
If to enter the number 47356359122 using fgets then the program output will be
97655433221

How do I compare an integer with a character in a string in C?

I want to compare the integers in a string with integers (0-9) and I wrote this -
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
int main() {
char num[100];
int count = 0;
scanf("%s", num);
int len = strlen(num);
for (int i = 0; i <= 9; i++)
{
for (int j = 0; j <= len; j++)
{
if (i == (num[j] - '0'))
{
count++;
}
}
printf("%d ", count);
count = 0;
}
return 0;
}
No problems with this (works in most cases but it is failing in few cases). So can you please give me alternate and best idea to do this?
Thanks in advance
Complete pic -
The root cause is not in char comparison, but in the under-allocated buffer:
char num[100];
The assignment constraint is:
1 <= len(num) <= 1000
After increasing the buffer size, all the tests pass.
Besides a too small input buffer (i.e. 100 instead of 1001), I think your approach is too complex.
Instead of a nested loop, I'll suggest an array to count the frequency, i.e. an array with 10 elements so that you have a counter for each digit.
int main() {
char num[1001]; // 1000 chars + 1 zero termination
int count[10] = {0}; // Array of 10 zero initialized counters, one for each digit
scanf("%1000s", num); // At max accept 1000 chars input
char* p = num;
while (*p)
{
if (isdigit(*p) ++count[*p - '0'];
++p;
}
for (int i = 0; i < 10; ++i) printf("%d ", count[i]);
puts("");
return 0;
}
If you don't want to use isdigit you can instead do:
if (*p >= '0' && *p <= '9') ++count[*p - '0'];

How to read multiple digit number from a string

I am trying to pass a string S as input. Here the string S can contain multiple integer values followed by an alphabet. The program must expand the alphabets based on the previous integer value.
Consider the Input: 4a5h
For which the Output: aaaahhhhh, that is 4 times a and 5 times h
Also for Input: 10a2b
Output: aaaaaaaaaabb, that is 10 times a and 2 times b
This is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char s[1000], alp[1000];
int num[1000];
int n = 0;
int i, j, k, m;
k = 0;
scanf("%[^\n]s", s);//Reads string until newline character is encountered
for (i = 0; i < strlen(s); i++) {
if (isalpha(s[i])) {
alp[n] = s[i]; // alp[] stores the alphabets
n += 1;
} else {
num[k] = s[i] - '0';// num[] stores the numbers
k += 1;
}
}
for (i = 0; i < k; i++) {
for (m = 0; m < num[i]; m++)
printf("%c", alp[i]);
}
return 0;
}
But with this code I am not able to read 2 or 3 or a N digit number. So if the Input is 100q1z then the alp[] array is fine but num[] array is not containing 100 and 1 as its elements instead 1 and 0 are its elements.
How do I correct this code?
You should modify the loop to handle as many digits are present successively int the string:
#include <ctype.h>
#include <stdio.h>
int main(void) {
char s[1000], alp[1000];
int num[1000];
int i, k = 0, m, n;
//Read string until newline character is encountered
if (scanf("%999[^\n]", s) == 1) {
for (i = 0; s[i]; i++) {
n = 1;
if (isdigit((unsigned char)s[i])) {
for (n = s[i++] - '0'; isdigit((unsigned char)s[i]); i++) {
n = n * 10 + s[i] - '0';
}
}
if (isalpha((unsigned char)s[i])) {
alp[k] = s[i]; // store the letter
num[k] = n; // store the number
k += 1;
}
}
for (i = 0; i < k; i++) {
for (m = 0; m < num[i]; m++)
putchar(alp[i]);
}
}
putchar('\n');
return 0;
}
Notes:
include <ctype.h> to use isalpha().
protect the destination array of scanf by passing a maximum number of characters and check the return value.
the format for converting a non empty line is simply %[^\n], the trailing s is incorrect. Note that unlike fgets(), this scanf() format will fail if the line is empty.
you should always test the return value of scanf().
cast the char argument to isalpha() and isdigit() as (unsigned char) to avoid undefined behavior if char is signed and has a negative value.
use putchar(c) to output a single character instead of printf("%c", c);
The part of else-bolock must be looped.
like this
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h> //need this for isalpha and isdigit
int main(void){
char s[1000], alp[1000];
int num[1000];
int m = 0, n = 0;
int i, j;
unsigned char ch;//convert char to unsigned char before use isalpha and isdigit
scanf("%999[^\n]", s);//remove s after [^\n] and Add limit
for(i = 0; ch = s[i]; i++){//replace strlen each loop
if(isalpha(ch)){
alp[n++] = s[i];
} else if(isdigit(ch)){
num[m] = 0;
while(isdigit(ch = s[i])){
num[m] = num[m] * 10 + s[i] - '0';
++i;
}
++m;
--i;//for ++i of for-loop
} else {//Insufficient as validation
printf("include invalid character (%c).\n", ch);
return -1;
}
}
for(i = 0; i < m; i++){
for(j = 0; j < num[i]; j++)
printf("%c", alp[i]);
}
puts("");
return 0;
}
The problem with the code is that when you encounter a digit in the string, you are considering it as a number and storing it in num array. This is fine if you have only single digit numbers in the array. For multidigit numbers do this- read the string for digits until you find a alphabet, form a number using the obtained digits and then save it to num array.I m leaving the code for you.

char into int and calculate sum of int

I want split the following string into alphabet and numbers, then I need to calculate the sum of the numbers. My sample question is a[20]={"abcd123dc2"};
Expected output:
abcddc 8
My code:
int main()
{
char a[20] = {"abcd123dc2"};
int l = 0, m = 0, n = 0, j, cc = 0, ll = 0;
char b[20];
char c[10];
l = strlen(a);
printf("%d", l);
for (j = 0; j < l; j++)
{
if (a[j] == 'a' || a[j] == 'b' || a[j] == 'd' || a[j] == 'c')
{
b[m] = a[j];
m++;
}
}
b[m] = '\0';
for (j = 0; j < l; j++)
{
if (a[j] == '3' || a[j] == '2' || a[j] == '1')
{
c[n] = a[j];
n++;
}
}
ll = strlen(c);
atoi(c);
for (j = 0; j < ll; j++)
{
cc += c[j];
}
printf("%d\n\n", cc);
printf("%s", b);
getch();
return 0;
}
char a[20]={"abd123vf"};
int l=0,m=0,j,cc=0;
char b[20];
l=strlen(a);
for(j=0;j<l;j++)
{
if(a[j]> 47 && a[j] <58){
cc+ = a[j] - '0';
}
else{
b[m]=a[j];
m++;
}
}
b[m]='\0';
printf("%d\n\n",cc);
printf("%s",b);
getch();
return 0;
Edit after the first comment:
Since you have not specifically mentioned a problem, I assume you are looking for a better way of writing this code.
Instead of looping through your string twice, you can do it in a single go.
Instead of checking for individual numbers or letters, you can check if the character is in the range : 48 - 57 [i.e., 0 to 9]
Instead of two if conditions, you can go for an else.
[Note that even the special characters in the original string will be part of your new string in this case]
a[j] - '0' will give the actual number in the string. eg:
if the number is 5, a[j] will be 53;
'0' is 48; 53 - 48 = 5 and that's what you add to your sum
Your code is OK for the most part.
There is one error in computing c. Instead of
cc += c[j]; // The integer value of c[j] when it is `0` is 48, not 0
You need to use
cc += c[j] - '0';
Based on your expected output at the top of the question, your printf lines
printf("%d\n\n",cc);
printf("%s",b);
need to be
printf("%s %d\n",b,cc);
Other
You have an unnecessary call to atoi. Was that just for debugging?
I wouldn't do it this way, the algorithm is actually quite simple. Works for every string.
char a[] = "abcd123dc2";
char b[20];
char c[20];
int i, spotinnumbers = 0, spotincharacters = 0;
for(i = 0 ; i < strlen(a) ; i++)
{
if((a[i] >= 'a' && a[i] <= 'z') || (a[i] >= 'A' && a[i] <= 'Z'))
{
b[spotincharacters] = a[i];
spotincharacters++;
}
else if(a[i] >= '0' && a[i] <= '9')
{
c[spotinnumbers] = a[i];
spotinnumbers++;
}
}
b[spotincharacters] = '\0';
c[spotinnumbers] = '\0';
Some explanation of the code. Basically, it's not splitting, just having another two strings, one of the alphabet in the main string and one of the numbers in it. We use one loop to run on the string and decide whether the character is an alphabet letter or a number and assign it in the right place.
About the sum calculation... As we have the numbers in c:
int total = 0;
for(i = 0 ; i < strlen(c) ; i++)
{
total += c[i]-'0';
}
explanation about this piece of code, in this code, as a string in C is simply an array of characters, in the string we have the characters resembling the numbers but the characters' value in numeric is something called ASCII value. You can look at the ASCII Table and find out that each character has a numeric value and there's an overall of 256 characters (2^8) which is why a character takes one byte (1 byte = 8 bits = 2^8 possibilities for different numbers). '0''s ASCII is 48 and that's how we basically turn a number from a character to its true numeric value. for 0 (48-48 = 0) and for 1 (49-48 = 1) as all number characters in the ASCII table are in a series.
The actual problem in the code isn't just efficiency as there is no need to run in two loops and so, you enter the numeric values of the numbers into C ! which turns them to different characters.

scan n numbers without spaces in C

Suppose n numbers are to be input in a single line without any spaces given the condition that these numbers are subject to the condition that they lie between 1 and 10.
Say n is 6 , then let the input be like "239435"
then if I have an array in which I am storing these numbers then I should get
array[0]=2
array[1]=3
array[2]=9
array[3]=4
array[4]=3
I can get the above result by using array[0]=(input/10^n) and then the next digit
but is there a simpler way to do it?
Just subtract the ASCII code of 0 for each digit and you get the value of it.
char *s = "239435"
int l = strlen(s);
int *array = malloc(sizeof(int)*l);
int i;
for(i = 0; i < l; i++)
array[i] = s[i]-'0';
update
Assuming that 0 is not a valid input and only numbers between 1-10 are allowed:
char *s = "239435"
int l = strlen(s);
int *array = malloc(sizeof(int)*l);
int i = 0;
while(*s != 0)
{
if(!isdigit(*s))
{
// error, the user entered something else
}
int v = array[i] = *s -'0';
// If the digit is '0' it should have been '10' and the previous number
// has to be adjusted, as it would be '1'. The '0' characater is skipped.
if(v == 0)
{
if(i == 0)
{
// Error, first digit was '0'
}
// Check if an input was something like '23407'
if(array[i-1] != 1)
{
// Error, invalid number
}
array[i-1] = 10;
}
else
array[i] = v;
s++;
}
E.g.
int a[6];
printf(">");
scanf("%1d%1d%1d%1d%1d%1d", a,a+1,a+2,a+3,a+4,a+5);
printf("%d,%d,%d,%d,%d,%d\n", a[0],a[1],a[2],a[3],a[4],a[5]);
result:
>239435
2,3,9,4,3,5
You can use a string to take the input and then check each position and extact them and store in an array. You need to check for the numeric value in each location explicitly, as you are accepting the input as a string. For integers taken input as string, there's no gurantee that the input is pure numeric and if it is not, things can go wild.
check this code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char ipstring[64];
int arr[64];
int count, len = 0;
printf("Enter the numbersi[not more than 64 numbers]\n");
scanf("%s", ipstring);
len = strlen(ipstring);
for (count = 0; count < len ; count++)
{
if (('0'<= ipstring[count]) && (ipstring[count] <= '9'))
{
arr[count] = ipstring[count] - '0';
}
else
{
printf("Invalid input detectde in position %d of %s\n", count+1, ipstring );
exit(-1);
}
}
//display
for (count = 0; count < len ; count++)
{
printf("arr[%d] = %d\n", count, arr[count]);
}
return 0;
}

Resources