can anyone simplify this code for me in c? - c

The sum of all odd digits of n.(eg. n is 32677, the sum would be 3+7+7=17)
Here is the code.
For this question, any of loop or function is acceptable, but not longer than this answer.
#include <stdio.h>
int main()
{
char n[20];
int m=0,i;
printf("Enter integers for the variable n: ");
for (i=0;i<20;i++)
{
scanf("%c",&n[i]);
if(n[i]=='\n')
{
break;
}
}
for (i=0;i<20;i++)// this is the part I would like to simplified
{
if (n[i]%2!=0)
{
if(n[i]==49)
m++;
if(n[i]==51)
m+=3;
if(n[i]==53)
m+=5;
if(n[i]==55)
m+=7;
else if(n[i]==57)
m+=9;
}
}
printf("The sum of odd digits of n is %d.",m);
}

Here are some tools/ideas you can use:
In ctype.h is a function isdigit() which tells you whether or not a character represents a digit.
Assuming the characters for the digits 0..9 are in sequence, the value represented by a character digit c is c-'0'

Here you are
#include <stdio.h>
int main( void )
{
enum { N = 20 };
char value[N];
printf( "Enter an unsigned integer: " );
size_t n = 0;
for ( char digit; n < N && scanf( "%c", &digit ) == 1 && digit != '\n'; ++n )
{
value[n] = digit;
}
unsigned int sum = 0;
for ( size_t i = 0; i < n; i++ )
{
if ( value[i] % 2 != 0 ) sum += value[i] - '0';
}
printf( "The sum of odd digits of the value is %u.\n", sum );
}
The program output might look like
Enter an unsigned integer: 0123456789
The sum of odd digits of the value is 25
Or you can add a check that an entered character is a digit. For example
#include <stdio.h>
#include <ctype.h>
int main( void )
{
enum { N = 20 };
char value[N];
printf( "Enter an unsigned integer: " );
size_t n = 0;
for ( char digit;
n < N && scanf( "%c", &digit ) == 1 && isdigit( ( unsigned char )digit );
++n )
{
value[n] = digit;
}
unsigned int sum = 0;
for ( size_t i = 0; i < n; i++ )
{
if ( value[i] % 2 != 0 ) sum += value[i] - '0';
}
printf( "The sum of odd digits of the value is %u\n", sum );
}
As for your code then in this loop
for (i=0;i<20;i++)
{
scanf("%c",&n[i]);
if(n[i]=='\n')
{
break;
}
}
you have to count how many digits were entered. And the new line character shall not be stored in the array. Otherwise this loop
for (i=0;i<20;i++)
can result in undefined behavior.
And you should not use magic numbers like for example 49.

Related

Find the position of a max on a number

