Convert roman numerals to decimal numbers - c

I write the following code to convert roman numbers to decimal numbers using C language but it is not giving the correct answers. I have done dry run also. please help.
#include <stdio.h>
int main()
{
char ch;
int num, newnum=0, result=0;
printf("Enter number:");
scanf("%s", &ch);
while (ch != 'n') {
switch (ch) {
case 'i': num = 1; break;
case 'v': num = 5; break;
case 'x': num = 10; break;
case 'l': num = 50; break;
case 'c': num = 100; break;
case 'd': num = 500; break;
case 'm': num = 1000; break;
}
if (newnum > num) {
result = result - num;
newnum = num;
} else {
result = result + num;
newnum = num;
}
printf("Enter number:");
scanf("%s", &ch);
}
printf("%d", result);
}

main()
should be written
int main( void )
This is not just a stylistic nit - as of C99, implicit typing is no longer allowed.
scanf("%s", &ch);
is not what you want here - the s conversion specifier expects ch to point to the first element of an array of char, not a single char object. It tells scanf to read a sequence of non-whitespace characters and store them to a buffer, and it will write the zero terminator to the end of that buffer (i.e., to store a one-character string, you need a 2-element array of char). As written, scanf will write to both ch and the byte immediately following it in memory, which may or may not have an effect elsewhere.
To read a single character from standard input, either use
scanf( " %c", &ch ); // note leading blank in format string; this tells scanf
// to skip over any leading whitespace characters
or
int ch;
...
ch = getchar(); // getchar returns int, not char
You might want to walk through your conversion algorithm on paper a few times. What happens when you enter i followed by v?

Related

Scanf preventing a C pragram from looping

