9

Right now I am trying to convert an int to a char in C programming. After doing research, I found that I should be able to do it like this:

int value = 10;
char result = (char) value;

What I would like is for this to return 'A' (and for 0-9 to return '0'-'9') but this returns a new line character I think. My whole function looks like this:

char int2char (int radix, int value) {
  if (value < 0 || value >= radix) {
    return '?';
  }

  char result = (char) value;

  return result;
}
Bathsheba
  • 231,907
  • 34
  • 361
  • 483
Kyle Hobbs
  • 445
  • 1
  • 4
  • 14
  • 3
    Why should converting `10` to a number return `'A'`? Are you expecting the conversion to be based on hex digits? – Barmar Sep 01 '17 at 19:32
  • Possible duplicate of [How to convert integer to char in C?](https://stackoverflow.com/questions/2279379/how-to-convert-integer-to-char-in-c) – PM 77-1 Sep 01 '17 at 19:33
  • 2
    @PM77-1: This one is the better dupe target, as the question is better written. I've closed that one to this one. – Bathsheba Sep 01 '17 at 20:04
  • Possible duplicate of [Convert char to int in C and C++](https://stackoverflow.com/questions/5029840/convert-char-to-int-in-c-and-c) – phuclv Nov 10 '18 at 13:25

9 Answers9

8

to convert int to char you do not have to do anything

char x;
int y;


/* do something */

x = y;

only one int to char value as the printable (usually ASCII) digit like in your example:

const char digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";

int inttochar(int val, int base)
{
    return digits[val % base];
}

if you want to convert to the string (char *) then you need to use any of the stansdard functions like sprintf, itoa, ltoa, utoa, ultoa .... or write one yourself:

char *reverse(char *str);
const char digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";

char *convert(int number, char *buff, int base)
{
    char *result = (buff == NULL || base > strlen(digits) || base < 2) ? NULL : buff;
    char sign = 0;


    if (number < 0)
    {
         sign = '-';

    }
    if (result != NULL)
    {
        do
        {
            *buff++ = digits[abs(number % (base ))];
            number /= base;
        } while (number);
        if(sign) *buff++ = sign;
        if (!*result) *buff++ = '0';
        *buff = 0;
        reverse(result);
    }
    return result;
}
0___________
  • 60,014
  • 4
  • 34
  • 74
  • 2
    This isn't what he wants. He wants to convert the number `9` to the character `'9'`, not `'\11'` – Barmar Sep 01 '17 at 19:36
  • 1
    "to convert int to char you do not have to do anything" - what do you mean by that? If for example `char` is signed, then the behaviour will be implementation defined if the `int` cannot fit into the `char`. Teaching in C has become sloppy over the years. These portability concerns matter. – Bathsheba Sep 01 '17 at 19:47
  • @Bathsheba no, it won't be undefined, because it is a narrowing integer conversion. [It is implementation-defined (including signal)](http://port70.net/~nsz/c/c11/n1570.html#6.3.1.3p3). – Antti Haapala -- Слава Україні Sep 01 '17 at 19:49
  • @Bathsheba but you do not have to do anything .All std lib. char functions have int paratemeters and return int as well ie `char c = tolower('C');`. Narrowing is not the UB. – 0___________ Sep 01 '17 at 19:50
  • @AnttiHaapala: You are of course correct - I've edited my comment. I will not teach C; it will add to the sloppiness. I don't understand the downvote on this answer btw. Let's reverse it. – Bathsheba Sep 01 '17 at 19:51
  • @Bathsheba I would rather say nitpickiness. It is a trivia. putting something potentially larger into a smaller container requires some consideration are care. If someone does not understand it - should not be programming computers as it is much too complicated for him . – 0___________ Sep 01 '17 at 19:55
  • @PeterJ_01 My comment was before the edit, when it was just `x = y;` – Barmar Sep 01 '17 at 20:11
  • @Barmar what is the diference between `x=y` and `char c = tolower('C');` except the believe or faith (function in std library is well written and will not return any worng values :)). – 0___________ Sep 01 '17 at 20:13
  • Corner cases oops: `convert(INT_MAX, ...), convert(-INT_MAX, ...)` work. `convert(INT_MIN, ..., 10), convert(INT_MIN, ..., 2)` fails. Interestingly the last 2 fail with "" and "0000000000000000000000000000000". Certain that `convert(INT_MIN...` invokes UB with `number = -number;` and `digits[number % (base )]` – chux - Reinstate Monica Sep 01 '17 at 21:06
  • @chux yo- sorted – 0___________ Sep 01 '17 at 21:12
  • `INT_MIN` is a pesky case. With `number == INT_MIN`, `number = -number;` can be the UB. `if(-number != n) ...;` is too late. – chux - Reinstate Monica Sep 01 '17 at 21:14
  • sorted it another way - brutforce :) – 0___________ Sep 01 '17 at 21:16
