I am solving this problem:
Given a string str containing alphanumeric characters, calculate sum
of all numbers present in the string.
Input:
The first line of input contains an integer T denoting the number of test cases. Then T test
cases follow. Each test case contains a string containing alphanumeric characters.
Output:
Print the sum of all numbers present in the string.
Constraints:
1 <= T<= 105
1 <= length of the string <= 105
Example:
Input:
4
1abc23
geeks4geeks
1abc2x30yz67
123abc
Output:
24
4
100
123
I have come up with the following solution:
#include <stdio.h>
#include <string.h>
int main() {
//code
int t,j;
char a[100000];
scanf("%d",&t);
while(t--)
{
int sum=0,rev=0,i=0,l;
scanf("%s",a);
l=strlen(a);
for(i=0;i<l;i++)
{
if (isdigit(a[i])){
while(isdigit(a[i])){
rev = rev *10 + (a[i]-48);
i++;
}
}
sum+=rev;
rev=0;
}
printf("%d\n",sum);
}
return 0;
}
This code is working fine.
BUT if loop termination condition is changed from i < l to a[i]!='\0', then code doesn't work. Why?
I would loop backwards over the string. No nested loops. Just take the 10s exponent as you move left
You have the length of the string, so there should be no reason to check for NUL char yourself
(untested code, but shows the general idea)
#include <math.h>
l=strlen(a);
int exp;
exp = 0;
for(i = l-1; i >= 0; i--)
{
if (isdigit(a[i])) {
rev = a[i]-48; // there are better ways to parse characters to int
rev = (int) pow(10, exp) * rev;
sum += rev; // only add when you see a digit
} else { exp = -1; } // reset back to 10^0 = 1 on next loop
exp++;
}
Other solutions include using regex to split the string on all non digit characters, then loop and sum all numbers
You will have to change the logic in your while loop as well if you wish to change that in your for loop condition because it's quite possible number exists at the end of the string as well, like in one of your inputs 1abc2x30yz67. So, correct code would look like:
Snippet:
for(i=0;a[i]!='\0';i++)
{
if (isdigit(a[i])){
while(a[i]!='\0' && isdigit(a[i])){ // this line needs check as well
rev = rev *10 + (a[i]-48);
i++;
}
}
sum+=rev;
rev=0;
}
On further inspection, you need the condition of i < l anyways in your while loop condition as well.
while(i < l && isdigit(a[i])){
Update #1:
To be more precise, the loop while(isdigit(a[i])){ keeps going till the end of the string. Although it does not cause issues in the loop itself because \0 ain't a digit, but a[i] != '\0' in the for loop condition let's you access something beyond the bounds of length of the string because we move ahead 1 more location because of i++ in the for loop whereas we already reached end of the string inside the inner while loop.
Update #2:
You need an additional check of a[i] == '\0' to decrement i as well.
#include <stdio.h>
#include <string.h>
int main() {
//code
int t,j;
char a[100000];
scanf("%d",&t);
while(t--)
{
int sum=0,rev=0,i=0,l;
scanf("%s",a);
l=strlen(a);
for(i=0;a[i]!='\0';i++)
{
if (isdigit(a[i])){
while(a[i] != '\0' && isdigit(a[i])){ // this line needs check as well
rev = rev *10 + (a[i]-48);
i++;
}
}
if(a[i] == '\0') i--; // to correctly map the last index in the for loop condition
sum+=rev;
rev=0;
}
printf("%d\n",sum);
}
return 0;
}
Update #3:
You can completely avoid the while loop as well as shown below:
#include <stdio.h>
#include <string.h>
int main() {
//code
int t,j;
char a[100005];
scanf("%d",&t);
while(t--)
{
int sum=0,rev=0,i=0,l;
scanf("%s",a);
l=strlen(a);
for(i=0;i<l;i++) {
if (isdigit(a[i])){
rev = rev * 10 + (a[i]-48);
}else{
sum += rev;
rev = 0;
}
}
printf("%d\n",sum + rev); // to also add last rev we captured
}
return 0;
}
Other answers have pointed out the correct loop conditions to ensure proper operation of your program.
If you are allowed to use library functions other than isdigit, I would recommend using strtol with the EndPtr parameter (output parameter that points to the character in the string that caused strtol to stop scanning a number):
char str[] = "1abc23def5678ikl";
int main()
{
char *pStop = str;
int n, accum = 0;
size_t len = strlen(str);
do
{
n = strtol(pStop, &pStop, 10);
pStop++;
if(n)
{
printf("%d\n", n);
accum += n;
}
}
while(pStop < &str[len]);
printf("Total read: %d\n", accum);
return 0;
}
Related
So, I was writing this code for counting the digit frequency i.e. the number of times the digits from 0-9 has appeared in a user inputted string(alphanumeric). So, I took the string, converted into integer and tried to store the frequency in "count" and print it but when I run the code, count is never getting incremented and the output comes all 0s. Would be grateful if anyone points out in which part my logic went wrong.
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
int main() {
// takes string input
char *s;
s = malloc(1024 * sizeof(char));
scanf("%[^\n]", s);
s = realloc(s, strlen(s) + 1);
//turns the string to int
int x = atoi(s);
int temp = x, len = 0;
//calculates string length
while (x != 0) {
x = x / 10;
len++;
}
x = temp;
//parses through the string and matches digits with each number
for (int j = 0; j < 10; j++){
int count = 0;
for(int i = 0; i < len; i++){
if(x % 10 == j){
count++;
}
x = x / 10;
}
x = temp;
printf("%d ", count);
}
return 0;
}
To write a correct and reasonable digit-counting program:
Do not allocate any buffer for this.
Create an array to count the number of times each digit occurs. The array should have ten elements, one for each digit.
Initialize the array to zero in each element.
In a loop, read one character at a time.
Leave the loop when the read routine (such as getchar) indicates end-of-file or a problem, or, if desired, returns a new-line or other character you wish to use as an end-of-input indication.
Inside the loop, check whether the character read is a digit. If the character read is a digit, increment the corresponding element of the array.
After the loop, execute a new loop to iterate through the digits.
Inside that loop, for each digit, print the count from the array element for that digit.
Your approach is way to complicated for a very easy task. This will do:
void numberOfDigits(const char *s, int hist[10]) {
while(*s) {
if(isdigit(*s))
hist[*s - '0']++;
s++;
}
}
It can be used like this:
int main(void) {
char buf[1024];
int hist[10];
fgets(buf, sizeof buf, stdin);
numberOfDigits(s, hist);
for(int i=0; i<10; i++)
printf("Digit %d occurs %d times\n", i, hist[i]);
}
This can also be quite easily achieved without a buffer if desired:
int ch;
int hist[10];
while((ch = getchar()) != EOF) {
if(isdigit(ch))
hist[ch - '0']++;
}
#include <stdio.h>
int main(void) {
int input = 1223330;
int freq[10] = {0};
input = abs(input);
while(input)
{
freq[input%10]++;
input /= 10;
}
for(int i=0; i<10; ++i)
{
printf("%d: %.*s\n", i, freq[i], "*************************************************");
}
return 0;
}
Output:
Success #stdin #stdout 0s 5668KB
0: *
1: *
2: **
3: ***
4:
5:
6:
7:
8:
9:
This app is currently limited by the size of an int (approximately 9 or 10 digits).
You can update it to use a long long easily, which will get you to about 19 digits.
I'm crazy about this problem (Uva 455):
A character string is said to have period k if it can be formed by
concatenating one or more repetitions of another string of length k.
For example, the string ”abcabcabcabc” has period 3, since it is
formed by 4 repetitions of the string ”abc”. It also has periods 6
(two repetitions of ”abcabc”) and 12 (one repetition of
”abcabcabcabc”).
Write a program to read a character string and
determine its smallest period.
Input
The first line oif the input file
will contain a single integer N indicating how many test case that
your program will test followed by a blank line. Each test case will
contain a single character string of up to 80 non-blank characters.
Two consecutive input will separated by a blank line.
Output
An
integer denoting the smallest period of the input string for each
input. Two consecutive output are separated by a blank line.
Sample Input
1
HoHoHo
Sample Output
2
I've checked all test cases I could imagine and all of them returned correct result, but I still get Wrong Answer on the online judge. Where did I go wrong?
(English is not my native language; please excuse typing or syntax errors.)
#include <stdio.h>
#include <string.h>
#define maxn 85
int check(char* s, int per){
for(int i = 0; i < strlen(s) - per; i++){
if(s[i + per] != s[i]) return 0;
}
return 1;
}
int main(){
int T;
scanf("%d", &T);
char s[maxn];
while(T--){
scanf("%s", s);
int len = strlen(s);
bool OK = false;
for(int i = 1; i <= len/2 && (len % i == 0); i++){//That's wrong.
if(check(s, i)){
printf("%d\n", i);
OK = true;
break;
}
}
if(!OK) printf("%d\n", len);
if(T) printf("\n");
}
return 0;
}
The problem is in for(int i = 1; i <= len/2 && (len % i == 0); i++). You are stopping as soon as you encounter an i that doesn't divide len, instead of skipping it.
Write the loop as:
for (int i = 1; i <= len/2; i++) {
if (len % i != 0) continue;
...
}
Program to calculate the average of n numbers given by the user.
Okay so I have this program whose purpose is what you have read above. Its output is not quite right. I figured out what the problem is but couldn't find the solution as I am not a leet at programming (newbie actually). Here is the code:
#include <stdio.h>
int main(void) {
char user_data[100];
long int sum = 0;
double average;
unsigned int numbers_count = 0;
for (int i = 0; i <= 99; ++i)
user_data[i] = 0;
unsigned int numbers[100];
for (int i = 0; i <= 99; ++i)
numbers[i] = 0;
printf("Please enter the numbers:");
fgets(user_data, sizeof(user_data), stdin);
int i = 0;
while (user_data[i] != 0) {
sscanf(user_data, "%u", &numbers[i]);
++i;
}
i = 0;
while (numbers[i] != 0) {
sum += numbers[i];
++i;
}
i = 0;
while (numbers[i] != 0) {
++numbers_count;
++i;
}
average = (float)sum / (float)numbers_count;
printf("\n\nAverage of the entered numbers is: %f",average);
return 0;
}
Now here comes the problem.
When I enter an integer say 23, it gets stored into the user_data in two separate bytes. I added a loop to print the values of user_data[i] to figure out what was wrong.
i = 0;
while (i <= 99) {
printf("%c\n",user_data[i]);
++i;
}`
and the result was this
user_data insight
This was the first problem, here comes the second one.
I added another loop same like the above one to print the numbers stored in numbers[100] and figure out what was wrong and here is the output. Here's a sample
numbers stored in numbers[]
Now my main question is
How to extract the full number from user_data?
I believe it could be helpful to layout user_data after the fgets() of "23" (assuming Linux or Mac new line):
+-----+-----+----+----+
| '2' | '3' | \n | \0 | .....
+-----+-----+----+----+
0 1 2 3
Note that user_data[0] does not contain 2 (the number 2)! It contains '2' (the character '2') whose code is (again, assuming Linux) 0x32 (in hex or 50 in decimal).
This is why your attempt to print the values of user_data[] have not been fruitful: you were trying to print the representation of the number, not the number itself.
To convert that string to the integer it represents, you can do something like:
num = atoi(user_data)
The function atoi() does the work for you. A more flexible function is strtol() which does the same but for long int (and also can handle string that represents numbers in a base that is not 10).
I hope this answers to your question: How to extract the full number from user_data?
There are some other points where you should clean up and simplify your code, but you can open another question in case you need help.
Try this:
#include<stdio.h>
#include<stdlib.h>
int main(void)
{
int i;
char user_data[100];
long int sum = 0;
double average;
unsigned int numbers_count = 0;
for( i=0; i<= 99; ++i)
user_data[i] = 0;
unsigned int numbers[100];
for( i=0; i<= 99; ++i)
numbers[i] = 0;
printf("Please enter the numbers:");
fgets(user_data,sizeof(user_data),stdin);
//int p=0;//use with strtol(see further code)
i = 0;
int j;//this will store each number in numbers array.. so this is also the count of numbers stored - 1
for(j=0;;){
for(i=0;i<strlen(user_data);i++)
{
if(user_data[i]=='\n'){
break;
}
if(user_data[i]==' '){
j++;
i++;
//p=i;//to be used with strtol
}
numbers[j]=(numbers[j]*10)+((user_data[i]-48));//alternatively use => numbers[j]=strtol(user_data+p,NULL,10);
}
break;
}
i = 0;
while( i<=j)
{
sum += numbers[i];
++i;
}
average = (float)sum/(j+1);
printf("\n\nAverage of the entered numbers is: %f",average);
return 0;
}
Sample input
10 11 12
Sample output
11.00000000
I have shown two approaches to solve this:
One is straight-forward, subtract 48 from each char and add it to numbers array(ASCII manipulation) .
Other is to use strtol. Now strtol converts the number pointed by the char pointer(char array in this case) until the next char is not a number. So use pointer arithmetic to point to further numbers(like here I have added p(yeah I know p is not a good variable name, so does i and j!)).
There are more ways to solve like using atoi library functions.
regarding the posted code:
what happens if one of the numbers is zero?
What happens if the sum of the numbers exceeds the capacity of 'sum'
#include <stdio.h> // sscanf(), fgets(), printf()
#include <stdlib.h> // strtol()
#include <string.h> // strtok()
// eliminate the 'magic' number by giving it a meaningful name
#define MAX_INPUTS 100
int main(void)
{
// the array can be initialized upon declaration
// which eliminates the 'for()' loop to initialize it
// char user_data[100];
// and
// initialization not actually needed as
// the call to 'fgets()' will overlay the array
// and 'fgets()' always appends a NUL byte '\0'
char user_data[ MAX_INPUTS ];
long int sum = 0;
double average;
// following variable not needed
// unsigned int numbers_count = 0;
// following code block not needed when
// 'user_data[]' initialized at declaration
// for (int i = 0; i <= 99; ++i)
// user_data[i] = 0;
// not needed, see other comments
//unsigned int numbers[100];
// not needed, as 'numbers' is eliminated
// for (int i = 0; i <= 99; ++i)
// numbers[i] = 0;
printf("Please enter the numbers:");
// should be checking the returned value
// to assure it is not NULL
// And
// this call to 'fgets()' is expecting
// all the numbers to be on a single input line
// so that could be a problem
fgets(user_data, sizeof(user_data), stdin);
// the following two code blocks will not extract the numbers
// for a number of reasons including that 'sscanf()'
// does not advance through the 'user_data[]' array
// int i = 0;
// while (user_data[i] != 0) {
// sscanf(user_data, "%u", &numbers[i]);
// ++i;
// }
// i = 0;
// while (numbers[i] != 0) {
// sum += numbers[i];
// ++i;
// }
// suggest the following,
// which also eliminates the need for 'numbers[]'
// note: the literal " \n" has both a space and a newline
// because the user is expected to enter numbers,
// separated by a space and
// 'fgets()' also inputs the newline
int i = 0;
char *token = strtok( user_data, " \n");
while( token )
{
// not everyone likes 'atoi()'
// mostly because there is no indication of any error event
// suggest using: 'strtol()'
//sum += atoi( token );
sum += strtol( token, NULL, 10 ) // could add error checking
i++;
token = strtok( NULL, " \n" );
}
// the value assigned to 'numbers_count'
// is already available in 'i'
// suggest eliminate the following code block
// and
// eliminate the 'numbers_count' variable
// i = 0;
// while (numbers[i] != 0) {
// ++numbers_count;
// ++i;
// }
// 'average' is declared as a 'double',
// so the casting should be to 'double'
// and
// if incorporating the prior comment about 'numbers_count'
// average = (float)sum / (float)numbers_count;
average = (double)sum / (double)i'
// to have the text immediately displayed on the terminal
// place a '\n' at the end of the format string.
// without adding the '\n' the text only displays
// as the program exits
// printf("\n\nAverage of the entered numbers is: %f",average);
printf("\n\nAverage of the entered numbers is: %f\n",average);
return 0;
} // end function: main
I need to code a program that gets input values for a string, then it ignores the characters that are not digits and it uses the digits from the string to create an integer and display it. here are some strings turned into integers as stated in the exercise.
I wanted to go through the string as through a vector, then test if the each position is a digit using isdigit(s[i]), then put these values in another vector which creates a number using the digits. At the end it's supposed to output the number. I can't for the life of it figure what's wrong, please help.
#include <stdio.h>
#include <ctype.h>
#include <string.h>
int main()
{
char *s;
scanf("%s", s);
printf("%s\n", s);
int i, n=0, v[100], nr=0;
for(i=0; i<strlen(s); i++)
{
if (isdigit(s[i]) == 1)
{
v[i] = s[i];
n++;
}
}
for(i=0;i<n;i++)
{
printf("%c\n", v[i]);
}
for(i=0; i<n; i++)
{
nr = nr * 10;
nr = nr + v[i];
}
printf("%d", nr);
return 0;
}
The pointer s is unintialized which is your major problem. But there are other problems too.
isdigit() is documented to return a non-zero return code which is not necessarily 1.
The argument to isdigit() needs to be cast to unsigned char to avoid potential undefined behaviour.
Your array v is also using the same index variable i - which is not right. Use a different variable to index v when you store the digits.
You need to subtract '0' to get the each digits integer equivalent.
scanf()'s format %s can't handle inputs with space (among other problems). So, use fgets().
#include <stdio.h>
#include <ctype.h>
#include <string.h>
int main(void)
{
char s[256];
fgets(s, sizeof s, stdin);
s[strcspn(s, "\n")] = 0; /* remove trailing newline if present */
printf("%s\n", s);
int i, n = 0, v[100], nr = 0;
size_t j = 0;
for(i = 0; i < s[i]; i++)
{
if (isdigit((unsigned char)s[i]))
{
v[j++] = s[i];
n++;
}
}
for(i = 0;i < j; i++)
{
printf("%c\n", v[i]);
}
if (j) { /* No digit was seen */
int multiply = 1;
for(i= j-1 ; i >= 0; i--) {
nr = nr + (v[i] - '0') * multiply;
multiply *= 10;
}
}
printf("%d", nr);
return 0;
}
In addition be aware of integer overflow of nr (and/or multiply) can't hold if your input contains too many digits.
Another potential source of issue is that if you input over 100 digits then it'll overflow the array v, leading to undefined behaviour.
Thanks a lot for your help, i followed someone's advice and replaced
v[i] = s[i] -> v[n] = s[i] and changed char *s with char s[100]
now it works perfectly, i got rid of the variable nr and just output the numbers without separating them through \n . Thanks for the debugger comment too, I didn't know I can use that effectively.
Firstly, you did not allocate any memory, I changed that to a fixed array.
Your use of scanf will stop at the first space (as in the first example input).
Next, you don't use the right array index when writing digits int v[]. However I have removed all that and simply used any digit that occurs.
You did not read the man page for isdigit. It does not return 1 for a digit. It returns a nonzero value so I removed the explicit test and left it as implicit for non-0 result.
I changed the string length and loop types to size_t, moving the multiple strlen calls ouside of the loop.
You have also not seen that digits' character values are not integer values, so I have subtracted '0' to make them so.
Lastly I changed the target type to unsigned since you will ignore any minus sign.
#include <stdio.h>
#include <ctype.h>
#include <string.h>
int main(void)
{
char s[100]; // allocate memory
unsigned nr = 0; // you never check a `-` sign
size_t i, len; // correct types
if(fgets(s, sizeof s, stdin) != NULL) { // scanf stops at `space` in you example
len = strlen(s); // outside of the loop
for(i=0; i<len; i++) {
if(isdigit(s[i])) { // do not test specifically == 1
nr = nr * 10;
nr = nr + s[i] - '0'; // character adjustment
}
}
printf("%u\n", nr); // unsigned
}
return 0;
}
Program session:
a2c3 8*5+=
2385
Just use this
#include <stdio.h>
#include <ctype.h>
int main()
{
int c;
while ((c = getchar()) != EOF) {
switch (c) {
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
case '\n':
putchar(c); break;
}
}
return 0;
} /* main */
This is a sample execution:
$ pru_$$
aspj pjsd psajf pasdjfpaojfdapsjd 2 4 1
241
1089u 0u 309u1309u98u 093u82 40981u2 982u4 09832u4901u 409u 019u019u 0u3 0ue
10890309130998093824098129824098324901409019019030
Very elegant! :)
This program takes an input of number of strings followed by the actual strings. The output should be the number of common characters to all strings.
The constraints are:
No of strings <= 100
Length of string <= 100
For example..
Input:
3
abc
bcd
cde
Output:
1
As only c is common to all strings.
It gives right output when used with small inputs.
But when used with large strings like this :https://hr-testcases.s3.amazonaws.com/2223/input19.txt?AWSAccessKeyId=AKIAINGOTNJCTGAUP7NA&Expires=1408959130&Signature=E%2BMnR6MA0gQNkuWHMvc70eCL5Dw%3D&response-content-type=text%2Fplain
It gives wrong output of 58 instead of 19.
This is my code :
#include<stdio.h>
#include<string.h>
void main(){
int n,i,j,count=0;
char s[100][100];
scanf("%d",&n);
for(i=0;i<n;i++){
scanf("%s",s[i]);
}
int t;
int l = strlen(s[0]);
for(i=0;i<l;i++){
t=0;
for(j=1;j<n;j++){
if(strchr(s[j],s[0][i])!='\0'){
t++;
}
}
if(t==n-1)
count++;
}
printf("%d",count);
}
As you iterate over the first string's characters, you might potentially find the same character more than one time.
This means that common chars found more than one time in the first string will be counted more than one time.
This is what causing your program to calculate 58 instead of 19.
Check below some quick update to your program - it treats the duplicates in the first string.
This program calculates 19 on your 100 strings' test case.
#include<stdio.h>
#include<string.h>
void main(){
int n,i,j/*,count=0*/;
int count[26] = {0}; /* counter per char */
char s[100][101];
scanf("%d",&n);
for(i=0;i<n;i++){
scanf("%s",s[i]);
}
int t;
int l = strlen(s[0]);
for(i=0;i<l;i++){
t=0;
/* convert char to integer - assuming lowercase char only */
int char_index = s[0][i] - 'a';
for(j=1;j<n;j++){
if(strchr(s[j],s[0][i])!='\0' && count[char_index] == 0){
t++;
}
}
if(t==n-1)
count[char_index] = 1;
/* count++; */
}
/* count how many chars are 1*/
int count_n = 0;
int index;
for (index = 0; index < 26; index ++)
{
if (count[index] == 1)
count_n ++;
}
printf("\n\n%d",count_n);
}