Related
How do I convert a char to an int in C and C++?
Depends on what you want to do:
to read the value as an ascii code, you can write
char a = 'a';
int ia = (int)a;
/* note that the int cast is not necessary -- int ia = a would suffice */
to convert the character '0' -> 0, '1' -> 1, etc, you can write
char a = '4';
int ia = a - '0';
/* check here if ia is bounded by 0 and 9 */
Explanation:
a - '0' is equivalent to ((int)a) - ((int)'0'), which means the ascii values of the characters are subtracted from each other. Since 0 comes directly before 1 in the ascii table (and so on until 9), the difference between the two gives the number that the character a represents.
Well, in ASCII code, the numbers (digits) start from 48. All you need to do is:
int x = (int)character - 48;
Or, since the character '0' has the ASCII code of 48, you can just write:
int x = character - '0'; // The (int) cast is not necessary.
C and C++ always promote types to at least int. Furthermore character literals are of type int in C and char in C++.
You can convert a char type simply by assigning to an int.
char c = 'a'; // narrowing on C
int a = c;
char is just a 1 byte integer. There is nothing magic with the char type! Just as you can assign a short to an int, or an int to a long, you can assign a char to an int.
Yes, the name of the primitive data type happens to be "char", which insinuates that it should only contain characters. But in reality, "char" is just a poor name choice to confuse everyone who tries to learn the language. A better name for it is int8_t, and you can use that name instead, if your compiler follows the latest C standard.
Though of course you should use the char type when doing string handling, because the index of the classic ASCII table fits in 1 byte. You could however do string handling with regular ints as well, although there is no practical reason in the real world why you would ever want to do that. For example, the following code will work perfectly:
int str[] = {'h', 'e', 'l', 'l', 'o', '\0' };
for(i=0; i<6; i++)
{
printf("%c", str[i]);
}
You have to realize that characters and strings are just numbers, like everything else in the computer. When you write 'a' in the source code, it is pre-processed into the number 97, which is an integer constant.
So if you write an expression like
char ch = '5';
ch = ch - '0';
this is actually equivalent to
char ch = (int)53;
ch = ch - (int)48;
which is then going through the C language integer promotions
ch = (int)ch - (int)48;
and then truncated to a char to fit the result type
ch = (char)( (int)ch - (int)48 );
There's a lot of subtle things like this going on between the lines, where char is implicitly treated as an int.
(This answer addresses the C++ side of things, but the sign extension problem exists in C too.)
Handling all three char types (signed, unsigned, and char) is more delicate than it first appears. Values in the range 0 to SCHAR_MAX (which is 127 for an 8-bit char) are easy:
char c = somevalue;
signed char sc = c;
unsigned char uc = c;
int n = c;
But, when somevalue is outside of that range, only going through unsigned char gives you consistent results for the "same" char values in all three types:
char c = somevalue;
signed char sc = c;
unsigned char uc = c;
// Might not be true: int(c) == int(sc) and int(c) == int(uc).
int nc = (unsigned char)c;
int nsc = (unsigned char)sc;
int nuc = (unsigned char)uc;
// Always true: nc == nsc and nc == nuc.
This is important when using functions from ctype.h, such as isupper or toupper, because of sign extension:
char c = negative_char; // Assuming CHAR_MIN < 0.
int n = c;
bool b = isupper(n); // Undefined behavior.
Note the conversion through int is implicit; this has the same UB:
char c = negative_char;
bool b = isupper(c);
To fix this, go through unsigned char, which is easily done by wrapping ctype.h functions through safe_ctype:
template<int (&F)(int)>
int safe_ctype(unsigned char c) { return F(c); }
//...
char c = CHAR_MIN;
bool b = safe_ctype<isupper>(c); // No UB.
std::string s = "value that may contain negative chars; e.g. user input";
std::transform(s.begin(), s.end(), s.begin(), &safe_ctype<toupper>);
// Must wrap toupper to eliminate UB in this case, you can't cast
// to unsigned char because the function is called inside transform.
This works because any function taking any of the three char types can also take the other two char types. It leads to two functions which can handle any of the types:
int ord(char c) { return (unsigned char)c; }
char chr(int n) {
assert(0 <= n); // Or other error-/sanity-checking.
assert(n <= UCHAR_MAX);
return (unsigned char)n;
}
// Ord and chr are named to match similar functions in other languages
// and libraries.
ord(c) always gives you a non-negative value – even when passed a negative char or negative signed char – and chr takes any value ord produces and gives back the exact same char.
In practice, I would probably just cast through unsigned char instead of using these, but they do succinctly wrap the cast, provide a convenient place to add error checking for int-to-char, and would be shorter and more clear when you need to use them several times in close proximity.
Use static_cast<int>:
int num = static_cast<int>(letter); // if letter='a', num=97
Edit: You probably should try to avoid to use (int)
int num = (int) letter;
check out Why use static_cast<int>(x) instead of (int)x? for more info.
I have absolutely null skills in C, but for a simple parsing:
char* something = "123456";
int number = parseInt(something);
...this worked for me:
int parseInt(char* chars)
{
int sum = 0;
int len = strlen(chars);
for (int x = 0; x < len; x++)
{
int n = chars[len - (x + 1)] - '0';
sum = sum + powInt(n, x);
}
return sum;
}
int powInt(int x, int y)
{
for (int i = 0; i < y; i++)
{
x *= 10;
}
return x;
}
It sort of depends on what you mean by "convert".
If you have a series of characters that represents an integer, like "123456", then there are two typical ways to do that in C: Use a special-purpose conversion like atoi() or strtol(), or the general-purpose sscanf(). C++ (which is really a different language masquerading as an upgrade) adds a third, stringstreams.
If you mean you want the exact bit pattern in one of your int variables to be treated as a char, that's easier. In C the different integer types are really more of a state of mind than actual separate "types". Just start using it where chars are asked for, and you should be OK. You might need an explicit conversion to make the compiler quit whining on occasion, but all that should do is drop any extra bits past 256.
I recomend to use the following function:
/* chartoint: convert char simbols to unsigned int*/
int chartoint(char s[])
{
int i, n;
n = 0;
for (i = 0; isdigit(s[i]); ++i){
n = 10 * n + (s[i] - '0');
}
return n;
}
The result of function could be checked by:
printf("char 00: %d \r\n", chartoint("00"));
printf("char 01: %d \r\n", chartoint("01"));
printf("char 255: %d \r\n", chartoint("255"));
Presumably you want this conversion for using functions from the C standard library.
In that case, do (C++ syntax)
typedef unsigned char UChar;
char myCppFunc( char c )
{
return char( someCFunc( UChar( c ) ) );
}
The expression UChar( c ) converts to unsigned char in order to get rid of negative values, which, except for EOF, are not supported by the C functions.
Then the result of that expression is used as actual argument for an int formal argument. Where you get automatic promotion to int. You can alternatively write that last step explicitly, like int( UChar( c ) ), but personally I find that too verbose.
Cheers & hth.,
I was having problems converting a char array like "7c7c7d7d7d7d7c7c7c7d7d7d7d7c7c7c7c7c7c7d7d7c7c7c7c7d7c7d7d7d7c7c2e2e2e" into its actual integer value that would be able to be represented by `7C' as one hexadecimal value. So, after cruising for help I created this, and thought it would be cool to share.
This separates the char string into its right integers, and may be helpful to more people than just me ;)
unsigned int* char2int(char *a, int len)
{
int i,u;
unsigned int *val = malloc(len*sizeof(unsigned long));
for(i=0,u=0;i<len;i++){
if(i%2==0){
if(a[i] <= 57)
val[u] = (a[i]-50)<<4;
else
val[u] = (a[i]-55)<<4;
}
else{
if(a[i] <= 57)
val[u] += (a[i]-50);
else
val[u] += (a[i]-55);
u++;
}
}
return val;
}
Hope it helps!
For char or short to int, you just need to assign the value.
char ch = 16;
int in = ch;
Same to int64.
long long lo = ch;
All values will be 16.
Use "long long" instead a "int" so it works for bigger numbers. Here the elegant solution.
long long ChardToint(char *arr, size_t len){
int toptenf=1;
long long toptenLf=10000000LL;
long long makeintf=3000000000000;
makeintf= 0LL;
int holdNumberf=0;
for(int i=len-1;i>=0 ;i--){
switch(arr[i]){
case '0':
holdNumberf=0;
break;
case '1':
holdNumberf=1;
break;
case '2':
holdNumberf=2;
break;
case '3':
holdNumberf=3;
break;
case '4':
holdNumberf=4;
break;
case '5':
holdNumberf=5;
break;
case '6':
holdNumberf=6;
break;
case '7':
holdNumberf=7;
break;
case '8':
holdNumberf=8;
break;
case '9':
holdNumberf=9;
break;
default:
holdNumberf=0;
}
if(toptenf>=10000000){
makeintf=makeintf+holdNumberf*toptenLf;
toptenLf=toptenLf*10;
}else{
makeintf=makeintf+holdNumberf*toptenf;
toptenf=toptenf*10;
}
}
return makeintf;
}
int charToint(char a){
char *p = &a;
int k = atoi(p);
return k;
}
You can use this atoi method for converting char to int. For more information, you can refer to this http://www.cplusplus.com/reference/cstdlib/atoi/ , http://www.cplusplus.com/reference/string/stoi/.
I am trying to grasp pointers and I have this simple code for which I need some explanation.
I need to copy one char array to another. In my main function I have this code:
const int MAX_SIZE = 100;
char x[MAX_SIZE] = "1234565";
char* y = new char[MAX_SIZE];
copyArray(x, y);
std::cout << y;
delete [] y;
Now comes the question, how does this code (which works jut fine):
while ((*dest = *source) != '\0')
{
dest += 1;
source += 1;
}
Differ from this (gives strange characters at the end):
while (*source != '\0')
{
*dest = *source;
dest += 1;
source += 1;
}
Looking at this it seems those two functions are pretty similar.
It makes sense that we are copying until we reach a null-terminator in the source string, right (2nd function)?
But it's not working correctly - I get some strange characters at the end of the copied array. However, the first function works just fine.
void copyArray(const char* source, char* dest);
The form
while ((*dest = *source) != '\0')
{
dest += 1;
source += 1;
}
guarantees that the assignment of the character to copy ((*dest = *source)) is applied before testing the condition if the terminating '\0' character is reached is evaluated to false.
The second version doesn't copy the terminating '\0' character, because the loop ends before the
*dest = *source;
statement is ever reached.
(*dest = *source) is an evaluated expression just like the 1+1 part of int i = 1+1; so, after it is evaluated, the value is usable in an other expression
The difference is that in ((*dest = *source) != '\0'), the value of *source is assigned to *dest, then the whole expression is evaluated ( expression has the same value than *source ) while the value pointed by *source is only used to evaluate *source != '\0', but never assigned during the evaluation of that statement.
EDIT
user0042 brings a realy acute observation : by doing so, the following code
while ((*dest = *source) != '\0')
{
dest += 1;
source += 1;
}
ensures that the final char of the array has a value of '\0'
In the example you incrementing the addresses of x, y thus until the last character they point to Null-terminator so you have to declare a temporary variables to hold the first address:
char* x = "1234565";
char* y = new char[MAX_SIZE];
// Temporary pointers to hold the first element's address
char* tmp1 = x;
char* tmp2 = y;
while( (*y = *x) != '\0'){
x += 1; // X no longer points to the first element
y += 1; // Y no longer points to the first element
}
std::cout << tmp2;
You can use a do while loop instead of while:
char* x = "1234565";
const int size = strlen(x);
char* y = new char[size];
char* tmp1 = x;
char* tmp2 = y;
do{
*y = *x;
x += 1;
y += 1;
}while( *(x - 1) != '\0');
// Now no need for adding a null-terminator it is already added in the loop
// tmp2[size] = '\0';
std::cout << tmp2;
Because Assigning the values before incrementing so the last character \0 will break the loop before added to the destination pointer y. Thus I made the loop breaks not on n = '\0' but on n - 1 = '\0' to ensure that it is added to y.
As a part of a larger program, I must convert a string of numbers to an integer(eventually a float). Unfortunately I am not allowed to use casting, or atoi.
I thought a simple operation along the lines of this:
void power10combiner(string deciValue){
int result;
int MaxIndex=strlen(deciValue);
for(int i=0; MaxIndex>i;i++)
{
result+=(deciValue[i] * 10**(MaxIndex-i));
}
}
would work. How do I convert a char to a int? I suppose I could use ASCII conversions, but I wouldn't be able to add chars to ints anyways(assuming that the conversion method is to have an enormous if statement that returns the different numerical value behind each ASCII number).
There are plenty of ways to do this, and there are some optimization and corrections that can be done to your function.
1) You are not returning any value from your function, so the return type is now int.
2) You can optimize this function by passing a const reference.
Now for the examples.
Using std::stringstream to do the conversion.
int power10combiner(const string& deciValue)
{
int result;
std::stringstream ss;
ss << deciValue.c_str();
ss >> result;
return result;
}
Without using std::stringstream to do the conversion.
int power10combiner(const string& deciValue)
{
int result = 0;
for (int pos = 0; deciValue[pos] != '\0'; pos++)
result = result*10 + (deciValue[pos] - '0');
return result;
}
EDITED by suggestion, and added a bit of explanation.
int base = 1;
int len = strlen(deciValue);
int result = 0;
for (int i = (len-1); i >= 0; i--) { // Loop right to left. Is this off by one? Too tired to check.
result += (int(deciValue[i] - '0') * base); // '0' means "where 0 is" in the character set. We are doing the conversion int() because it will try to multiply it as a character value otherwise; we must cast it to int.
base *= 10; // This raises the base...it's exponential but simple and uses no outside means
}
This assumes the string is only numbers. Please comment if you need more clarification.
You can parse a string iteratively into an integer by simply implementing the place-value system, for any number base. Assuming your string is null-terminated and the number unsigned:
unsigned int parse(const char * s, unsigned int base)
{
unsigned int result = 0;
for ( ; *s; ++s)
{
result *= base;
result += *s - '0'; // see note
}
return result;
}
As written, this only works for number bases up to 10 using the numerals 0, ..., 9, which are guaranteed to be arranged in order in your execution character set. If you need larger number bases or more liberal sets of symbols, you need to replace *s - '0' in the indicated line by a suitable lookup mechanism that determines the digit value of your input character.
I would use std::stringstream, but nobody posted yet a solution using strtol, so here is one. Note, it doesn't perform handle out-of-range errors. On unix/linux you can use errno variable to detect such errors(by comparing it to ERANGE).
BTW, there are strtod/strtof/strtold functions for floating-point numbers.
#include <iostream>
#include <cstdlib>
#include <string>
int power10combiner(const std::string& deciValue){
const char* str = deciValue.c_str();
char* end; // the pointer to the first incorrect character if there is such
// strtol/strtoll accept the desired base as their third argument
long int res = strtol(str, &end, 10);
if (deciValue.empty() || *end != '\0') {
// handle error somehow, for example by throwing an exception
}
return res;
}
int main()
{
std::string s = "100";
std::cout << power10combiner(s) << std::endl;
}
So, I am learning about pointers via http://cplusplus.com/doc/tutorial/pointers/ and I do not understand anything about the pointer arithmetic section. Could someone clear things up or point me to a tutorial about this that I may better understand.
I am especially confused with all the parentheses things like the difference between *p++,(*p)++, *(p++), and etc.
*p++
For this one, ++ has higher precedence then * so it increments the pointer by one but retrieves the value at the original location since post-increment returns the pointer and then increments its value.
(*p)++
This forces the precedence in the other direction, so the pointer is de-referenced first and then the value at that location in incremented by one (but the value at the original pointer location is returned).
*(p++)
This one increments the pointer first so it acts the same as the first one.
An important thing to note, is that the amount the pointer is incremented is affected by the pointer type. From the link you provided:
char *mychar;
short *myshort;
long *mylong;
char is one byte in length so the ++ increases the pointer by 1 (since pointers point to the beginning of each byte).
short is two bytes in length so the ++ increases the pointer by 2 in order to point at the start of the next short rather than the start of the next byte.
long is four bytes in the length so the ++ increases the pointer by 4.
I found useful some years ago an explanation of strcpy, from Kernighan/Ritchie (I don't have the text available now, hope the code it's accurate): cpy_0, cpy_1, cpy_2 are all equivalent to strcpy:
char *cpy_0(char *t, const char *s)
{
int i = 0;
for ( ; t[i]; i++)
t[i] = s[i];
t[i] = s[i];
i++;
return t + i;
}
char *cpy_1(char *t, const char *s)
{
for ( ; *s; ++s, ++t)
*t = *s;
*t = *s;
++t;
return t;
}
char *cpy_2(char *t, const char *s)
{
while (*t++ = *s++)
;
return t;
}
First you have to understand what post increment does;
The post increment, increases the variable by one BUT the expression (p++) returns the original value of the variable to be used in the rest of the expression.
char data[] = "AX12";
char* p;
p = data;
char* a = p++;
// a -> 'A' (the original value of p was returned from p++ and assigned to a)
// p -> 'X'
p = data; // reset;
char l = *(p++);
// l = 'A'. The (p++) increments the value of p. But returns the original
value to be used in the remaining expression. Thus it is the
original value that gets de-referenced by * so makeing l 'A'
// p -> 'X'
Now because of operator precedence:
*p++ is equivalent to *(p++)
Finally we have the complicated one:
p = data;
char m = (*p)++;
// m is 'A'. First we deference 'p' which gives us a reference to 'A'
// Then we apply the post increment which applies to the value 'A' and makes it a 'B'
// But we return the original value ('A') to be used in assignment to 'm'
// Note 1: The increment was done on the original array
// data[] is now "BXYZ";
// Note 2: Because it was the value that was post incremented p is unchaged.
// p -> 'B' (Not 'X')
*p++
Returns the content, *p, an then increases the pointer's value (postincrement). For example:
int numbers[2];
int *p;
p = &numbers[0];
*p = 4; //numbers[0] = 4;
*(p + 1) = 8; //numbers[1] = 8;
int a = *p++; //a = 4 (the increment takes place after the evaluation)
//*++p would have returned 8 (a = 8)
int b = *p; //b = 8 (p is now pointing to the next integer, not the initial one)
And about:
(*p)++
It increases the value of the content, *p = *p + 1;.
(p++); //same as p++
Increases the pointer so it points to the next element (that may not exist) of the size defined when you declared the pointer.
Recently in an interview i was asked a question to write a function which takes two character arrays(integers) as input and returns the output character array.
Function Signature:
char* find_sum(char* a, char* b)
How would one approach this?
Example scenario:
find_sum("12345","32142") = "44487"
Note:
The number of digits can be many(1-100).
u can add huge numbers using the char array approach. however you need to delete the char* after using it every time or use some smart pointer.
char* find_sum(char* a, char* b) {
int lenA = strlen(a), lenB = strlen(b);
int max = lenA > lenB ? lenA : lenB; // Get the max for allocation
char* res = (char*)malloc (max+2);
memset(res, '0', max +1); // set the result to all zeros
res[max+1] = '\0';
int i=lenA - 1, j = lenB - 1, k = max;
for (; i >= 0 || j >=0; --i, --j, --k) {
int sum = 0;
if (i >= 0 && j>=0)
sum = a[i] - '0' + b[j] - '0' + res[k] - '0' ; // add using carry
else if (j >= 0)
sum = b[j] - '0' + res[k] - '0' ; // add the carry with remaining
else if (i >= 0)
sum = a[i] - '0' + res[k] - '0' ;
res[k] = sum % 10 + '0';
res[k-1] = sum / 10 + '0';
}
return res;
}
int main() {
printf (" sum = %s ", find_sum("12345432409240242342342342234234234", "9934563424242424242423442424234"));
return 0;
}
Note: The precondition for the function is the input char arrays should contain only numbers.
The most obvious answer is internally to use something like atoi and sprintf to convert the numbers to integers, do the sum and return the response as a char* However the important thing here is not what the interviewer is asking but why.
In my experience, the interviewer is probably not wanting you to write a hum-dinger of a solution that covers all angles. What they most likely want to get to is what the most common approach would be, and what are the likely limitations of such a function. I.e.:
What happens if your input numbers aren't integers? (e.g. 13.245, 2.3E+7)
What happens if your 'numbers' aren't numbers at all?
What happens if your input integers are really big? (i.e. ~2^31)
How could you detect an error and how would you report it.
How would you allocate memory for the resultant string?
What would the memory allocation imply for the calling code?
What is the efficiency of the function and how could you make it more efficient?
In this way, the interviewer wants to probe your experience of critiquing approaches to problem solving. Naturally, there are many ways of solving this problem. Some of the approaches have side-effects but in certain contexts, these side effects (i.e. integer overflow) may not be greatly important.
Coding is often a trade off between a comprehensive solution and what can be produced quickly (and therefore less expensively) These questions allow the interviewer to get a feel for your understanding of quality - that is, can you design something that is fit for purpose, robust and yet does not take too long to put together - and also your experience of having to identify / resolve common bugs.
You did not mention anything about not using any external command.
We can do this easily on machines that have the bc command. You can add any number of digits:
$ echo "99999999999999999999999999999999+1" | bc
100000000000000000000000000000000
$
We call this bc from the C program. We need to construct the right command line as
echo "n1+n2" | bc
and then use popen to read its result. Below is the function to do that. The code lacks many error checking.
char* find_sum(char* a, char* b) {
int l1 = strlen(a),l2 = strlen(b);
int cmdLen = l1 + l2 + 30; // 30 to accomodate echo,bc and stuff.
char *cmd = malloc(cmdLen);
snprintf(cmd,cmdLen,"echo \"%s+%s\"|bc",a,b);
FILE *fp = popen(cmd, "r");
int max = (l1 > l2) ? l1:l2;
max += 2; // one for additional digit, one for null.
char *result = malloc(max);
fgets(result, max, fp);
return result;
}
Working link
The answer is probably that you have to ask what is returned? Is this a memory allocated string that should be freed by the user or is this a static memory location that is overwritten the next time the function is called?
char* find_sum(char* a, char* b) {
static char buf[MAX_STRING];
...
return buf;
}
or
char* find_sum(char* a, char* b) {
char *buf = malloc(MAX_STRING*sizeof(char));
...
return buf;
}
Giving this answer shows the interviewer that you know more about C than just making an algorithm. (As a side-node: It also shows why a language like java shines in these situations as the garbage collections takes care of freeing the buffer).
Just remember how you did addition in the second grade on the paper.
#include <stdio.h>
#include <string.h>
char *sum(char *a,char *b);
int main()
{
char a[] = "100";
char b[] = "300";
char *c;
c = sum(a,b);
printf("%s",c);
}
char *sum(char *a,char *b)
{
int x,y,z,z2,zLen;
char *result;
x = atoi(a);
y = atoi(b);
z = x + y;
z2 = z;
/* Determine the length of the string now! */
for(zLen = 1; z > 0 || z < 0; zLen++)
z/=10;
result = (char *)malloc(zLen*sizeof(char)+1);
sprintf(result,"%d\0",z2);
return result;
}
Quick and dirty implimentation. Note that I'm not freeing the memory, which is not "ideal". Will fetch you extra brownie points for mentioning that there are no error checks happening here, and no freeing of memory, which is far from ideal in practical situations.
Online Version of Code
Several of the answers mention the use of atoi & itoa functions.
atoi returns int. Your numbers may not fit into an integer data type.
You may try to alleviate the problem (not completely though) using atol, which return a long int, or atoll, which returns a long long int.
Also, itoa is not a standard library function, and hence may not be available on all systems.
Here's another approach. Nothe that I don't like the prototype for find_sum. I'd very much prefer it to be
char *find_sum(char *dst, size_t len, const char *a, const char *b);
letting the caller be responsible for managing resources.
a and b are strings composed of 1 or more digits (and digits only); the result should be freed by caller. Calling find_sum with invalid inputs causes UB :-)
char *find_sum(char *a, char *b) {
char *res;
int alen, blen, rlen;
int carry;
alen = strlen(a);
blen = strlen(b);
rlen = 1 + ((alen > blen) ? alen : blen);
res = malloc(1 + rlen);
if (res) {
int oldlen = rlen;
res[rlen] = 0;
carry = 0;
while (rlen) {
int tmp;
if (alen && blen) tmp = a[--alen] - '0' + b[--blen] - '0';
else if (alen) tmp = a[--alen] - '0';
else if (blen) tmp = b[--blen] - '0';
else tmp = 0;
tmp += carry;
res[--rlen] = '0' + tmp % 10;
carry = tmp / 10;
}
if (res[0] == '0') memmove(res, res+1, oldlen);
}
return res;
}
There's a working version of the function at ideone ( http://ideone.com/O2jrx ).
itoa(atoi(a) + atoi(b), t, 10); if you want to be lazy, where t is a char[MAX_NUMBER_OF_DIGITS].
The real question regards the output array, as mentioned by other users.