I have C program that needs to find the position of a number. It goes like this:
From standard input we enter unknown number of number that are positive. The numbers have maximum of 5 digits, we read new numbers till the user enters a value that is not a number. I need to find the positions of the max digit of a number from right to left. Use the right-most position if there are more than one instance of the max digit.
The program needs to output the position and the number of times the max digit of a number was found at that position.
For example:
input:
97654 48654 12345 12343 1263 12443 12643 12777 #
output:
0: 2
1: 3
2: 1
3: 1
4: 1
because
Position: 4 3 0 1 1 1 2 0
v v v v v v v v
97654 48654 12345 12343 1263 12443 12643 12777 #
THE PROGRAM WORKS FOR THIS SPECIFIC TEST CASE
More test cases under the code.
Here is my code:
#include <stdio.h>
int main(){
int n;
int max;
int num,digit,pos,br0=0,br1=0,br2=0,br3=0,br4=0;
while (scanf("%d",&n)) {
max =0;
num = n;
pos=0;
while (num>0) {
digit = num%10;
if(digit > max){
max=digit;
pos++;
}
num/=10;
}
printf("%d\n",pos);
switch (pos) {
case 1: br0++; break;
case 2: br1++; break;
case 3: br2++; break;
case 4: br3++; break;
case 5: br4++; break;
}
}
printf("0: %d\n1: %d\n2: %d\n3: %d\n4: %d\n",br0,br1,br2,br3,br4);
return 0;
}
This program work for some test cases, such as
97654 48654 12345 12343 1263 12443 12643 12777 #
123 456 789 987 654 321 #
But not for:
542 8965 7452 1111 12 8 6532 98745 15926 #
75386 86142 94285 15926 35724 #
The problem with your program is that within this loop
while (num>0) {
digit = num%10;
if(digit > max){
max=digit;
pos++;
}
num/=10;
}
the variable pos is incremented only when a digit that is greater than previous digits is found. For example If you have a number like this
51234
then the first largest digit is 4 and the variable pos is set to 1. After that when the next largest digit is found that is the digit 5 the variable pos is incremented and becomes equal to 2 while actually the largest digit 5 is at the position 5.
You need to introduce one more variable as for example
max =0;
num = n;
pos=1;
int i = 1;
do
{
digit = num%10;
if(digit > max){
max=digit;
pos = i;
}
} while ( ( num /=10 ) && ( i++ != 5 ) );
I would write the program the following way
#include <stdio.h>
int main(void)
{
enum { N = 5 };
const unsigned int Base = 10;
size_t total[N] = { 0 };
unsigned int n;
while ( scanf( "%u", &n ) == 1 )
{
unsigned int pos = 0;
unsigned int max_digit = 0;
unsigned int i = 0;
do
{
unsigned int current_digit = n % Base;
if ( max_digit < current_digit )
{
pos = i;
max_digit = current_digit;
}
} while ( ( n /= Base ) && ( ++i != N ) );
++total[pos];
}
for ( unsigned int i = 0; i < N; i++ )
{
printf( "%u: %zu\n", i, total[i] );
}
return 0;
}
For the input
542 8965 7452 1111 12 8 6532 98745 15926 #
the program output is
0: 3
1: 0
2: 3
3: 2
4: 1
It may be fewer steps to do the work using fgets(), and keeping the input in string format. (verifying that it contains numeric characters.)
Plus, an array of values will be easier to keep tract of value to index relationships.
Here is an alternate way of getting the information you describe:
int main(void) {
char inBuf[20] = {0};
int index = 0;
int loops = 0;
int maxPos = 0;
int maxVal = 0;
printf("Enter a number : ");
while (fgets(inBuf, sizeof inBuf, stdin) && loops < 6) {
inBuf[strcspn(inBuf, "\r\n")] = 0;//remove unwanted white space
if(strstr(inBuf, "#")) return 0;//exit if "#"
if(digits_only(inBuf))
{
index = 0;
maxVal = inBuf[index];
while(inBuf[index])
{
if(inBuf[index] >= maxVal)
{
maxVal = inBuf[index];
maxPos = index;
}
index++;
}
printf("%d:%d \n", loops, maxPos);
loops++;
inBuf[0]=0;
}
else
{
printf("\n%s contains non-numeric characters, it cannot be converted.\n\nctrl-c to exit\n...Or enter a number : \n", inBuf);
}
};
return 0;
}
scanf is the wrong tool for this. (scanf is (almost) always the wrong tool). For this particular problem, you really want to treat the input as a string. As long as you don't want to accept inputs that look like "1e3" (which is a perfectly valid representation of an integer), you could just do something like:
#include <stdio.h>
#include <assert.h>
#include <ctype.h>
#include <string.h>
int
main(void){
int max = -1;
int br[5] = {0};
int maxpos = -1;
int len = 0;
int c;
while( (c = getchar()) != EOF ){
if( c && strchr("0123456789", c) ){
if( ++len > 5 ){
fputs("invalid input\n", stderr);
return 1;
}
assert( len > 0 && len < 6 );
if( c > max + '0' ){
maxpos = len;
max = c - '0';
}
} else if( isspace(c) ){
if( max > -1 ){
br[len - maxpos] += 1;
}
maxpos = -1;
len = 0;
max = '0' - 1;
} else {
fputs("invalid input\n", stderr);
return 1;
}
}
for( int i = 0; i < 5; i++ ){
printf("%d: %d\n", i, br[i]);
}
return 0;
}

