multi-character character constant and overflow in implicit constant conversion - c

I write a code is about black jack.
I cannot compiler it,it occurs warning.
multi-character character constant and overflow in implicit constant conversion
Can any one tell me what's going on.
I have thought it for long time plz help me.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int flower;
int k;
int add [13]={1,2,3,4,5,6,7,8,9,10,10,10,10};
char flower_all [4]={'\3','\4','\5','\6'};
char number_all [13]={'A','2','3','4','5','6','7','8','9','10','J','Q','K'};
char player_f[13],player_n[13];
char com_f[13],com_n[13];
int poker [52]={0};
int i,j,y,num,ans;
int player_p=0,com_p=0;
void wash (){
int k;
k=rand()%52;
while(poker[k]==1)
{
k=rand()%52;
}
poker[k]=1;
}
void give_card_p (){
char player_f[13],player_n[13];
int i,k;
int ans;
printf("請問是否要補牌? 1:要 2:不要");
scanf("%d",&ans);
fflush(stdin);
while (ans==1){
wash();
player_f[i]=flower_all[k/13];
player_n[i]=number_all[k%13];
player_p+=add[k%13];
continue;
if (player_p>21)
break;
}
}
int main (){
srand(time(0));
char player_f[13],player_n[13];
int k;
for(i=0;i<2;i++){
wash ();
player_f[i]=flower_all[k/13];
player_n[i]=number_all[k%13];
player_p+=add[k%13];
}
for (i=0;i<2;i++){
wash ();
com_f[i]=flower_all[k/13];
com_n[i]=number_all[k%13];
com_p+=add[k%13];
}
printf("%c%c",player_f[i],player_n[i]);
fflush(stdin);
return 0;
}

Single quotes ' denote 'character constants'. In the following line
char number_all [13]={'A','2','3','4','5','6','7','8','9','10','J','Q','K'};
the '10' is a 'multi-character constant'. This is 'implementation defined' - that is, different compilers are free to interpret it in different ways. In this case given the error message you have provided, it is likely the source of your error. I would suggest using an enumerated type to represent your cards.

I hope you are getting these two error
h.c:9:59: warning: multi-character character constant
h.c:9: warning: overflow in implicit constant conversion
It happens because in the program,
char number_all
[13]={'A','2','3','4','5','6','7','8','9','10','J','Q','K'};
you have '10' which is a multi character constant, the compiler is unable to convert it into a single character.
From Wikipedia:
Individual character constants are single-quoted, e.g. 'A', and have
type int (in C++, char). The difference is that "A" represents a
null-terminated array of two characters, 'A' and '\0', whereas 'A'
directly represents the character value (65 if ASCII is used). The
same backslash-escapes are supported as for strings, except that (of
course) " can validly be used as a character without being escaped,
whereas ' must now be escaped.
A character constant cannot be empty (i.e. '' is invalid syntax),
although a string may be (it still has the null terminating
character). Multi-character constants (e.g. 'xy') are valid, although
rarely useful — they let one store several characters in an integer
(e.g. 4 ASCII characters can fit in a 32-bit integer, 8 in a 64-bit
one). Since the order in which the characters are packed into an int
is not specified, portable use of multi-character constants is
difficult.

Related

Why do I receive the 'expected expression' error when compiling this C code