5

A portable way of doing this would be to define a

const char* foo = "0123456789ABC...";

where ... are the rest of the characters that you want to consider.

Then and foo[value] will evaluate to a particular char. For example foo[0] will be '0', and foo[10] will be 'A'.

If you assume a particular encoding (such as the common but by no means ubiquitous ASCII) then your code is not strictly portable.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
2

Characters use an encoding (typically ASCII) to map numbers to a particular character. The codes for the characters '0' to '9' are consecutive, so for values less than 10 you add the value to the character constant '0'. For values 10 or more, you add the value minus 10 to the character constant 'A':

char result;
if (value >= 10) {
    result = 'A' + value - 10;
} else {
    result = '0' + value;
}
dbush
  • 205,898
  • 23
  • 218
  • 273
  • It's odd that folk choose to do it this way given that the portable solution is not particularly more verbose and is probably faster too. I'm sure you know this, but to put it out there, the C standard requires 0 to 9 to be consecutive, but pretty much anything goes for the alphas. – Bathsheba Sep 01 '17 at 19:39
1

Converting Int to Char

I take it that OP wants more that just a 1 digit conversion as radix was supplied.


To convert an int into a string, (not just 1 char) there is the sprintf(buf, "%d", value) approach.

To do so to any radix, string management becomes an issue as well as dealing the corner case of INT_MIN


The following C99 solution returns a char* whose lifetime is valid to the end of the block. It does so by providing a compound literal via the macro.

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>

// Maximum buffer size needed
#define ITOA_BASE_N (sizeof(unsigned)*CHAR_BIT + 2)

char *itoa_base(char *s, int x, int base) {
  s += ITOA_BASE_N - 1;
  *s = '\0';
  if (base >= 2 && base <= 36) {
    int x0 = x;
    do {
      *(--s) = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[abs(x % base)];
      x /= base;
    } while (x);
    if (x0 < 0) {
      *(--s) = '-';
    }
  }
  return s;
}

#define TO_BASE(x,b) itoa_base((char [ITOA_BASE_N]){0} , (x), (b))

Sample usage and tests

void test(int x) {
  printf("base10:% 11d base2:%35s  base36:%7s ", x, TO_BASE(x, 2), TO_BASE(x, 36));
  printf("%ld\n", strtol(TO_BASE(x, 36), NULL, 36));
}

int main(void) {
  test(0);
  test(-1);
  test(42);
  test(INT_MAX);
  test(-INT_MAX);
  test(INT_MIN);
}

Output

base10:          0 base2:                                  0  base36:      0 0
base10:         -1 base2:                                 -1  base36:     -1 -1
base10:         42 base2:                             101010  base36:     16 42
base10: 2147483647 base2:    1111111111111111111111111111111  base36: ZIK0ZJ 2147483647
base10:-2147483647 base2:   -1111111111111111111111111111111  base36:-ZIK0ZJ -2147483647
base10:-2147483648 base2:  -10000000000000000000000000000000  base36:-ZIK0ZK -2147483648

