Invalid conversion from "char" to "char *" - c

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.

Related

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.

The switch statement is not initializing the value even if the case is True?

I want this switch statement to initialize the right value to the variable option but it is not initializing therefore not allowing the if statement to work.
#define arti 2.05
int main(void)
{
char ch;
float option = 0;
while(ch = getchar())
{
ch = toupper(ch);
switch(ch)
{
case 'A':
option = arti; //value of arti is 2.05
break;
case 'B':
option = beets;
break;
default:
printf("Enter a valid value.\n");
continue;
break;
}
if(option == arti)
{
printf("arti printed successfully!\n");
}
}
return 0;
}
The output i am getting is this:
a //input
Enter a valid value. //output
I don't know where is the problem i have made this code as short as possible to explain you the problem. Please help me with this.
You are comparing a float value (option) to a double constant (arti), which is causing a problem. To define arti as a (single-precision) float, add the f suffix:
#define arti 2.05f

Convert roman numerals to decimal numbers

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?

Why does the string return "#" or mess up my "Z"?

char convertalphas(char s) {
switch (s){
case 'A':
return '0';
break;
case 'B':
return '1';
break;
case 'C':
return '2';
break;
case 'D':
return '3';
break;
case 'E':
return '4';
break;
case 'F':
return '5';
break;
case 'G':
return '6';
break;
case 'H':
return '7';
break;
case 'I':
return '8';
break;
case 'J':
return '9';
break;
case 'K':
return '10';
break;
case 'L':
return '11';
break;
case 'M':
return '12';
break;
case 'N':
return '13';
break;
case 'O':
return '14';
break;
case 'P':
return '15';
break;
case 'Q':
return '16';
break;
case 'R':
return '17';
break;
case 'S':
return '18';
break;
case 'T':
return '19';
break;
case 'U':
return '20';
break;
case 'V':
return '21';
break;
case 'W':
return '22';
break;
case 'X':
return '23';
break;
case 'Y':
return '24';
break;
case 'Z':
return '25';
break;
}
}
int main()
{
char astring[10];
int i = 0;
int flag = 0;
int startedalpha = 0;
//check if there is a digit input or not
int nodigit = 0;
char cell[10];
int col;
scanf( "%s", &astring );
for ( i = 0; i < 10; ++i )
{
if(astring[i] != '\0') {
//check whether letter is capital or small
if (astring[i] >= 65 && astring[i] <= 90)
{
startedalpha = 1;
//printf( "%c\n", astring[i] );
cell[i] = convertalphas(astring[i]);
printf("cell is %s\n", cell);
}
What im trying to do is to concatenate all of my conversions for a later use. when I put "AB" it returns "01#" and when I put "Z" it returns something else than "25". I don't know what is wrong but it is driving me crazy! I want to be able to input "ABZ" and it saves all of my values into the variable cell. For example, "ABZ" "0125"
Thanks!
I'm confused with this forum. Obviously, I posted the question because there is something I don't know and I'm not a guru as many of you! So, why would I get -2? I already posted what I tried. I thought it is about helping not being condescending!
Thanks for those who replied anyway!
Edit --
I converted my switch statement to int but now how can I concatenate the integers in variable cell?
One of things I noticed is that you have a char returning function, and is returning something else than a char, like '10'. It will return an unexpected value. You can, for example, set the return of this function to integer.
So it will look like this:
int convertalphas(char s) {
switch (s){
case 'A':
return 0;
case 'B':
return 1;
case 'C':
return 2;
case 'D':
return 3;
case 'E':
return 4;
return -1;
}
And then, change inside the loop in main function:
sprintf(auxvar, "%d", convertalphas(astring[i]);
for( jj = 0; jj < strlen(auxvar); jj++)
cell[i++] = auxvar[jj];
I hope it can help you somehow!
Good Luck.
According to the C Standard (6.4.4.4 Character constants)
...The value of an integer character constant containing more than one
character (e.g., 'ab'), or containing a character or escape sequence
that does not map to a single-byte execution character, is
implementation-defined.All
All return values of the function starting from '10' to '25' inclusively are imolementation defined and you can get the result that you did not expect to get.
You need to write a function that would be declared like
char * convertalphas( const char *s );
Or
char * convertalphas( char *dest, const char *source );
By the way it will be difficult to make the reverse conversion. For example what does "25" mean? Whether it is "CF" or "Z"?:)
Apart from the values returned by chars 'K' thru 'Z' (as mentioned by others) there are some other errors with the use of cell
Each character returned from your function is written into cell[] and then you print cell as a string. But there is no string terminator. You either need to fill cell[] with zeros first, or write a 0 into the next character
cell[i] = convertalphas(astring[i]);
cell[i+1] = 0;
But the problem with this is that cell[i] is skipped when the char is not a capital letter. You need to maintain a separate index into cell[]
cell[j++] = convertalphas(astring[i]);
cell[j] = 0;
One more problem is cell[] is not long enough for the final string terminator. You need to declare it as
char cell[11];
To summarize, your problem is:
A char function cannot return anything other than a single character. If you try to return something like '12', it just simply doesn't work. You need to rethink your algorithm. Implementing this using ints should be very straightforward.
Is this a homework assignment requiring the use of the switch statement? If not, and if you follow the advice to return int instead of char, a simple s-65 would do the trick, you don't need a 78-line switch.
Since cell is a char array, each element of cell can also only store a single character.
It is not very clear what you are trying to achieve, so I will try to comprehend it in two ways:
3.1. You want to store each character's value separately in cell.
Example: for input "ABZ", you want cell to be {0, 1, 25}.
This is easy. Change cell to an int array, and output them using %d format specifier in your printf.
3.2 You treat cell as a string rather than an array of characters, and you concatenate the string for every character's value.
Example: for input "ABZ", you want cell to be "0125", or in other words, {'0', '1', '2', '5'}. This means that you won't be able to differentiate between "ABZ" and, say, "AMF", as others have pointed out.
If this is what you want to achieve, firstly 10 elements is not enough for cell - each character must be stored separately, and you cannot store "25" as two characters in a single element of cell.
You can assign it with, say, 21 elements (2 max for each alphabet, one extra for the terminating '\0' byte). After each alphabet is converted to its value in int, implement a counter and some conditionals to fill cell one character at a time. Example, if an alphabet's value is stored in val:
char cell[21];
int i=0;
if(val < 10) {
cell[i] = val + '0';
i++;
} else {
cell[i] = val / 10 + '0';
i++;
cell[i] = val % 10 + '0';
i++;
}
I'll leave the implementation of this into a loop as an exercise for you...

Passing arrays as arguments to a function without passing their length to that function

I read that while passing an array as argument we must also have to pass its length as argument( strict C89 ).
In this given code snippet
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#define NUM_RANKS 13
#define NUM_SUITS 4
#define NUM_CARDS 5
bool straight, flush, four, three;
int pairs;
void read_cards(int a[], int b[]); // I did't specify the length in this declaration
void analyze_hand(int a[], int b[]); // I did't specify the length in this declaration
void print_result(void);
int main()
{
int num_in_rank[NUM_RANKS];
int num_in_suit[NUM_SUITS];
for(;;)
{
read_cards(num_in_rank, num_in_suit);
analyze_hand(num_in_rank, num_in_suit);
print_result();
}
}
void read_cards(int num_in_rank[], int num_in_suit[])
{
bool card_exists[NUM_RANKS][NUM_SUITS];
char ch, rank_ch, suit_ch;
int rank, suit;
bool bad_card;
int cards_read = 0;
for(rank = 0; rank < NUM_RANKS; rank++)
{
num_in_rank[rank] = 0;
for(suit = 0; suit < NUM_SUITS; suit++)
card_exists[rank][suit] = false;
}
for(suit = 0; suit < NUM_SUITS; suit++)
num_in_suit[suit] = 0;
while(cards_read < NUM_CARDS)
{
bad_card = false;
printf("Enter a card: ");
rank_ch = getchar();
switch(rank_ch)
{
case '0': exit(EXIT_SUCCESS);
case '2': rank = 0; break;
case '3': rank = 1; break;
case '4': rank = 2; break;
case '5': rank = 3; break;
case '6': rank = 4; break;
case '7': rank = 5; break;
case '8': rank = 6; break;
case '9': rank = 7; break;
case 't': case 'T': rank = 8; break;
case 'j': case 'J': rank = 9; break;
case 'q': case 'Q': rank = 10; break;
case 'k': case 'K': rank = 11; break;
case 'a': case 'A': rank = 12; break;
default: bad_card = true;
}
suit_ch = getchar();
switch(suit_ch)
{
case 'c': case 'C': suit = 0; break;
case 'd': case 'D': suit = 1; break;
case 'h': case 'H': suit = 2; break;
case 's': case 'S': suit = 3; break;
default: bad_card = true;
}
while((ch = getchar()) != '\n')
if(ch != ' ')
bad_card = true;
if(bad_card)
printf("Bad card; ignored.\n");
else if(card_exists[rank][suit])
printf("Duplicate card; ignored.\n");
else
{
num_in_rank[rank]++;
num_in_suit[suit]++;
card_exists[rank][suit] = true;
cards_read++;
}
}
}
void analyze_hand(int num_in_rank[], int num_in_suit[])
{
int num_consec = 0;
int rank, suit;
straight = false;
flush = false;
four = false;
three = false;
pairs = 0;
for(suit = 0; suit < NUM_SUITS; suit++)
if(num_in_suit[suit] == NUM_CARDS)
flush = true;
rank = 0;
while(num_in_rank[rank] == 0)
rank++;
for(; rank < NUM_RANKS && num_in_rank[rank] > 0; rank++ )
num_consec++;
if(num_consec == NUM_CARDS)
{
straight = true;
return;
}
for(rank = 0; rank < NUM_RANKS; rank++)
{
if(num_in_rank[rank] == 4)
four = true;
if(num_in_rank[rank] == 3)
three = true;
if(num_in_rank[rank] == 2)
pairs++;
}
}
I passed the two arrays num_in_rank[NUM_RANKS] and num_in_suit[NUM_SUITS] together to the functions void read_cards(int a[], int b[]) and void analyze_hand(int a[], int b[]) without supplying the arrays length and I don't know how this worked(without any warning/error)?
Any idea is it right or wrong?
I read that while passing an array as argument we must also have to pass its length as argument
This applies only in situations when the function does not know the size of the array upfront. When the function knows that the array must have a certain number of elements, you do not need to pass the size to the function.
This is exactly what is happening in your code: both functions that receive arrays know that num_in_rank contains exactly NUM_RANKS elements, and num_in_suit contains exactly NUM_SUITS elements. That is why you do not need to pass the size, and nothing is going to happen: the function already knows the size through #defined constants.
On the other hand, if you needed to pass an array of size unknown to your function, then you would need to do one of the following:
Pass the number of elements in your array, or
Pass a pointer to the last element (or one past the last element) of your array, or
Agree on a "sentinel" value such as zero or negative one that would indicate the end of the valid range of data in your array.
When you pass an array in c, all the function sees is a pointer to the start of the array, so the length is not visible inside the function.
In order to allow the function to use the length, you have to either create some kind of struct that also contains the length, have some kind of special character at the end of the valid input to the array (like '\0' for strings), or expicitly pass in the size as a function argument.
You won't get compile errors if you don't pass in the length, but most operations that you do on the array will require you to know how long it is, so you're likely going to get a segfault when you try to do operations on the array without knowing its length.
Edit:
After posting the full code, it's because you are using the macros for bounds checking, which is sort of like passing in the size, but less flexible.
Remember that arrays in C are essentially pointers to the beginning of the memory block that your program setting aside. So when you say
int num_in_rank[NUM_RANKS];
int num_in_suit[NUM_SUITS];
you can use them as pointers. It is usually in practice to also pass the size as an int, such as
void read_cards(int a[], int b[], int a_size, int b_size);
void analyze_hand(int a[], int b[], int a_size, int b_size);
if you need to utilize the size of the array. But to answer your question there is no problem in doing what you're doing.
I tried on Visual Studio on how the compiler is doing the name mangling for various function declarations -
void foo(int a[]);
void foo(int a[10]);
void foo(int *a);
For all the above declarations, the mangled name is unique -
?foo##YAXPAH#Z
I demangled to see what MS compiler is converting function declaration to -
void __cdecl foo(int * const)
So, at least it gives us an insight that MS compiler is not worried until a negative array index is used in function declaration. g++ also should be doing something like this, if I amn't wrong.

Resources