How do I get this code to reject numbers (in the form of floats) which are negative? This is part of problem set one for cs50? When attempting to compile, an error is generated in "n = get_int(%n, prompt"
#include <cs50.h>
#include <stdio.h>
//prompts user to submit amount of change
int get_positive_float(string prompt);
int main(void)
{
float change = get_positive_float("Change owed: ");
printf("%.2f\n", change);
}
//ensures user submits a positive number
int get_positive_float(string prompt)
{
int n;
do
{
n = get_int(%n, prompt);
}
while (n < 0);
return n;
}
This line:
n = get_int(%n, prompt);
Is wrong. % is the modulo operator and needs two operands. Maybe you intended this to be some kind of format string? You don't have a definition of get_int present, so it's hard to say.
As an editorial aside, it's a bit weird to have a function called get_positive_float that returns an int.
Gonna warn you right now, the way CS50 handles C strings and I/O is extremely misleading, and it will lead to heartburn later on. I understand the motivation (put a friendly, high-level interface on unfriendly, low-level operations), but they botched it badly.
From the CS50 Programmer's Manual entry for get_int, the first argument needs to be type char * (string is a typedef name, or alias, for char *1), so what you need to write is
n = get_int( prompt );
The expression %n is invalid in C, and that's what the compiler was choking on.
You can put this in a loop to repeat the operation while n is less than or equal to 0:
do {
n = get_int( prompt );
} while ( n <= 0 );
And this is what I mean about CS50 being misleading. A char * is not a string. In C, a string is a sequence of character values including a 0-valued terminator. For example, the string "hello" is represented as the sequence {'h', 'e', 'l', 'l', 'o', 0}. Strings are stored in arrays of character type. Under most circumstances, an expression of type "N-element array of T" will be converted ("decay") to an expression of type "pointer to T", and the value of the expression will be the address of the first element of the array. So, when we're dealing with strings, we're usually dealing with expressions of type char *, but a char * isn't always a pointer to the first character in a string.

+'0' wont give char value of int

I was trying to make this int to char program. The +'0' in the do while loop wont convert the int value to ascii, whereas, +'0' in main is converting. I have tried many statements, but it won't work in convert() .
#include<stdio.h>
#include<string.h>
void convert(int input,char s[]);
void reverse(char s[]);
int main()
{
int input;
char string[5];
//prcharf("enter int\n");
printf("enter int\n");
scanf("%d",&input);
convert(input,string);
printf("Converted Input is : %s\n",string);
int i=54;
printf("%c\n",(i+'0')); //This give ascii char value of int
printf("out\n");
}
void convert(int input,char s[])
{
int sign,i=0;
char d;
if((sign=input)<0)
input=-input;
do
{
s[i++]='0'+input%10;//but this gives int only
} while((input/=10)>0);
if(sign<0)
s[i++]='-';
s[i]=EOF;
reverse(s);
}
void reverse(char s[])
{
int i,j;
char temp;
for(i=0,j=strlen(s)-1;i<j;i++,j--)
{
temp=s[i];
s[i]=s[j];
s[j]=temp;
}
}
Output screenshot
Code screenshot
The +'0' in the do while loop wont convert the int value to ascii
Your own screenshot shows otherwise (assuming an ASCII-based terminal).
Your code printed 56, so it printed the bytes 0x35 and 0x36, so string[0] and string[1] contain 0x35 and 0x36 respectively, and 0x35 and 0x36 are the ASCII encodings of 5 and 6 respectively.
You can also verify this by printing the elements of string individually.
for (int i=0; string[i]; ++i)
printf("%02X ", string[i]);
printf("\n");
I tried your program and it is working for the most part. I get some goofy output because of this line:
s[i]=EOF;
EOF is a negative integer macro that represents "End Of File." Its actual value is implementation defined. It appears what you actually want is a null terminator:
s[i]='\0';
That will remove any goofy characters in the output.
I would also make that string in main a little bigger. No reason we couldn't use something like
char string[12];
I would use a bare minimum of 12 which will cover you to a 32 bit INT_MAX with sign.
EDIT
It appears (based on all the comments) you may be actually trying to make a program that simply outputs characters using numeric ascii values. What the convert function actually does is converts an integer to a string representation of that integer. For example:
int num = 123; /* Integer input */
char str_num[12] = "123"; /* char array output */
convert is basically a manual implementation of itoa.
If you are trying to simply output characters given ascii codes, this is a much simpler program. First, you should understand that this code here is a mis-interpretation of what convert was trying to do:
int i=54;
printf("%c\n",(i+'0'));
The point of adding '0' previously, was to convert single digit integers to their ascii code version. For reference, use this: asciitable. For example if you wanted to convert the integer 4 to a character '4', you would add 4 to '0' which is ascii code 48 to get 52. 52 being the ascii code for the character '4'. To print out the character that is represented by ascii code, the solution is much more straightforward. As others have stated in the comments, char is a essentially a numeric type already. This will give you the desired behavior:
int i = 102 /* The actual ascii value of 'f' */
printf("%c\n", i);
That will work, but to be safe that should be cast to type char. Whether or not this is redundant may be implementation defined. I do believe that sending incorrect types to printf is undefined behavior whether it works in this case or not. Safe version:
printf("%c\n", (char) i);
So you can write the entire program in main since there is no need for the convert function:
int main()
{
/* Make initialization a habit */
int input = 0;
/* Loop through until we get a value between 0-127 */
do {
printf("enter int\n");
scanf("%d",&input);
} while (input < 0 || input > 127);
printf("Converted Input is : %c\n", (char)input);
}
We don't want anything outside of 0-127. char has a range of 256 bits (AKA a byte!) and spans from -127 to 127. If you wanted literal interpretation of higher characters, you could use unsigned char (0-255). This is undesirable on the linux terminal which is likely expecting UTF-8 characters. Values above 127 will be represent portions of multi-byte characters. If you wanted to support this, you will need a char[] and the code will become a lot more complex.