Ref How to use compound literals to fprintf() multiple formatted numbers with arbitrary bases?

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
0

Check out the ascii table

The values stored in a char are interpreted as the characters corresponding to that table. The value of 10 is a newline

savram
  • 500
  • 4
  • 18
0

So characters in C are based on ASCII (or UTF-8 which is backwards-compatible with ascii codes). This means that under the hood, "A" is actually the number "65" (except in binary rather than decimal). All a "char" is in C is an integer with enough bytes to represent every ASCII character. If you want to convert an int to a char, you'll need to instruct the computer to interpret the bytes of an int as ASCII values - and it's been a while since I've done C, but I believe the compiler will complain since char holds fewer bytes than int. This means we need a function, as you've written. Thus,

if(value < 10) return '0'+value;
return 'A'+value-10;

will be what you want to return from your function. Keep your bounds checks with "radix" as you've done, imho that is good practice in C.

0

1. Converting int to char by type casting

Source File charConvertByCasting.c

#include <stdio.h>

int main(){
    int i = 66;              // ~~Type Casting Syntax~~
    printf("%c", (char) i); //  (type_name) expression
    return 0;
}

Executable charConvertByCasting.exe command line output:

C:\Users\boqsc\Desktop\tcc>tcc -run charconvert.c
B

Additional resources:
https://www.tutorialspoint.com/cprogramming/c_type_casting.htm https://www.tutorialspoint.com/cprogramming/c_data_types.htm

2. Convert int to char by assignment

Source File charConvertByAssignment.c

#include <stdio.h>

int main(){
    int i = 66;
    char c = i;
    printf("%c", c);
    return 0;
}

Executable charConvertByAssignment.exe command line output:

C:\Users\boqsc\Desktop\tcc>tcc -run charconvert.c
B
user3789797
  • 450
  • 6
  • 15
0

You can do

char a;
a = '0' + 5;

You will get character representation of that number.

maxim
  • 31
  • 2
0

Borrowing the idea from the existing answers, i.e. making use of array index. Here is a "just works" simple demo for "integer to char[]" conversion in base 10, without any of <stdio.h>'s printf family interfaces.

Test:

$ cc -o testint2str testint2str.c && ./testint2str
Result: 234789

Code:

#include <stdio.h>
#include <string.h>

static char digits[] = "0123456789";

void int2str (char *buf, size_t sz, int num);


/*
  Test: 
        cc -o testint2str testint2str.c && ./testint2str
*/
int
main ()
{
  int num = 234789;
  char buf[1024] = { 0 };

  int2str (buf, sizeof buf, num);

  printf ("Result: %s\n", buf);


}

void
int2str (char *buf, size_t sz, int num)
{
  /*
     Convert integer type to char*, in base-10 form.
   */

  char *bufp = buf;
  int i = 0;

  // NOTE-1
  void __reverse (char *__buf, int __start, int __end)
  {
    char __bufclone[__end - __start];
    int i = 0;
    int __nchars = sizeof __bufclone;
    for (i = 0; i < __nchars; i++)
      {
    __bufclone[i] = __buf[__end - 1 - i];
      }
    memmove (__buf, __bufclone, __nchars);
  }

  while (num > 0)
    {
      bufp[i++] = digits[num % 10]; // NOTE-2
      num /= 10;
    }

  __reverse (buf, 0, i);

  // NOTE-3
  bufp[i] = '\0';
}

// NOTE-1:
//         "Nested function" is GNU's C Extension. Put it outside if not
//         compiled by GCC.
// NOTE-2:
//         10 can be replaced by any radix, like 16 for hexidecimal outputs.
//
// NOTE-3:
//         Make sure inserting trailing "null-terminator" after all things
//         done.

NOTE-1: "Nested function" is GNU's C Extension. Put it outside if not compiled by GCC.

NOTE-2: 10 can be replaced by any radix, like 16 for hexidecimal outputs.

NOTE-3: Make sure inserting trailing "null-terminator" after all things done.

Michael Lee
  • 197
  • 8