I.E., you enter the number 5, and the character A and the output would yield F. I have no idea how to even start to go about this, any give me a push in the right direction?
Individual characters are represented by numbers according to the ASCII code (usually). In C, if you add a number to a character, you're shifting the character down. Try:
char c = 'A';
int n = 5;
printf("%c\n", c + n);
Look at the ASCII table and note the values of the characters.
Try this:
#include <stdio.h>
char shift_char(char val, char shift)
{
val = toupper(val);
assert(isupper(val));
char arr[26] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
return arr[ ( (toupper(val) - 'A' + shift) % 26) ];
}
You can get a little fancier if you want to preserve the case of the character. It also assumes, but does not verify shift is non-negative. That case may cause problems with the modulus operation you will need to guard against... or better yet prevent. Still, since this is tagged as homework, that's the sort of thing you should work through.
If you can assume ASCII, it is easier.
Characters are no more than simple numbers: only the interpretation of said numbers changes. In ASCII all letters are sequential; so the number for 'A' + 5 is the number for 'F'; 'F' - 1 is 'E' ..., ...
int ch = 'J';
ch -= 2; putchar(ch);
ch -= 3; putchar(ch);
ch += 7; putchar(ch); putchar(ch);
ch += 3; putchar(ch);
puts("");
Just pay attention to wrapping!
If you can't assume ASCII, you need to convert characters yourself. Something like:
char charr[26] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
int ndx = 9; /* charr[9] is 'J' */
ndx -= 2; putchar(charr[ndx]);
ndx -= 3; putchar(charr[ndx]);
ndx += 7; putchar(charr[ndx]); putchar(charr[ndx]);
ndx += 3; putchar(charr[ndx]);
puts("");
Do not forget the wrapping
Other people have pointed out that you can use ASCII.
An easy way to handle wrapping is with modulus arithmetic:
char result, ch;
int offset;
... // Populate ch with the letter to be changed and offset with the number.
result = ch - 'a';
result = (result + offset) % 26; // 26 letters in the alphabet
result += 'a';
char shift_char(char c, char shift)
{
if(isalpha(c)) {
if (c>='A' && c<='Z') {
return 'A' + ( (c - 'A' + shift) % 26);
} else if(c>='a' && c<='z') {
return 'a' + ( (c - 'a' + shift) % 26);
}
}
return c;
}
Related
`
#include <unistd.h>
int ft_atoi(char *str)
{
int c;
int sign;
int result;
c = 0;
sign = 1;
result = 0;
while ((str[c] >= '\t' && str[c] <= '\r') || str[c] == ' ')
{
c++;
}
while (str[c] == '+' || str[c] == '-')
{
if (str[c] == '-')
sign *= -1;
c++;
}
while (str[c] >= '0' && str[c] <= '9')
{
result = (str[c] - '0') + (result * 10);
c++;
}
return (result * sign);
}
#include <stdio.h>
int main(void)
{
char *s = " ---+--+1234ab567";
printf("%d", ft_atoi(s));
}
`
This line: result = (str[c] - '0') + (result * 10);
Why do we subtract zero and multiply by 10? How its convert ascii to int with this operations?
Thanks...
Some detail before answering your question
Internally everything is a number a char is not an exception.
In C char is a promoted type of integer meaning characters are integer in C. The char which is promoted type of integer are mapped to responding ASCII Value.
For example:
Capital Letter Range
65 => 'A' to 90 => 'Z'
Small Letter Range
97 => 'a' to 122 => 'z'
Number Range
48 => '0' to 57 => '9'
To answer your question
The ASCII CHARACTER '0' subtracted from any ASCII CHARACTER that is a digit(0-9) results to an actual Integer.
For Example
'9'(57) - '0'(48) = 9 (int)
'8'(56) - '0'(48) = 8 (int)
Remember char are promoted integer in C Read the detail to understand this statement.
And Also the ASCII CHARACTER '0' added to any INTEGER in the range(0-9) results to an ASCII CHARACTER.
For Example
9 + '0'(48) = '9'(57) (char)
8 + '0'(48) = '8' (56)(char)
Please see ASCII table
The ASCII code for '0' is 48 - not zero. Therefore, to convert to decimal you need to subtract 48
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
This is for C programming. I am studying for a midterm and one of the problems on the practice test had me a little confused and was hoping someone could help walk me through the code.
The code to the function is:
int xtoi(char s[])
{
int i;
int result;
i = result = 0;
while (s[i]) {
if (s[i] >= '0' && s[i] <= '9') {
result = result * 16 + s[i++] - '0';
} else if (s[i >= 'a' && s[i] <= 'f') {
result = result * 16 + s[i++] - 'a' + 10;
} else if (s[i] >= 'A' && s[i] <= 'F') {
result = result * 16 + s[i++] - 'A' +10;
}
}
return result;
}
What is the result of the following?
xtoi("1fa")
The answer should be 506, but I have no idea how. It is probably quite simple but this is all relatively new to me, so any help and guidance is much appreciated.
Thanks in advance.
If s[i] is a char from '0' to '9', convert it to the
corresponding int(0 to 9).
If not, if s[i] is a char from 'a' to 'f', convert it to the corresponding int(10 to 16).
If not, if s[i] is a char from 'A' to 'F', convert it to the corresponding int(10 to 16).
If still not, ignore it.
Then all such numbers are added up (following a rule) to generate the hex value represented by s.
Hint concerning the rule: For example, say you want to get a decimal number consists of '4' and '2'. You'll let a temporary result to be 4 first, multiply it by 10, and add 2 to that temp result. This will give you what you want: 4 * 10 + 2 = 42.
Please think about it again, and I promise you can understand it on your own.
BTW, the result of xtoi("1fa") is identical to that of strtol("1fa", NULL, 16)
The function converts hex strings into ints. It is analagous to atoi.
int xtoi(char s[])
{
int i = 0;
int result = 0;
/* while we haven't seen the null terminator */
while (s[i]) {
/* if this char is a digit
* convert this char to an int and then add
* it to the next decimal place in the number.
* Then advance to the next character */
if (s[i] >= '0' && s[i] <= '9')
result = result * 16 + s[i++] - '0';
/* if this character is a hex digit
* convert this char to an int and then add
* it to the next decimal place in the number.
* Then advance to the next character */
else if (s[i] >= 'a' && s[i] <= 'f')
result = result * 16 + s[i++] - 'a' + 10;
/* same as above, except for uppercase hex digits */
else if (s[i] >= 'A' && s[i] <= 'F')
result = result * 16 + s[i++] - 'A' + 10;
}
/* return the converted number */
return result;
}
This program could be rewritten like this
int xtoi(char s[])
{
int i = 0;
int result = 0;
/* while we haven't seen the null terminator */
for (i = 0; s[i]; ++i) {
/* if this char is a digit
* convert this char to an int and then add
* it to the next decimal place in the number. */
if (isdigit(s[i]))
result = result * 16 + (s[i] - '0');
/* if this character is a hex digit
* convert this char to an int and then add
* it to the next decimal place in the number. */
else if (isxdigit(s[i])) {
/* if the hex digit is uppercase, the char to subtract
* from is also uppercase. Otherwise it is lowercase */
char base = isupper(s[i]) ? 'A' : 'a';
result = result * 16 + s[i] - base + 10;
}
}
/* return the converted number */
return result;
}
The output of the new xtoi("1fa"); is correct: 506.
I have a char array say char value []={'0','2','0','c','0','3'};
I want to convert this into a byte array like unsigned char val[]={'02','0c','03'}
This is in an embedded application so i can't use string.h functions. How can i do this?
Sicne you talk about an embedded application I assume that you want to save the numbers as values and not as strings/characters. So if you just want to store your character data as numbers (for example in an integer), you can use sscanf.
This means you could do something like this:
char source_val[] = {'0','A','0','3','B','7'} // Represents the numbers 0x0A, 0x03 and 0xB7
uint8 dest_val[3]; // We want to save 3 numbers
for(int i = 0; i<3; i++)
{
sscanf(&source_val[i*2],"%x%x",&dest_val[i]); // Everytime we read two chars --> %x%x
}
// Now dest_val contains 0x0A, 0x03 and 0xB7
However if you want to store it as a string (like in your example), you can't use unsigned char
since this type is also just 8-Bit long, which means it can only store one character. Displaying 'B3' in a single (unsigned) char does not work.
edit: Ok according to comments, the goal is to save the passed data as a numerical value. Unfortunately the compiler from the opener does not support sscanf which would be the easiest way to do so. Anyhow, since this is (in my opinion) the simplest approach, I will leave this part of the answer at it is and try to add a more custom approach in this edit.
Regarding the data type, it actually doesn't matter if you have uint8. Even though I would advise to use some kind of integer data type, you can also store your data into an unsigned char. The problem here is, that the data you get passed, is a character/letter, that you want to interpret as a numerical value. However, the internal storage of your character differs. You can check the ASCII Table, where you can check the internal values for every character.
For example:
char letter = 'A'; // Internally 0x41
char number = 0x61; // Internally 0x64 - represents the letter 'a'
As you can see there is also a differnce between upper an lower case.
If you do something like this:
int myVal = letter; //
myVal won't represent the value 0xA (decimal 10), it will have the value 0x41.
The fact you can't use sscanf means you need a custom function. So first of all we need a way to conver one letter into an integer:
int charToInt(char letter)
{
int myNumerical;
// First we want to check if its 0-9, A-F, or a-f) --> See ASCII Table
if(letter > 47 && letter < 58)
{
// 0-9
myNumerical = letter-48;
// The Letter "0" is in the ASCII table at position 48 -> meaning if we subtract 48 we get 0 and so on...
}
else if(letter > 64 && letter < 71)
{
// A-F
myNumerical = letter-55
// The Letter "A" (dec 10) is at Pos 65 --> 65-55 = 10 and so on..
}
else if(letter > 96 && letter < 103)
{
// a-f
myNumerical = letter-87
// The Letter "a" (dec 10) is at Pos 97--> 97-87 = 10 and so on...
}
else
{
// Not supported letter...
myNumerical = -1;
}
return myNumerical;
}
Now we have a way to convert every single character into a number. The other problem, is to always append two characters together, but this is rather easy:
int appendNumbers(int higherNibble, int lowerNibble)
{
int myNumber = higherNibble << 4;
myNumber |= lowerNibbler;
return myNumber;
// Example: higherNibble = 0x0A, lowerNibble = 0x03; -> myNumber 0 0xA3
// Of course you have to ensure that the parameters are not bigger than 0x0F
}
Now everything together would be something like this:
char source_val[] = {'0','A','0','3','B','7'} // Represents the numbers 0x0A, 0x03 and 0xB7
int dest_val[3]; // We want to save 3 numbers
int temp_low, temp_high;
for(int i = 0; i<3; i++)
{
temp_high = charToInt(source_val[i*2]);
temp_low = charToInt(source_val[i*2+1]);
dest_val[i] = appendNumbers(temp_high , temp_low);
}
I hope that I understood your problem right, and this helps..
If you have a "proper" array, like value as declared in the question, then you loop over the size of it to get each character. If you're on a system which uses the ASCII alphabet (which is most likely) then you can convert a hexadecimal digit in character form to a decimal value by subtracting '0' for digits (see the linked ASCII table to understand why), and subtracting 'A' or 'a' for letters (make sure no letters are higher than 'F' of course) and add ten.
When you have the value from the first hexadeximal digit, then convert the second hexadecimal digit the same way. Multiply the first value by 16 and add the second value. You now have single byte value corresponding to two hexadecimal digits in character form.
Time for some code examples:
/* Function which converts a hexadecimal digit character to its integer value */
int hex_to_val(const char ch)
{
if (ch >= '0' && ch <= '9')
return ch - '0'; /* Simple ASCII arithmetic */
else if (ch >= 'a' && ch <= 'f')
return 10 + ch - 'a'; /* Because hex-digit a is ten */
else if (ch >= 'A' && ch <= 'F')
return 10 + ch - 'A'; /* Because hex-digit A is ten */
else
return -1; /* Not a valid hexadecimal digit */
}
...
/* Source character array */
char value []={'0','2','0','c','0','3'};
/* Destination "byte" array */
char val[3];
/* `i < sizeof(value)` works because `sizeof(char)` is always 1 */
/* `i += 2` because there is two digits per value */
/* NOTE: This loop can only handle an array of even number of entries */
for (size_t i = 0, j = 0; i < sizeof(value); i += 2, ++j)
{
int digit1 = hex_to_val(value[i]); /* Get value of first digit */
int digit2 = hex_to_val(value[i + 1]); /* Get value of second digit */
if (digit1 == -1 || digit2 == -1)
continue; /* Not a valid hexadecimal digit */
/* The first digit is multiplied with the base */
/* Cast to the destination type */
val[j] = (char) (digit1 * 16 + digit2);
}
for (size_t i = 0; i < 3; ++i)
printf("Hex value %lu = %02x\n", i + 1, val[i]);
The output from the code above is
Hex value 1 = 02
Hex value 2 = 0c
Hex value 3 = 03
A note about the ASCII arithmetic: The ASCII value for the character '0' is 48, and the ASCII value for the character '1' is 49. Therefore '1' - '0' will result in 1.
It's easy with strtol():
#include <stdlib.h>
#include <assert.h>
void parse_bytes(unsigned char *dest, const char *src, size_t n)
{
/** size 3 is important to make sure tmp is \0-terminated and
the initialization guarantees that the array is filled with zeros */
char tmp[3] = "";
while (n--) {
tmp[0] = *src++;
tmp[1] = *src++;
*dest++ = strtol(tmp, NULL, 16);
}
}
int main(void)
{
unsigned char d[3];
parse_bytes(d, "0a1bca", 3);
assert(d[0] == 0x0a);
assert(d[1] == 0x1b);
assert(d[2] == 0xca);
return EXIT_SUCCESS;
}
If that is not available (even though it is NOT from string.h), you could do something like:
int ctohex(char c)
{
if (c >= '0' && c <= '9') {
return c - '0';
}
switch (c) {
case 'a':
case 'A':
return 0xa;
case 'b':
case 'B':
return 0xb;
/**
* and so on
*/
}
return -1;
}
void parse_bytes(unsigned char *dest, const char *src, size_t n)
{
while (n--) {
*dest = ctohex(*src++) * 16;
*dest++ += ctohex(*src++);
}
}
Assuming 8-bit bytes (not actually guaranteed by the C standard, but ubiquitous), the range of `unsigned char` is 0..255, and the range of `signed char` is -128..127. ASCII was developed as a 7-bit code using values in the range 0-127, so the same value can be represented by both `char` types.
For the now discovered task of converting a counted hex-string from ascii to unsigned bytes, here's my take:
unsigned int atob(char a){
register int b;
b = a - '0'; // subtract '0' so '0' goes to 0 .. '9' goes to 9
if (b > 9) b = b - ('A' - '0') + 10; // too high! try 'A'..'F'
if (b > 15) b = b - ('a' - 'A); // too high! try 'a'..'f'
return b;
}
void myfunc(const char *in, int n){
int i;
unsigned char *ba;
ba=malloc(n/2);
for (i=0; i < n; i+=2){
ba[i/2] = (atob(in[i]) << 4) | atob(in[i+1]);
}
// ... do something with ba
}
So I'm hoping to get a little guidance on this one. I have a function that takes a radix(base) and then using getchar() will get the number to convert from the given radix to an integer representation.
The only argument given is the radix number, then getchar() gets the number representation via the command line.
So if I pass
str2int 16
input a number: 3c
It should output (16^1*3) + (16^0*12) = 48 + 12 = 60.
I fully understand the math, and different ways of converting bases, but don't know how to go about coding something up. The math is always MUCH easier than the code, at least to me.
Another way to compute would be:
(702) base 15 = 15*7 + 0 = 105; 15*105 + 2 = 1577
I don't know how to express this in C only using getchar()? Is it possible to do without using the math function?
Keep getting one char at a time until not a digit or no more are needed.
unsigned shparkison(unsigned base) {
unsigned sum = 0;
int ch;
while ((ch = getchar()) != EOF) {
// one could instead look up the toupper(value) in an array "0123...ABC...Z";
// Following assumes ASCII
if (isdigit(ch)) ch -= '0';
else if (islower(ch)) ch -= 'A' - 10;
else if (isupper(ch)) ch -= 'a' - 10;
else {
break; // Not a digit
}
if (ch >= base) {
break; // Digit too high
}
unsigned sum_old = sum;
sum *= base;
sum += ch;
if (sum < sum_old) {
sum = sum_old;
break; // Overflow
}
}
ungetc(ch, stdin);
return sum;
}
My program's goal is to receive from the standard input a text, and a 'number', and to return to the screen the text after shifting of the letters 'number' times (for shift 3, 'a' becomes 'd', 'e' becomes 'g'). It should only shift the lower case letter and should be cyclic (letter 'y' in a shift of 3 should become 'a' again).
I have some bugs, though. If I shift 't' 11 times, it'll come to 'e', but if I shift 't' 12 times, I get space (" "). Why? Here's my code:
3 int main(int argc, char *argv[]) {
4 if (argc != 2) {
5 printf ("Wrong input\n");
6 return 1;
7 }
8 int shift = atoi (argv[1]);
9 int c;
10 while ((c = getchar()) != EOF) {
11 if (c >= 'a' && c <= 'z') {
12 char newch = c + shift;
13 if (newch > 'z') {
14 newch = 'a' + (newch - 'z' - 1);
15 }
16 if (newch < 'a') {
17 newch = 'z' - ('a' - newch - 1);
18 }
19 putchar (newch);
20 }
21 else
22 putchar(c);
23 }
24 return 0;
25 }
Also, when compiling I receive those warnings:
shift_chars.c: In function `main':
shift_chars.c:8: warning: implicit declaration of function `atoi'
shift_chars.c:8: warning: ISO C90 forbids mixed declarations and code
What do those mean?
The first warning means you did not include <stdlib.h>, which is where atoi() is declared.
The second warning means that you declared variables (shift etc) after you had some executable code. C++ allows that; C99 allows that; ISO C 90 (ANSI C 89) did not allow that. In older C, all variables in a block had to be defined before any executable statements.
Also, if you are shifting 3 and translate 'y' to 'a' you have a bug -- it should be 'b' ('z', 'a', 'b').
One of your problems is that the code for 'z' is 122, and adding 11 to 122 wraps you to a negative value if your characters (char type) are signed; you do not have this problem if char is unsigned. You'd probably do best to use an int instead of char while computing the new character value.
You might find it easier to manage if you calculate:
int newch = ((c - 'a') + shift) % 26 + 'a';
The c - 'a' gives you an index into the alphabet: a = 0, b = 1, ... z = 25. Add the shift; take the result modulo 26 to get the offset into the alphabet again; then add the result to 'a' to get the correct letter. Since c - 'a' generates an integer (because all char values are promoted to int), this avoid any overflows in char.
Indeed, you could avoid newch altogether and simply compute:
a = (c - 'a' + shift) % 26 + 'a';
You can then omit the putchar() at line 19, and drop the else, leaving the putchar(c); to output both transformed and untransformed characters.
I would shift the chars this way:
if(c >= 'a' && c <= 'z') {
newchar = (c - 'a' + shift) % 26 + 'a';
}
As for warnings - guys perfectly explained them.
If you look at the ascii table, 't' has the value 116. A char is likely signed on your platform.
So you get 116 + 12 = 128 , however that will be represented using a signed 8 bit value, so the value will be -128. Then you end up calculating newch = 'z' - ('a' - newch - 1);
If you use int newch = c + shift; , you'll not have that problem (until the addition wraps past 2147483648).
shift_chars.c:8: warning: implicit declaration of function 'atoi' says that the compiler has not seen a declaration for the atoi() function. You should #include <stdlib.h> to use atoi
Instead of lines 12 through 18, just do
char newch = (c - 'a' + shift) % 26 + 'a';
try to change
char newch = c + shift;
to
int newch = c + shift;
or, alternatively to unsigned char
My answer include explanation, plus solution:
Your newch has a char datatype. Most machines interpretes char as 1 byte.
That would mean the maximum decimal value for your newch variable is:
11111111 (in binary) == 128 in decimal. That's 0-127.
Now, in your code, when you pressed 't', getchar get this as 116 in decimal. If you add it with 12 (your shift), then the result will be 116+12=128. 128 overflows from the 0-127 range.
The solution? Make your newch datatype able to accept greater range, like:
unsigned char newch = c + shift;
or
int newch = c + shift;
Here's the complete code:
#include <stdio.h>
int main(int argc, char *argv[]) {
if (argc != 2) {
printf ("Wrong input\n");
return 1;
}
int shift = atoi (argv[1]);
int c;
while ((c = getchar()) != EOF) {
if (c >= 'a' && c <= 'z') {
unsigned char newch = c + shift;
if (newch > 'z') {
newch = 'a' + (newch - 'z' - 1);
}
if (newch < 'a') {
newch = 'z' - ('a' - newch - 1);
}
putchar (newch);
}
else
putchar(c);
}
return 0;
}