printing the char value of each wide character's bytes

when running the following:
char acute_accent[7] = "éclair";
int i;
for (i=0; i<7; ++i)
{
printf("acute_accent[%d]: %c\n", i, acute_accent[i]);
}
I get:
acute_accent[0]:
acute_accent[1]: �
acute_accent[2]: c
acute_accent[3]: l
acute_accent[4]: a
acute_accent[5]: i
acute_accent[6]: r
which makes me think that the multibyte character é is 2-byte wide.
However, when running this (after ignoring the compiler warning me from multi-character character constant):
printf("size: %lu",sizeof('é'));
I get size: 4.
What's the reason for the different sizes?
EDIT: This question differs from this one because it is more about multibyte characters encoding, the different UTFs and their sizes, than the mere understanding of a size of a char.
The reason you're seeing a discrepancy is because in your first example, the character é was encoded by the compiler as the two-byte UTF-8 codepoint 0xC3 0xA9.
See here:
http://www.fileformat.info/info/unicode/char/e9/index.htm
And as described by dbush, the character 'é' was encoded as a UTF-32 codepoint and stored in an integer; therefore it was represented as four bytes.
Part of your confusion stems from using an implementation defined feature by storing Unicode in an undefined manner.
To prevent undefined behavior you should always clearly identify the encoding type for string literals.
For example:
char acute_accent[7] = u8"éclair"
This is very bad form because unless you count it out yourself, you can't know the exact length of the string unless. And indeed, my compiler (g++) is yelling at me because, while the string is 7 bytes, it's 8 bytes total with the null character at the end. So you have actually overrun the buffer.
It's much safer to use this instead:
const char* acute_accent = u8"éclair"
Notice how your string is actually 8-bytes:
#include <stdio.h>
#include <string.h> // strlen
int main() {
const char* a = u8"éclair";
printf("String length : %lu\n", strlen(a));
// Add +1 for the null byte
printf("String size : %lu\n", strlen(a) + 1);
return 0;
}
The output is:
String length : 7
String size : 8
Also note that the size of a char is different between C and C++!!
#include <stdio.h>
int main() {
printf("%lu\n", sizeof('a'));
printf("%lu\n", sizeof('é'));
return 0;
}
In C the output is:
4
4
While in C++ the output is:
1
4
From the C99 standard, section 6.4.4.4:
2 An integer character constant is a sequence of one or more multibyte
characters enclosed in single-quotes, as in 'x'.
...
10 An integer character constant has type int.
sizeof(int) on your machine is probably 4, which is why you're getting that result.
So 'é', 'c', 'l' are all integer character constants, so all are of type int whose size is 4. The fact that some are multibyte and some are not doesn't matter in this regard.

Warning: comparison is always true due to limited range of data type