C program to count the character with the lowest frequency

I have written this code for finding the character with the minimum frequency.
So, giving in input "Hi, how is the weather todayy Dori", the output should be
The letter with the minimum frequency is ā€˜sā€™ and the frequency is 1.
But it shows
How to remove the that coma what is my mistake here
#include<stdio.h>
#include <string.h>
#include <ctype.h>
#define MAX 1000
int main()
{
char str[MAX];
int fre[MAX],i,q,r,co=0,num;
printf("The string : ");
gets(str);
for(q=0;str[q];q++);
r=num=q;
for(i=0;i<num;i++)
{
fre[i]=num;
co=1;
if(str[i])
{
for(q=i+1;q<num;q++)
{
if(tolower(str[i]) == tolower(str[q]))
{
{
co++;
str[q]='\0';
}
}
fre[i]=co;
if(co<=r)
r=co;
}
}
}
printf("The letter with the minimum frequency is");
for(q=0;q<num;q++)
{
if(fre[q]==r)
{
printf(" '%c' ",str[q]);
}
}
printf("and the frequency is %d \n ",r);
return 0;
}
For starters the function gets is unsafe and is not supported by the C Standard. Instead use the standard C function fgets.
As an entered string in general can be very big while letters in the string converted to the lower case can be in the range of ['a', 'z'] then there is no sense to declare such a big array as the array fre declared like.
int fre[MAX];
As you already included the header <string.h> then there is no sense manually to calculate the length of the entered string.
for(q=0;str[q];q++);
To exclude non-letters characters from counting you can use the standard C function isalpha declared in the header <ctype.h>.
Pay attention to that in general the entered string can have no letters.
Here is a demonstrative program that shows how your approach can be implemented.
#include <stdio.h>
#include <ctype.h>
int main(void)
{
enum { MAX = 1000 };
char s[MAX];
size_t frequency[ 'z' - 'a' + 1] = { 0 };
const size_t N = sizeof( frequency ) / sizeof( *frequency );
printf( "The string: " );
if ( fgets( s, MAX, stdin ) )
{
for ( const char *p = s; *p; ++p )
{
if ( isalpha( ( unsigned char )*p ) )
{
++frequency[tolower( ( unsigned char )*p ) - 'a'];
}
}
size_t min = 0;
for ( size_t i = 0; i < N; i++ )
{
if ( frequency[i] != 0 && ( min == 0 || frequency[i] < min ) )
{
min = frequency[i];
}
}
if ( min == 0 )
{
puts( "There ie no letters in the entered string." );
}
else
{
printf( "The letter with the minimum frequency is: " );
for ( size_t i = 0; i < N; i++ )
{
if ( frequency[i] == min ) printf( "%c ", ( int )('a' + i ) );
}
printf( "\nand the frequency is %zu\n ", min );
}
}
return 0;
}
The program output might look like
The string: Hi, how is the weather todayy Dor
The letter with the minimum frequency is: s
and the frequency is 1
There's really no reason to read more than one character at a time. In general, that's a good pattern to try and follow. eg:
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include <ctype.h>
int main(void)
{
int c;
int fre[26] = {0};
printf("The string : ");
while( (c = getchar()) != EOF ) {
putchar(c);
if( isalpha(c) ) {
fre[tolower(c) - 'a'] += 1;
}
}
printf("The letter with the minimum frequency is");
int idx = 0;
int m = INT_MAX;
for( int q = 0; q < 26; q++ ) {
if( fre[q] > 0 && fre[q] < m ) {
idx = q;
m = fre[q];
}
}
printf(" '%c', with frequency %d\n", idx + 'a', fre[idx]);
return 0;
}

How do i add an "(if)" that allows only letters between a-f || A-F?