I'm trying to write a program that takes Roman numerals as input and then converts them to decimal values. The user has to first declare how many Roman numerals they are going to input (either one or two).
I am using a for loop that repeats as many times as the number of Roman numerals. It either shouldn't loop if the there is only one numeral or if there are two it should loop twice because we need to take one letter as input at a time.
The issue I was having is that the scanf statement that is inside the for loop, keeps preventing the programme from looping. As soon as I removed the scanf and statically assigned the value then it worked perfectly fine. Then while trying to fix the issue I tried to print out the value scanf is returning by assigning it to a new variable, like char snf = scanf("%s", &numeral); and for some reason it started working exactly I wanted it to work. I have absolutely no idea why it is working now and why it was preventing the loop from looping before. Can anyone explain to me what's going on?
// A program to convert Roman Numerals to Decimals system.
#include <stdio.h>
int convert_numerals(char numeral){
switch(numeral){
case 'I':
return 1;
case 'V':
return 5;
case 'X':
return 10;
case 'L':
return 50;
case 'C':
return 100;
case 'D':
return 500;
case 'M':
return 1000;
default :
printf("\nError! You did not enter a valid numeral\n");
return 0;}}
int main(){
int Decimal_Val = 0; //Initializing the variable with 0 to avoid issues at check.
int Numeral_Count;
printf("How many characters does your Roman numerals have? 1 or 2\n");
scanf("%d",&Numeral_Count);
for (int i = 1; i < 1+Numeral_Count; ++i)
{
char numeral = 'O';
int converted_val;
printf("\n\nEnter numeral %d : ",i);
scanf("%s", &numeral); // The problematic line.
converted_val = convert_numerals(numeral);
if (Decimal_Val != 0)
{
if (Decimal_Val < converted_val)
{
Decimal_Val = converted_val - Decimal_Val;
}else{
Decimal_Val += converted_val;
}
}else{
Decimal_Val = converted_val;
}
}
printf("\nThe Roman numerals you entered are equal to %d in Decimals\n", Decimal_Val);
return 0;
}
Scanf can be a problematic function, especially with characters. Instead, try using fgets to read a line, then use the first character. If we break this out into a separate function. (Breaking problems down is crucial to solving complex problems in any programming language.)
char get_roman_numeral(const char *prompt, const char * error_msg) {
while (1) {
printf("%s: ", prompt);
char input[20] = {};
fgets(input, 19, stdin);
input[strcspn(input, "\n")] = '\0';
if (strlen(input) > 0) {
switch (input[0]) {
case 'i': case 'I':
case 'v': case 'V':
case 'x': case 'X':
case 'l': case 'L':
case 'c': case 'C':
case 'd': case 'D':
case 'm': case 'M':
return input[0];
default:
printf("%s\n", error_msg);
}
}
else {
printf("%s\n", error_msg);
}
}
}
Picking this apart, we loop indefinitely. Each time we print the prompt we provide, then read a line from stdin into the char buffer input which can hold 20 characters (one of them has to be the null terminating character).
input[strcspn(input, "\n")] = '\0';
This is going to find the first newline character in the input string and set it to '\0'. This effectively removes the newline character than fgets will include in the input string.
If the input string is then longer than 0 characters, we'll evaluate the first character. If it's a roman numeral, we return it. The function is done!
If it's either not a roman numeral, or the string is zero characters in length, we'll print the error message, and the loop starts over.
Hopefully looking at getting your input this way, without the problematic scanf will help you solve the bigger problem.
just decide to stop working for no apparent reason.
Below fails as "%s" attmeps to form a string and numeral is only big enoguh for the stirng "".
//char numeral = 'O';
//scanf("%s", &numeral); // The problematic line.
char numeral[100];
if (scanf("%99s", &numeral) == 1) {
// Success, continue and use `numeral`
converted_val = convert_numerals(numeral); will need to change too as that only handles 1 char.

Validate user's input to check if input is in the right format in C

The program will prompt the user to enter a simple expression. After splitting the string and assigning the variables, i want to check to see if what the user entered is a an integer so it can be calculated in the switch statement. What would be the best way to validate the data inside num1 and num2 to make sure they are integers and not letters or any other character.
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
/*This function will display the user's desired expression to be calculated */
char* expressionDisplay(char* input)
{
char *str = input;
printf("The expression entered is: %s\n", str);
}
int main()
{
char str[50];
char operator[6] = "+-*/%";
int num1,num2;
char calculation;
char *oldstr = malloc(sizeof(str));
printf("This program will solve a simple expression in the format 'value' 'operator' 'value'\n ");
printf("Example 2+6 or 99 * 333\n");
printf("Enter the simple expression to be calculated: \n");
scanf("%[^\n]%*c", str); //this will scan the whole string, including white spaces
strcpy(oldstr, str);
for(int i = 0; i < strlen(operator); i++)
{
char *position_ptr = strchr(str, operator[i]);
int position = (position_ptr == NULL ? -1 : position_ptr - str);
if(str[position] == operator[i])
{
calculation = operator[i];
char *num1_ptr = strtok(str, operator);
int num1 = atoi(num1_ptr);
char * num2_ptr = strtok(NULL, operator);
int num2 = atoi(num2_ptr);
break;
}else
calculation = position;
}
switch(calculation)
{
case '+':
expressionDisplay(oldstr);
printf("Sum\n");
break;
case '-':
expressionDisplay(oldstr);
printf("Subtract\n");
break;
case '*':
expressionDisplay(oldstr);
printf("Multiply\n");
break;
case '/':
expressionDisplay(oldstr);
printf("Division\n");
break;
case '%':
expressionDisplay(oldstr);
printf("Modulus\n");
break;
default:
printf("Sorry unable to calculate the expression entered. Try again.\n");
printf("Enter a simple expression - number operator number - ");
break;
}
}
In this case you can use the strtol function of standard c library.
You can see more detail about it at this link : strtol - c++reference.

How to convert a character into a number

I have a homework problem. It requires me to convert a word into uppercase and several characters have to be converted to decimal for example :
"Hello my NamE is FeLix" --> "H3LL0 MY N4M3 15 F3L1X". So, these characters had to be converted :
I = 1
S = 5
E = 3
O = 0
A = 4
etc.
How to convert it? I already tried to convert it to capslock but i cannot convert it into decimal.
I already tried to convert the words into uppercase, but have no idea how to convert the character into numbers.
int main()
{
char sentence[200];
int sentencelength = strlen(sentence);
// Ambil data user
scanf("%s",&sentence); getchar();
// Cek satu persatu pake for
for (int i= 1; i <= sentencelength; i++) {
if(sentence[i] >= 'a' && sentence[i] <= 'z') {
char uppercase = sentence[i] + 'A' - 'a';
printf("%c",uppercase);
}
}
getchar();
return 0;
}
There is no error, but I just have no idea how to convert it.
You can use switch as below.
switch(uppercase ) {
case 'I':
uppercase = '1';
break;
case 'S':
uppercase = '5';
break;
case 'E':
uppercase = '3';
break;
…
}
C arrays start at index 0, not 1, so change the for loop bounds to:
for (int i = 0; i < sentencelength; i++) {
You can use toupper (declared by #include <ctype.h>) to convert a character from lowercase to uppercase, leaving non-alphabetic characters alone. It is only defined for values representable by an unsigned char or for the value EOF.
char l33t = sentence[i];
if (l33t == (unsigned char)l33t)
l33t = toupper(l33t);
You can use a switch statement to replace certain uppercase letters with digits:
switch (l33t) {
case 'I':
l33t = '1';
break;
case 'S':
l33t = '5';
break;
case 'E':
l33t = '3';
break;
case 'O':
l33t = '0';
break;
case 'A':
l33t = '4';
break;
}
Rather than using scanf to read a whole word of input into a buffer, an alternative is to read the input a character at a time. Here is an example program that behaves as a filter:
#include <stdio.h>
#include <ctype.h>
static int convert(int ch)
{
if (ch == (unsigned char)ch)
ch = toupper(ch);
switch (ch) {
case 'I': ch = '1'; break;
case 'S': ch = '5'; break;
case 'E': ch = '3'; break;
case 'O': ch = '0'; break;
case 'A': ch = '4'; break;
}
return ch;
}
int main(void)
{
int ch;
while ((ch = getchar()) != EOF) {
ch = convert(ch);
putchar(ch);
}
return 0;
}
The above will convert the whole input until it sees end-of-file. To terminate after a single line, just add a check for a newline character to break out of the while loop.
create an array of characters: [4BCD3F....Z]
and an array of sources: [abcd...z]
run on your string, replace each character found in index I with the same character in the first array, if it's not found return the character as is.
crude, simple, works
Also, if someone complain on the calculation complexity, since you have fixed number of letters in the arrays A to Z , the complexity is O(N*M) when M is const, hence O(N) anyway

How to get a character ASCII value in a integer variable?

I'm new in C and I couldnt find the answer to my question in the forum.
The point is, I need to get a value of deck cards from the user. So it can spread from 2 to 10 and also be 'J', 'Q', 'K' or 'A'. That means it can be a integer or a character.
I'm trying to put it in an integer variable called "_val1". This work for any number from 0 to 10. I expected that if I typed a letter, _val1 would get the ASCII value of that character (wich I could use later for my pourposes). But instead _val1 geta value '0' and the letter is automatically passed to my next variable call (wich is _naipe1).
How can I solve that?
That means, how cam I use scanf to get either a integer value or the ASCII value of a character?
short int _val1, _val2;
char _naipe1, _naipe2;
printf("Qual a 1ª carta?\n Valor:");
scanf(" %hd", &_val1);
printf("Valor 1 = %hd \n", _val1 );
printf(" Naipe:");
scanf(" %c", &_naipe1);
well, if I were you I'd try to simplify the problem:
get the ASCII value of the card representation from '2' to '9' and 'J','Q','K','A' ; there you can simply use a scanf("%c") or even better a getchar() operation.
then either you keep using the ASCII representation of your cards throughout your algorithm, or you can translate it using a mapping function such as:
int map(char card) {
switch (card) {
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
return card-'0';
case 'A':
return 1;
case 'J':
return 10;
case 'Q':
return 11;
case 'K':
return 12;
}
}
First, there are 52 cards to a typical poker deck, These are split into 4 suits: hearts, diamonds, spades and clubs. This kind of suggests that user input will be something like: 10s, Ad, 3c, etc (meaning 10 of spades, Ace of diamonds and 3 of clubs) So, not only must you determine the value of the individual card, you also must determine the suit.
This will not solve all of those requirements, but it will at least answer your most direct question, how to read an int or a char using scanf().
This will demonstrate that:
#include <stdio.h>
int main(int argc, char** argv)
{
int aNumber;
char aChar;
printf("\nEnter a number:");
scanf("%d", &aNumber);
printf("\nEnter a character:");
scanf("%c", &aChar);
printf("\nThe number entered is %d\n", aNumber);
printf("\nThe character entered is %c\n", aChar);
return 0;
}
You can also simply have all the values in a string such as
char cards[]={"Ad Js 10c 2c Qh"};
Then parse it using strtok(), then test each token for its ascii content, using functions like isdigit() or isalpha()
Note: you will have to map each card to a value to keep them straight, something like this abbreviated enum may work:
enum {
AD = 1, //start enum values at 1 for the diamonds suit
2D,
3D,
...//fill in rest of cards here
JC,
QC,
KC, // last card == 52, with the clubs suit
};
The reason your output from _val1 is 0 when entering a letter lies in the fact that you've declared _val1 as an short int. You should be using a char. Then you can assign and compare their ascii values.
char card;
int value;
scanf("%c", card);
if(card < 58 && card > 49)
value = card - 48;
else {
switch(card) {
case 'a': value = 1;
case '0': value = 10;
case 'j': value = 11;
case 'q': value = 12;
case 'k': value = 13;
default: printf("Must enter 0-9 (0 for 10 card), or a, j, q, k\n");
}
}
To read in "A", "2", "3", ... "10", "J",... "K", use fgetc() and strchr().
#include <ctype.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
short GetCardRank(void) {
static const char rank[] = "A234567891JQK";
short val = -1;
int ch = fgetc(stdin);
while (isspace(ch)) ch = fgetc(stdin); // Skip leading white-space
char *p = strchr(rank, toupper(ch)); // Use toupper() to make case insensitive
if (ch != EOF && p != NULL && *p != '\0') {
short val = (short) (p - rank + 1);
if (val != 10) return val;
ch = fgetc(stdin);
if (ch == '0') return val;
val = 1; // Allow a lone '1' to act like an 'A'
}
ungetc(ch, stdin); // Put back unused char for next IO function
return val;
}
I'm trying to put it in an integer variable called "_val1". This work for any number from 0 to 10. I expected that if I typed a letter, _val1 would get the ASCII value of that character (wich I could use later for my pourposes). But instead _val1 geta value '0' and the letter is automatically passed to my next variable call (wich is _naipe1)
The problem is that the %d conversion specifier only recognizes strings of decimal digits (with an optional leading + or -) and will stop reading at the first non-digit character; if you type in something other than a digit, then the input operation will fail and that character will be left in the input stream.
Your best bet is to read your input as text, then convert it to a numerical value manually, something like the following:
#include <ctype.h>
#include <stdlib.h>
/**
* Reads a card's face value (2-10,J,Q,K,A) from standard input
* Returns 0 on error
*/
short get_card_value( void )
{
char buf[4]; // large enough to hold a 2-digit string plus newline plus 0 terminator
short val = 0;
if ( fgets( buf, sizeof buf, stdin ) != NULL )
{
char *chk;
short tmp = (short) strtol( buf, &chk, 0 );
if ( isspace( *chk ) || *chk == 0 )
{
if ( tmp >= 2 && tmp <= 10 )
val = tmp;
}
else
{
switch( tolower( *chk ) )
{
case 'j': val = 11; break;
case 'q': val = 12; break;
case 'k': val = 13; break;
case 'a': val = 11; break;
default: break;
}
}
}
// else read error
return val;
}
You'd call this as
val1 = get_card_value();
if ( val1 == 0 )
// error on input
This code doesn't do any length checking on input, so if you enter a card value of 1234567890, that won't be handled gracefully.
Don't use leading underscores in your variable names; names with leading underscores are reserved for the implementation.

Invalid conversion from "char" to "char *"

This is the program to convert a Roman number (for example VI) to a decimal.
The algorithm is writing a function that recognize each element of the input string and return the corresponding value in decimal.
We got char Roman_num[20]
For each element, sum+=value(Roman_num[i]).The function prototype is int value (char digit).It results in the 'Invalid conversion from char to char *' error.
However, when passing each element's address &a[i] to the function and changing the prototype to int value (char *digit), it doesn't repeat this error but leads to another error in this switch-case (inside the function) : switch (*digit) gives an error of 'digit' cannot appear in a constant-expression
My question is I was not clear that: in this example, do we have to pass only the address to the funcion? If we want to pass the value, a single character value, then how? Last but not least, *digit is actually a single character, then why it cannot appear in a constant-expression in case()?
I will be grateful for your help. On the other hand, can you please recommend me some books for deep understanding in C? I'm now using C : How To Program book, and I hardly know about how the variables, functions working on the inside for a deeper understanding.
This is the code:
int value (char *digit);
int main (void)
{
char a[100];
int length,i,sum=0;
printf("Enter your Roman number: ");
fflush(stdin);
gets(a);
printf("\nThe Roman number that you have entered is %s",a);
length=strlen(a);
for (i=0;i<length;i++)
{
sum+=value(&a[i]);
}
printf("\nthen it is: %d",sum);
getch();
return 0;
}
int value (char *digit)
{
int num;
case ( *digit ){
case 'M':
num=1000;
break;
case 'D':
num=500;
break;
case 'C':
num=100;
break;
case 'L':
num=50;
break;
case 'X':
num=10;
break;
case 'V':
num=5;
break;
case 'I':
num=1;
break;
}
return num;
}
Since you will not post code, here some code for getting roman numerals that always increase. The subtraction part is left to you to figure out. I only post this as it sounds like you are self teaching yourself which is comendable:
int romanToValue(const char c)
{
switch(c) // Only works with upper-case as lower case means different things.
{
case 'I' : return 1;
case 'V' : return 5;
case 'X' : return 10;
case 'L' : return 50;
case 'C' : return 100;
case 'D' : return 500;
case 'M' : return 1000;
default: printf("Bad value in string %c\n", c); break;
}
return 0;
}
int romanToInt(const char *str)
{
int value = 0;
int i;
for(i=0; str[i]; i++) // Dangerous way to do strings, but works for a C example.
{
value += romanToValue(str[i]);
}
return value;
}
int main(void)
{
const char cstr[] = "VIII";
printf("value:%d\n", romanToInt(cstr));
return 0;
}
Notice the switch statement is working off of char values.

Resources