I'm testing this function that's supposed to read input from the user but it throws me a segmentation fault
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define MAX_STRING_LENGTH 10
int
readinput(char *input)
{
int c;
int i=0;
while((c=getchar()) != EOF && c != '\n') //Here is where the warning occurs.
{
input[i]=c;
i++;
}
input[i]=0;
if(strlen(input)>0)
{
if(isalpha(input[0]) && input[1]=='-' && isalpha(input[2]) && strlen(input)==3)
return 0;
else if(!strcmp(input, "quit"))
return 1;
else if(!strncmp(input, "save ", 5))
return 2;
else if(!strcmp(input, "undo"))
return 3;
}
return -1;
}
int main()
{
char *str;
printf("write a string\n");
int nr=readinput(str);
printf("%d\n", nr);
printf("%s\n", str);
return 0;
}
I did notice the stupid error I made, but still, segmentation fault, why?
This is because EOF is defined (in my compiler) as -1 and char is unsigned byte. so it is always !=
c != '/n' is wrong
change it to
c != '\n'
c != '/n' should be c != '\n'
\ is an escape character which indicates, in the case where it is followed by n, a newline. /n will be treated as two distinct characters, which cannot properly be compared to a single char variable.
As for you segmentation fault, you'll need to allocate some space for str in your main function:
char* str = malloc(sizeof(char)*MAX_STRING_LENGTH);
or
char str[MAX_STRING_LENGTH];
but you'll also have to ensure you don't try to read a string that has more characters than your str array can hold.
It faults because you never allocated space for str and it points to a random location which causes readinput to try to store data in a place that doesn't exist.
The segmentation fault arises because you've passed an uninitialized pointer to the function readinput(). You need to do something like:
char str[4096];
int nr = readinput(str);
You should pass in a length of the array so that the called code can verify that it does not overflow its boundaries. Or you can live dangerously and decide that 4096 is big enough, which it probably will be until someone is trying to break your program deliberately.
The original compiler warning was because the multi-character constant '/n' has a value (of type int) which is outside the range of values that can be stored in a char, so when c is promoted to int, the != comparison with the (implementation-defined) value of '/n' is bound to be true. Hence the warning:
Warning: comparison is always true due to limited range of data type
All multi-character character constants have implementation-defined values. There are no portable multi-character character constants.
ISO/IEC 9899:2011 §6.4.4.4 Character constants
¶10 ... 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. ...

C programming language: Behavior of strcmp(str1, str2)

In C, I have a character array:
d[20]
Which is assigned the value 'if' with a null termination character:
d[0]='i'
d[1]='f'
d[2]='\0'
Should the value of strcmp(d,"if") be 0? Why?
I expect strcmp to return a value of 0. When I run it, I get the value of -1
If you mean d[0] = 'i'; d[1] = 'f'; d[2] = '\0';, then yes, that should return 0. d[2] = '/0' will assign something entirely different and your string won't be null terminated. At least not where you expect it to be - strcmp will probably head off into the weeds and start sucking mud.
#everyone: The '/0' typo was introduced by #Mark when he edited the original question. The original had the proper '\0'. Most of your answers (and assumptions about the OP) are misdirected.
#mekasperasky The following code correctly produces the value of 0. If you can compare it to your personal code and find the difference, you may have solved your own problem.
int main(int argc, char* argv[])
{
char d[20] = {0};
d[0] = 'i';
d[1] = 'f';
d[2] = '\0';
int value = strcmp(d,"if");
cout << value << endl;
return 0;
}
d[2] should be '\0', not '/0'.
The null value is indicated by:
d[2]='\0'
and not /0 as you wrote.
As other answers have mentioned, '/0' is not a null termination character, '\0' is.
You might expect that specifying more than one character in a character literal might generate an error; unfortunately (at least in this case) C allows 'multi-character' literal characters - but the exact behavior of multi-character literals is implementation defined (6.4.4.4/2 "Character constants"):
An integer character constant has type int. The value of an integer character constant containing a single character that maps to a single-byte execution character is the numerical value of the representation of the mapped character interpreted as an integer. 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.
So your '/0' 'character' ends up being some implementation defined int value that gets truncated when stored in d[2]. Your compiler might generate a warning for 'multi-character' literals, but that would probably also depend on the exact options you give the compiler.
For example, I get the following warning from GCC (I happen to have -Wall set):
C:\temp\test.cpp:6:14: warning: multi-character character constant
In my tests with MSVC and MinGW, the value of '/0' is 0x00002f30, so d[2] = '/0' ends up being equivalent to d[2] = '0'.
This works on every C compiler I have. I did not expect differently. It also works on Codepad.
Does this work on your C compiler?
#include <stdio.h>
#include <string.h>
char d[20];
int main(void) {
d[0]='i';
d[1]='f';
d[2]='\0';
printf("Value of strcmp=%i\n\n",strcmp(d,"if")); /* will print 0 */
return 0;
}

Resources