I wrote a program that does conversion from hex to decimal. all I got left is to check if the char is between a-f or A-F, maybe 0-9 as well. if it is not between them it will print "Illegal input".
My code:
int n, i;
char currentDigit;
unsigned long int sum, currentDigitInt;
printf("Enter the number of digits in the Hexadecimal number:");
scanf_s("%d", &n);
sum = 0;
printf("Enter the Hexadecimal number:\n");
for (i = n - 1; i >= 0; i--) {
scanf_s(" %c", &currentDigit);
if (currentDigit >= 'a') {
currentDigitInt = (currentDigit - 'a') + 10;
}
else if (currentDigit >= 'A') {
currentDigitInt = (currentDigit - 'A') + 10;
}
else
currentDigitInt = currentDigit - '0';
sum += currentDigitInt * pow(16, i);
}
printf("The decimal number is: %u", sum);
The output I need:
Enter the number of digits in the Hexadecimal number: 2
Enter the Hexadecimal number: QQ
Illegal input
There are several problems with the code.
For starters the function scanf_s shall include as a parameter the size of buffer for the format specifier c.
To output an object of the type unsigned long you have to use the format specifier ul.
In these if statements you do not check the upper limit of valid alpha hexadecimal digits.
if (currentDigit >= 'a') {
currentDigitInt = (currentDigit - 'a') + 10;
}
else if (currentDigit >= 'A') {
currentDigitInt = (currentDigit - 'A') + 10;
}
To check whether an entered symbol is a valid hex digit you should write a separate function.
Here is a demonstrative program that shows how it can be done.
//Microsoft (R) C/C++ Optimizing Compiler Version 19.00.23506 for x64
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int hex_digit( char c )
{
const char *alpha = "ABCDEF";
unsigned char c1 = toupper( ( unsigned char )c );
const char *p;
int result = -1;
if ( '0' <= c1 && c1 <= '9' )
{
result = c1 - '0';
}
else if ( c1 != '\0' && ( p = strchr( alpha, c1 ) ) != NULL )
{
result = *p - alpha[0] + 10;
}
return result;
}
int main(void)
{
const unsigned long HEX_BASE = 16;
unsigned int n;
printf( "Enter the number of digits in the Hexadecimal number: " );
scanf_s("%u", &n);
unsigned long sum = 0;
if ( n )
{
printf( "Enter the Hexadecimal number: " );
unsigned int i = 0;
for ( ; i < n; i++ )
{
char c;
scanf_s( " %c", &c, 1 );
int digit = hex_digit( c );
if ( digit < 0 ) break;
else sum = sum * HEX_BASE + digit;
}
if ( i == n )
{
printf("The decimal number is: %ul\n", sum);
}
else
{
puts( "Illegal input" );
}
}
return 0;
}
Its output might look the following way
Enter the number of digits in the Hexadecimal number: 8
Enter the Hexadecimal number: ffFFffFF
The decimal number is: 4294967295l
If you want you can add a check in the program that the specifird number of inputted hexadecimal digits is not greater than 2 * sizeof( unsigned long ).
There are multiple problems in your code:
you can test character ranges with the && operator. For example:
if (currentDigit >= 'a' && currentDigit <= 'f')
you combine these tests in a series of if / else and complain if none of the tests match.
note also that the expression for sum is incorrect too. sum += currentDigitInt * pow(16, i); should be;
sum = sum * 16 + currentDigitInt;
the printf format for unsigned long is %lu, not %u.
you should test the return value of scanf_s to properly detect a potential end of file.
scanf_s expects 2 extra arguments for conversion specifier %c and may not be available on all systems.
note too that you do not need to ask for the number of hex digits, just break from the loop when the character entered is a newline for the second time.
Here is a corrected version:
#include <stdio.h>
int main() {
int currentDigit;
unsigned long int sum;
int invalid = 0;
printf("Enter the Hexadecimal number: ");
sum = 0;
while ((currentDigit = getchar()) ! EOF && currentDigit != '\n') {
int currentDigitInt;
if (currentDigit >= 'a' && currentDigit <= 'f') {
currentDigitInt = (currentDigit - 'a') + 10;
} else
if (currentDigit >= 'A' && currentDigit <= 'F') {
currentDigitInt = (currentDigit - 'A') + 10;
} else
if (currentDigit >= '0' && currentDigit <= '9') {
currentDigitInt = currentDigit - '0';
} else {
invalid = 1;
continue; // keep scanning the input until end of line
}
sum = sum * 16 + currentDigitInt;
}
if (invalid) {
printf("Invalid input\n");
} else {
printf("The decimal number is: %lu\n", sum);
}
return 0;
}
Notes:
The C standard does guarantee that 0 through 9 are consecutive but purists will argue that the letters a through f and A through F might not be consecutive the execution character set. While the are correct, obscuring newbie programmers with these considerations is counter productive and quite excessive as these character ranges are consecutive in both ASCII and EBCDIC (the gaps in EBCDIC are between i and j and between r and s in both cases).
a (A) to f (F) need not be consecutive in C.
If you want your program to run on all implementations of C (klingon space-ship, DS9K, Mars Rover, ..., ...) you could try something like this
if ((currentdigit == 0) || (strchr("0123456789abcdefABCDEF", currentdigit) == NULL)) /* invalid */;
#include <stdio.h>
#include <ctype.h>
#include <string.h>
int isaTof(int c)
{
c = toupper(c);
if(c >= 'A' && c <= 'F') return 1;
return 0;
}
int isin(int c, const char *allowedchars)
{
return strchr(allowedchars, c) != NULL;
}
int isHEXNumber(const char *number)
{
const char allowedchars[] = "abcdefABCDEF0123456789";
while(*number)
{
if(!isin(*number++, allowedchars)) return 0;
}
return 1;
}
or nitpickers version
int isHEXNumber(const char *number)
{
const char allowedchars[] = "abcdefABCDEF0123456789";
if(!number || |*number) return 0;
while(*number)
{
if(!isin(*number++, allowedchars)) return 0;
}
return 1;
}
int main()
{
const char allowedchars[] = "abcdefABCDEF0123456789";
printf("%s\n", isin('d', allowedchars) ? "Yes" : "No");
return 0;
}

Returning a value with pointer ( C program)

I'm a beginner in C and below is a program to find the position of a given digit. My first function works but i can't say the same for the 2nd one(digitPos2) that returns the value from a pointer. I'm not sure what is wrong and why.
#include <stdio.h>
int digitPos1(int num, int digit);
void digitPos2(int num, int digit, int *result);
int main()
{
int number, digit, result=0;
printf("Enter the number: \n");
scanf("%d", &number);
printf("Enter the digit: \n");
scanf("%d", &digit);
printf("digitPos1(): %d\n", digitPos1(number, digit));
digitPos2(number, digit, &result);
printf("digitPos2(): %d\n", result);
main();//return 0;
}
int digitPos1(int num, int digit)
{
int pos=0;
while(num)
{
if(num%10 == digit)
{
return pos = pos + 1;
}
else
{
pos++;
num = num/10;
}
}
}
void digitPos2(int num, int digit, int *result)
{
int pos=0;
while(num)
{
if(num%10 == digit)
{
pos = pos + 1;
*result = pos;
}
else
{
pos++;
num = num/10;
}
}
*result = 0;
}
Output
The both functions are invalid.
For starters it is better to set the parameters num and digit as having the type unsigned int. Otherwise the functions will be more complicated. That is you will need to check whether one of the parameters or both are negative.
Secondly the function digitPos1 has undefined behavior because it returns nothing in case when the digit is not present in the number.
Moreover instead of the while loop you should use a do-while loop because num can be set by the user to 0 and 0 is a valid number.
This statement in the function digitPos2
*result = 0;
does not make sense.
And you have to exut the function if the digit is found
while(num)
{
if(num%10 == digit)
{
pos = pos + 1;
*result = pos;
// exit the function
}
//...
Also it is unclear how the user can determine whether the digit is not present in the number.
You can use an approach that returns for example -1 in case the digit is not present in the number.
Pay attention to that according to the C Standard the function main without parameters shall be declared like
int main( void )
Here is a demonstrative program
#include <stdio.h>
int digitPos1( unsigned int num, unsigned int digit);
void digitPos2( unsigned int num, unsigned int digit, int *result);
int main( void )
{
unsigned int number, digit;
int result;
printf( "Enter the number: " );
scanf( "%d", &number );
printf( "Enter the digit: " );
scanf( "%d", &digit );
printf("digitPos1(): %d\n", digitPos1( number, digit ) );
digitPos2(number, digit, &result);
printf( "digitPos2(): %d\n", result );
return 0;
}
int digitPos1( unsigned int num, unsigned int digit )
{
const unsigned int Base = 10;
int pos = -1;
int n = 0;
do
{
if ( num % Base == digit )
{
pos = n;
}
else
{
++n;
}
} while ( ( num /= Base ) && ( pos == -1 ) );
return pos;
}
void digitPos2( unsigned int num, unsigned int digit, int *result )
{
const unsigned int Base = 10;
int n = 0;
*result = -1;
do
{
if ( num % Base == digit )
{
*result = n;
}
else
{
++n;
}
} while ( ( num /= Base ) && ( *result == -1 ) );
}
The program output might look for example like
Enter the number: 123456
Enter the digit: 2
digitPos1(): 4
digitPos2(): 4
The position startrs from 0.
First of all,
In case the digit is not present at all you should return a index that is not possible in a real number, e.g. you can return a negative number in that case, may be -1. (In c/c++ indexing starts from 0 so 0 is always a valid index)
so for digitPos1(int num, int digit) the ending should look like
while(num){
//your code
//return pos + 1 in case digit found
//more code
}
return -1;
similarly for digitPos2(int num, int digit, int *result) you should initialize *result with -1
int pos=0;
*result = -1;
and the biggest mistake is to set *result=0 at the end. To understand this you should understand that while dealing with pointers, every change you make to the pointers value is reflected in the callee function also, so if you set *result=0 then all the previous computation is just wasted and the position is returned blindly as 0. So you MUST remove this line for your computations to reflect back in the main function.
Secondly,
I don't think you have considered the cases of duplicates, e.g.
num : 1232323
digit : 3
Here, ideally you should break or return after you have found the match in case of digitPos2
*result = pos;
return; //return type is void
This changes should give expected behaviour according to me.

Finding digit position

I am to write a recursive function int digitpos(int num, int digit) which takes in a positive integer num and digit which returns the position of first appearance of digit in num from the right starting from 1. If not found, 0 will be returned.
For example, digitPos(12234, 2) would yield 3 and digitpos(123, 8) would yield 0
int digitPos(int n, int digit)
{
if (n == 0) return 0;
if (n % 10 == digit) return 1;
return 1 + digitPos(n / 10, digit);
}
The above works if the digit exists in the number. If it doesn't, it will print out how many digits are there(as it goes through all digits).
It don't seems to me to be possible to do so by recursion given only these 2 parameters. Sure, by iteration I can do it. But I wanna know is it possible through recursion?
The function can be written for example the following way
int digitPos( unsigned int n, unsigned int digit )
{
if ( n % 10 == digit ) return 1;
if ( ( n /= 10 ) == 0 ) return 0;
int i = digitPos( n, digit );
return i == 0 ? 0 : i + 1;
}
Here is a demonstrative program
#include <stdio.h>
int digitPos( unsigned int n, unsigned int digit )
{
if ( n % 10 == digit ) return 1;
if ( ( n /= 10 ) == 0 ) return 0;
int i = digitPos( n, digit );
return i == 0 ? 0 : i + 1;
}
int main( void )
{
printf( "%d\n", digitPos( 12345, 2 ) );
return 0;
}
The output is
4
Take into account that 0 is a valid digit.:)
Modify your code as below:
#include <stdio.h>
#include <string.h>
int count=1;
int digitPos(int n, int digit)
{
if(n==0) { count=0; return 0;}
if (n % 10 == digit) return 1;
count++;
digitPos(n/10, digit );
return count;
}
int main(void){
printf("%d",digitPos(12234,8));
return 0;
}
You don't have to divide digit by 10 as it will always give 0, instead divide n by 10.

Resources