convert particular array elements as integer value - c

I have declared an array char Buffer[100]="01 05 01 4A 63 41"; now the array looks like this
Buffer[0]='0'
Buffer[1]='1'
Buffer[2]=' '
Buffer[3]='0'
Buffer[4]='5'
i just want to convert these value to int `eg.:
Buffer[0]='0', Buffer[1]='1' to 0x01 (1)
Buffer[0]='0', Buffer[1]='5' to 0x05 (5)
... etc.
atoi()cannot be used since it converts all the Buffer value as integer.
How to convert a particular space delimited value sub-string to an integer?

My first solution works only for integers, and the following one works also for hexadecimal numbers. I wrote down the function which converts string representation of a hexadec. number into a decimal number. Then, as suggested by Jochim Pileborg, I used strtok to parse the given Buffer array.
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int hexToInt(char *tok)
{
int i,out=0, tens=1, digit;
for(i=strlen(tok)-1; i>=0; i--)
{
switch(tok[i])
{
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9': digit=tok[i]-'0';
break;
case 'A': digit=10; break;
case 'B': digit=11; break;
case 'C': digit=12; break;
case 'D': digit=13; break;
case 'E': digit=14; break;
case 'F': digit=15; break;
}
out+=digit*tens;
tens*=16;
}
// printf("hex:%s int:%d ", tok, out);
return out;
}
int main()
{
char Buffer[100]="01 2A 10 15 20 25";
int intarr[100],current=0;
char *tok=malloc(20*sizeof(char));
tok=strtok(Buffer," ");
while(tok!=NULL)
{
intarr[current]=hexToInt(tok);
current++;
tok=strtok(NULL," ");
}
printf("\n");
}

You can treat Buffer as a string (which it is), and use e.g. strtok to "tokenize" the numbers on space boundary. Then use strtol to convert each "token" to a number.
But do note that strtok modifies the string, so if you don't want that you have to make a copy of the original Buffer and work on that copy.
Also note that as the numbers seems to be hexadecimal you can't use atoi because that function only parses decimal numbers. You have to use strtol which can handle any base from 2 to 36.

Consider this:
#include <stdio.h>
int main()
{
char Buffer[100] = "01 05 01 4A 63 41" ;
const char* h = &Buffer[0] ;
int i ;
while( *h != 0 )
{
if( sscanf( h, "%2x", &i ) == 1 )
{
printf( "0x%02X (%d)\n", i, i ) ;
}
h += 3 ;
}
return 0;
}
The output from which is:
0x01 (1)
0x05 (5)
0x01 (1)
0x4A (74)
0x63 (99)
0x41 (65)
I have assumed that all the values are hexadecimal, all two digits, and all separated by a single space (or rather a single non-hex-difgit character), and that the array is nul terminated. If either of these conditions are not true, the code will need modification. For example if the values may be variable length, then the format specifiers need changing, and, you should increment h until a space or nul is found, and if a space is found, increment once more.
You could write similar code using strtol() instead of sscanf() for conversion, but atoi() is specific to decimal strings, so could not be used.
If you are uncomfortable with the pointer arithmetic, then by array indexing the equivalent is:
#include <stdio.h>
int main()
{
char Buffer[100] = "01 05 01 4A 63 41" ;
int c = 0 ;
int i ;
while( *h != 0 )
{
if( sscanf( &Buffer[c], "%2x", &i ) == 1 )
{
printf( "0x%02X (%d)\n", i, i ) ;
}
c += 3 ;
}
return 0;
}
and the strtol() version if you prefer:
#include <stdio.h>
#include <stdlib.h>
int main()
{
char Buffer[100] = "01 05 01 4A 63 41" ;
const char* h = &Buffer[0] ;
while( *h != 0 )
{
int i = strtol( h, 0, 16 ) ;
printf( "0x%02X (%d)\n", i, i ) ;
h += 3 ;
}
return 0;
}

You can use sscanf for this, e.g.:
int intarr[6];
sscanf(Buffer,"%d %d %d %d %d %d",&intarr[0],&intarr[1],&intarr[2],&intarr[3],&intarr[4],&intarr[5]);

You can cast Buffer[i] to int.
Then check its value, which will be in ASCII.
48->0
.
.
57->9
You can even compare the char to its ASCII value without casting
int CharToDigit(char c)
{
if(c>=48 && c<=57) // or as suggested if(c>='0' && c <='9')
return (int)c - 48; // subtract the ascii of 0
return -1; // not digit
}
For digits from A to F you'll have to subtract 55 from uppercase letters (65-10, 65 is ascii of A)
Then loop through the chars in Buffer sending them to the function: CharToDigit(Buffer[i]) and check the returned int.

Related

C Program to convert binary numbers to Hex can't convert more than two binary numbers if they equal hex letters

For example if I type in 101010101010 it should equal AAA but it doesn't work. It only returns letters if it is less than two letters at a time. For example it works if I type in, "10101010". (It returns AA). Please help?
#include <stdio.h>
#include <math.h>
#include <string.h>
void binary_hex(int n, char hex[]);
int hex_binary(char hex[]);
int main()
{
printf("Enter binary number: ");
scanf("%d",&n);
binary_hex(n,hex);
printf("Hexadecimal number: %s",hex);
}
void binary_hex(int n, char hex[]) /* Function to convert binary to hexadecimal. */
{
int i=0,decimal=0, rem;
while (n!=0)
{
decimal += (n%10)*pow(2,i);
n/=10;
++i;
}
/* At this point, variable decimal contains binary number in decimal format. */
i=0;
while (decimal!=0)
{
rem=decimal%16;
switch(rem)
{
case 10:
hex[i]='A';
break;
case 11:
hex[i]='B';
break;
case 12:
hex[i]='C';
break;
case 13:
hex[i]='D';
break;
case 14:
hex[i]='E';
break;
case 15:
hex[i]='F';
break;
default:
hex[i]=rem+'0';
break;
}
++i;
decimal/=16;
}
hex[i]='\0';
strrev(hex); /* Function to reverse string. */
}
You've not shown a complete program - n is not declared in any scope in main. Assuming int n, your first problem is here:
printf("Enter binary number: ");
scanf("%d",&n);
You're reading the string of ones and zeros in as a base 10 (decimal) integer. Instead, you should write a function that takes a const char * and iterates over each character, verifying it is either a 1 or 0, interpreting each one's value, and accumulating the total. Hint: It may be easier to work in right to left order.
int parse_binary(const char *str)
{
int total = 0;
while (...) {
total += ...
}
return total;
}
Another hint: Don't re-invent the wheel. Certainly, someone has wanted to parse binary numbers in C before you, no? Check out strtoul - namely the description of its third parameter.
Note: Both things I've mentioned so far limit your binary values to 32 bits (or 64, depending on your data type choices). If you don't need to actually use your integer values, any only convert a string of 1s and 0s to a string of hexadecimal values (of arbitrary length), then you can break up the problem into even simpler steps.
The reason we really like to use hexadecimal is that each character in a hex value represents exactly one nibble, which is exactly four bits. That means every group of four 1s or 0s corresponds to exactly one hexadecimal character. Assuming your input is always a multiple of 4 characters in length, you can easily process an arbitrarily long string.
D E A D B E E F
1101 1110 1010 1101 1011 1110 1110 1111
A very beginner friendly solution. This will work for big binary numbers/string.
#include <stdio.h>
#include <string.h>
int main()
{
int hexConstant[] = {0, 1, 10, 11, 100, 101, 110, 111, 1000, 1001, 1010, 1011, 1100, 1101, 1110, 1111};
char hex[20000];
char binary[20000];
int index, i, digit;
printf("Enter binary string: ");
scanf("%s", binary);
index = 0;
int len = strlen(binary) ;
for(int j = len-1; j>=0; j-=4) {
if(j-3>=0) digit = (binary[j-3]-'0')*1000 + (binary[j-2]-'0')*100 + (binary[j-1]-'0') * 10 + (binary[j]-'0');
else if(j-3>=0) digit = (binary[j-2]-'0')*100 + (binary[j-1]-'0') * 10 + (binary[j]-'0');
else if(j-1>=0) digit = (binary[j-1]-'0') * 10 + (binary[j]-'0');
else digit = (binary[j]-'0');
for(i=0; i<16; i++)
{
if(hexConstant[i] == digit)
{
if(i<10)
{
hex[index] = (char)(i + 48);
}
else
{
hex[index] = (char)((i-10) + 65);
}
index++;
break;
}
}
}
hex[index] = '\0';
strrev(hex);
printf("Hexadecimal number = %s", hex);
return 0;
}

How to get a character ASCII value in a integer variable?

I'm new in C and I couldnt find the answer to my question in the forum.
The point is, I need to get a value of deck cards from the user. So it can spread from 2 to 10 and also be 'J', 'Q', 'K' or 'A'. That means it can be a integer or a character.
I'm trying to put it in an integer variable called "_val1". This work for any number from 0 to 10. I expected that if I typed a letter, _val1 would get the ASCII value of that character (wich I could use later for my pourposes). But instead _val1 geta value '0' and the letter is automatically passed to my next variable call (wich is _naipe1).
How can I solve that?
That means, how cam I use scanf to get either a integer value or the ASCII value of a character?
short int _val1, _val2;
char _naipe1, _naipe2;
printf("Qual a 1ยช carta?\n Valor:");
scanf(" %hd", &_val1);
printf("Valor 1 = %hd \n", _val1 );
printf(" Naipe:");
scanf(" %c", &_naipe1);
well, if I were you I'd try to simplify the problem:
get the ASCII value of the card representation from '2' to '9' and 'J','Q','K','A' ; there you can simply use a scanf("%c") or even better a getchar() operation.
then either you keep using the ASCII representation of your cards throughout your algorithm, or you can translate it using a mapping function such as:
int map(char card) {
switch (card) {
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
return card-'0';
case 'A':
return 1;
case 'J':
return 10;
case 'Q':
return 11;
case 'K':
return 12;
}
}
First, there are 52 cards to a typical poker deck, These are split into 4 suits: hearts, diamonds, spades and clubs. This kind of suggests that user input will be something like: 10s, Ad, 3c, etc (meaning 10 of spades, Ace of diamonds and 3 of clubs) So, not only must you determine the value of the individual card, you also must determine the suit.
This will not solve all of those requirements, but it will at least answer your most direct question, how to read an int or a char using scanf().
This will demonstrate that:
#include <stdio.h>
int main(int argc, char** argv)
{
int aNumber;
char aChar;
printf("\nEnter a number:");
scanf("%d", &aNumber);
printf("\nEnter a character:");
scanf("%c", &aChar);
printf("\nThe number entered is %d\n", aNumber);
printf("\nThe character entered is %c\n", aChar);
return 0;
}
You can also simply have all the values in a string such as
char cards[]={"Ad Js 10c 2c Qh"};
Then parse it using strtok(), then test each token for its ascii content, using functions like isdigit() or isalpha()
Note: you will have to map each card to a value to keep them straight, something like this abbreviated enum may work:
enum {
AD = 1, //start enum values at 1 for the diamonds suit
2D,
3D,
...//fill in rest of cards here
JC,
QC,
KC, // last card == 52, with the clubs suit
};
The reason your output from _val1 is 0 when entering a letter lies in the fact that you've declared _val1 as an short int. You should be using a char. Then you can assign and compare their ascii values.
char card;
int value;
scanf("%c", card);
if(card < 58 && card > 49)
value = card - 48;
else {
switch(card) {
case 'a': value = 1;
case '0': value = 10;
case 'j': value = 11;
case 'q': value = 12;
case 'k': value = 13;
default: printf("Must enter 0-9 (0 for 10 card), or a, j, q, k\n");
}
}
To read in "A", "2", "3", ... "10", "J",... "K", use fgetc() and strchr().
#include <ctype.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
short GetCardRank(void) {
static const char rank[] = "A234567891JQK";
short val = -1;
int ch = fgetc(stdin);
while (isspace(ch)) ch = fgetc(stdin); // Skip leading white-space
char *p = strchr(rank, toupper(ch)); // Use toupper() to make case insensitive
if (ch != EOF && p != NULL && *p != '\0') {
short val = (short) (p - rank + 1);
if (val != 10) return val;
ch = fgetc(stdin);
if (ch == '0') return val;
val = 1; // Allow a lone '1' to act like an 'A'
}
ungetc(ch, stdin); // Put back unused char for next IO function
return val;
}
I'm trying to put it in an integer variable called "_val1". This work for any number from 0 to 10. I expected that if I typed a letter, _val1 would get the ASCII value of that character (wich I could use later for my pourposes). But instead _val1 geta value '0' and the letter is automatically passed to my next variable call (wich is _naipe1)
The problem is that the %d conversion specifier only recognizes strings of decimal digits (with an optional leading + or -) and will stop reading at the first non-digit character; if you type in something other than a digit, then the input operation will fail and that character will be left in the input stream.
Your best bet is to read your input as text, then convert it to a numerical value manually, something like the following:
#include <ctype.h>
#include <stdlib.h>
/**
* Reads a card's face value (2-10,J,Q,K,A) from standard input
* Returns 0 on error
*/
short get_card_value( void )
{
char buf[4]; // large enough to hold a 2-digit string plus newline plus 0 terminator
short val = 0;
if ( fgets( buf, sizeof buf, stdin ) != NULL )
{
char *chk;
short tmp = (short) strtol( buf, &chk, 0 );
if ( isspace( *chk ) || *chk == 0 )
{
if ( tmp >= 2 && tmp <= 10 )
val = tmp;
}
else
{
switch( tolower( *chk ) )
{
case 'j': val = 11; break;
case 'q': val = 12; break;
case 'k': val = 13; break;
case 'a': val = 11; break;
default: break;
}
}
}
// else read error
return val;
}
You'd call this as
val1 = get_card_value();
if ( val1 == 0 )
// error on input
This code doesn't do any length checking on input, so if you enter a card value of 1234567890, that won't be handled gracefully.
Don't use leading underscores in your variable names; names with leading underscores are reserved for the implementation.

Function that counts chars in a string in C

I am new a C. I would like to get help to finish my function.
The mission is:
Write a function that accepts a string maximum length of 256 characters containing characters from 'a' to 'z'.
The function to print the number of occurrences of each character.
For example: input abba output will be:
a = 2 b = 2 c = 0 d = 0 .... z = 0
Do not use if during any function.
I would like to get your help to finish this program please.
This is my code
#include "stdlib.h"
#include "conio.h"
#include "stdio.h"
#include "string.h"
#define size 256
void repeat(char *str);
void main()
{
char str[size];
printf("Please enter a string:\n");
flushall;
gets(str);
repeat(str);
system("pause");
return ;
}
void repeat(char *str)
{
char temp=strlen(str);
int i, count=0;
do
{
for (i=0; i<temp ; i++)
{
count += (*str == str[temp-i]);
}
printf("Char %c appears %d times\n ",*str,count);
count=0;
}
while(*(str++));
}
Please enter a string:
abbba
Char a appears 1 times
Char b appears 2 times
Char b appears 1 times
Char b appears 0 times
Char a appears 0 times
Char appears 0 times
Press any key to continue . . .
this is the output!
I would like to do it in the same building i did.
and should be like
Char a appears 2 times
Chars b appears 3 times
You make a stipulation about not using if. This satisfies that restriction.
#include <stdio.h>
int main(void) {
int i, c;
int counts[256] = { 0 };
const char lower[] = "abcdefghijklmnopqrstuvwxyz";
while ((c = getchar()) != EOF) {
counts[c] += 1;
}
for (i = 0; lower[i]; ++i) {
c = lower[i];
printf("Char %c appears %d times.\n", c, counts[c]);
}
return 0;
}
The problem with your attempt is that you do not track any state to remember which characters you have already printed information about. It also fails to include the character under consideration as part of the count. It also makes multiple passes over the string to collect count information about each character, but that doesn't affect correctness, just performance. If you can somehow remember which character you have already printed out information for, so that you don't do it again when the same character appears later in the string, your method should print out the counts for the characters that appear. Afterwards, you would need to print out zero counts for the characters that did not appear at all. If the outputs need to be in alphabetical order, then you need to make sure you take care of that as well.
One way to track the information properly and to allow your output to be printed in alphabetical order is to maintain counts for each character in an array. After making a pass over the string and incrementing the count associated with each found character, you can iterate over the count array, and print out the counts.
The following program is for zubergu:
#include <stdio.h>
#include <string.h>
int main (void) {
int i, c;
int counts[26] = { 0 };
const char lower[] = "abcdefghijklmnopqrstuvwxyz";
while ((c = getchar()) != EOF) {
switch (c) {
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
case 'v': case 'w': case 'x': case 'y': case 'z':
counts[strchr(lower, c) - lower] += 1;
break;
default:
break;
}
}
for (i = 0; lower[i]; ++i) {
printf("Char %c appears %d times.\n", lower[i], counts[i]);
}
return 0;
}
It might be one of the ugliest solutions, but also the simplest:
while(*str!='\0')
{
switch(tolower(*str))
{
case 'a': a_count++;break;
case 'b': b_count++;break;
.
.
.
}
str++;
}
It checks if str points to valid letter, then turns it to lower, so it's not case sensitive('A' will be same as 'a' character). No 'if' used and will work with every length char array terminated with '\0' char.
EDIT I have edited the program to follow the requirements of #SagiBinder.
(In my old version, I used an if sentence that checked if the character is in the set 'a'...'z').
The type of temp must be "bigger", that is, something different to char.
Try int, instead.
The algorithm would be this (some details of your program are not repeated here):
int temp = strlen(str);
int i, j;
unsigned char c;
int ch[UCHAR_MAX]; // The macro CHAR_MAX needs the header <limits.h>
for (i = 1; i <= UCHAR_MAX; i++)
ch[i] = 0;
for (j=0; j<temp ; j++) {
c = (unsigned char)(str[j]);
ch[c]++;
}
for (c = 'a'; c <= 'z'; c++)
printf("%c == %d\n", c, ch[c]);
The variable temp holds the length of the string str.
The macro UCHAR_MAX (existing in the header <limits.h>, that you have to #include at the beginning of the program). It is the max. value that holds in a unsigned char.
The array ch[] contains a component for each possible value in the range of the type unsigned char. The intent is that, for some character c, the element ch[c] is the amount of times that c is in str.
I have used unsigned char in order to ensures that the index c of the array ch[] when writting ch[c] is a non-negative integer value, because an array cannot have negative indexes.
The 2nd for goes through the string str. In the step number j, the j-th character of the string str is taken.
This character is a value of type char.
Since one cannot be sure that char have not negative values, I have converted it to (unsigned char) with an explicit cast.
This value is held in the variable c.
The value of c has the (unsigned char version of the) j-th character in str,
so we are going to count it.
How?
Well, we access the array of counters: ch[] with index c, and increment its value in 1:
ch[c]++;
After the for is finished, we have in the array ch[] the information we want.
Finally, we check for the characters from 'a' to 'z'.
(For this, we have supposed that the character encodings in our system follow the convention that the letters have contiguous values).
The 3rd for goes from 'a' to 'z', and the values of the letter (the variable c that controls the for) and the counting of this letter, that is, ch[c].
Moreover: to show the count of any character, you need a re-cast to char, in this way:
printf("%c: %d\n", (char)c, ch[c]);
But this is not necessary with the letters 'a' to 'z', because they belong to the basic execution character set which means that their values are non-negative and equal to their unsigned char counterparts. So, in this case, it is enough to write:
printf("%c: %d\n", c, ch[c]);
EDIT 2: I will use the idea in the answer of #jxh to improve my code.
Since it cannot be guaranted that the encodings of letters 'a' to 'z' are in contiguous order, we can use a string holding the letters:
char letters[] = "abcdefghijklmnopqrstuvwxyz";
The "last" element is, by C convention, a \0 character held after the element 'z'.
Now, we can show the letter counting by changing the 3rd `for` in this way:
for (i = 0; letter[i] != '\0'; i++)
printf("%c == %d\n", letter[i], ch[letter[i]]);
This is equivalent to write:
for (i = 0; letter[i] != '\0'; i++) {
c = letter[i];
printf("%c == %d\n", c, ch[c]);
}
Optimized solution. complexity O(N), N - Input String length.
your void repeat function will be like this,
void repeat(char *str)
{
int temp=strlen(str);// use int here
int i, count=0;
int charCount[26] = {0};
#if 0
//your logic, traverses the string (n*n) time, n - input string length.
do
{
for (i=0; i<temp ; i++)
{
count += (*str == str[temp-i]);
}
printf("Char %c appears %d times\n ",*str,count);
count=0;
}
while(*(str++));
#endif
#if 1
// This logic traverses string once only. n time, n - input string length.
for (i=0; i<temp ; i++)
{
charCount[str[i]%'a']++;
}
for (i=0; i<26 ; i++)
{
printf("%c appears : %d times \n", 'a'+i, charCount[i]);
}
#endif
}
[EDIT]
Here
charCount[str[i]%'a']++; // 'a' is used a its ASCII Value.
You can use it as
charCount[str[i]%97]++;
If you wan to count lower case letter and upper case letter both.
use it like this
if(str[i] >= 'a' && str[i] <= 'z'){
iMap = str[i]%97; // 97 is ASCII Value of 'a'
charCount[iMap]++;
}else if(str[i] >= 'A' && str[i] <= 'Z'){
iMap = str[i]%65; // 65 is ASCII Value of 'A'
charCount[iMap]++;
}
//iMpa is a integer (int iMap;), used for better undersanding.
i = 0;
while (s[i] !=0)
if (( s[i] >= 'a' && s[i] <= 'z') || (s[i] <= 'A' && s[i] >= 'Z'))
{
letters++;
i++;
}
else
if (( s[i] >= '!' && s[i] <= ')'))
{
other++;
}
else
if (( s[i] >= '0' && s[i] <= '9'))
{
numbers++;
}
total = letters + numbers + other;

How to split a char* to integer tables in C

I have a char* like this "1 10 14 16"
I want to split it to integer array like 1,10,14,16...
how i do that?
I suggest using strtol in a loop, using explicitly its endptr argument, something like:
char* pc = input_string;
char* end = NULL;
while (*pc) {
long l = strtol (pc, &end, 0);
if (end == pc) break;
do_something_useful_with_the_number (l);
pc = end;
}
if you want to accumulate all the numbers in an array, replace do_something_useful_with_the_number (l); with code growing that array (probably using malloc and/or realloc ...)
I would use strtok() like this:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main() {
char string[] = "1 10 14 16",
*next = NULL;
int number[10] = {0},
noOfNumbers = 0,
i = 0;
next = strtok(string, " "); /* first call must have the string and delimiters */
while ( next != NULL ) {
number[noOfNumbers++] = atoi(next);
next = strtok(NULL, " "); /* second call only the delimiters */
}
for ( i = 0; i < noOfNumbers; i++ ) {
printf("number[%d] = %d\n", i, number[i]);
}
return 0;
}
How you ensure the array of ints is big enough is left to you.
Use strtok to separate the numbers and then use atoi on each of them to convert them to integers.
http://www.elook.org/programming/c/strtok.html
int output[4];
char *input_string = "1 10 14 16";
sscanf(input_string, "%d %d %d %d", &output[0], &output[1], &output[2], &output[3]);
printf(" OUTPUT : %d %d %d %d\n", output[0], output[1], output[2], output[3]);
Above code should work
Regards
1 you will have to a strtok to get one number string at a time.
2 Then you have todo atoi to convert a number string into an int.
This needs to be done till the loop condition of strtok returns a valid string
#include <stdio.h>
///i is count *input_string[] times
///j is count temp[] times
int main() {
int i,j=0,num=0,*ptr,output;
char temp[9]={'\0'};
char *input_string[] = {"1 10 14 16 20 31 34 67 23 45 23"};
for(i=0;*(*(input_string+0)+i)!='\0';)
{
switch(*(*(input_string+0)+i))
{
case ' ':i++;break;
case '1':case '2':case '3':
case '4':case '5':case '6':
case '7':case '8':case '9':
case '0':
j=0;
while(*(*(input_string+0)+i) != ' ' || j>9 )
{
temp[j]=*(*(input_string+0)+i);
i++;j++;
}
j++;
temp[j]='\0';
output=atoi(temp);
ptr=malloc( sizeof(int) );
ptr=&output;
printf("%d ",*ptr);
break;
}
}
return 0;
}
I made small modifications.I updated the malloc (); function.May I ask whether the condition?Thank you!
#include <stdio.h>
///i is count *input_string[] times
///j is count temp[] times
///num is count output[] times
int main() {
int i,j=0,num=0;
int output[4];
char temp[9]={'\0'};
char *input_string[] = {"1 10 14 16"};
for(i=0;*(*(input_string+0)+i)!='\0';)
{
switch(*(*(input_string+0)+i))
{
case ' ':i++;break;
case '1':case '2':case '3':
case '4':case '5':case '6':
case '7':case '8':case '9':
case '0':
j=0;
while(*(*(input_string+0)+i) != ' ' || j>9 )
{
temp[j]=*(*(input_string+0)+i);
i++;j++;
}
j++;
temp[j]='\0';
output[num]=atoi(temp);
num++;
break;
}
}
for(i=0;i<4;i++)///print number
printf("%d ",output[i]);
return 0;
}
///*(*(input_string+0)+i) you can see is e.g char input_string[][];

How to turn a hex string into an unsigned char array?

For example, I have a cstring "E8 48 D8 FF FF 8B 0D" (including spaces) which needs to be converted into the equivalent unsigned char array {0xE8,0x48,0xD8,0xFF,0xFF,0x8B,0x0D}. What's an efficient way to do this? Thanks!
EDIT: I can't use the std library... so consider this a C question. I'm sorry!
This answers the original question, which asked for a C++ solution.
You can use an istringstream with the hex manipulator:
std::string hex_chars("E8 48 D8 FF FF 8B 0D");
std::istringstream hex_chars_stream(hex_chars);
std::vector<unsigned char> bytes;
unsigned int c;
while (hex_chars_stream >> std::hex >> c)
{
bytes.push_back(c);
}
Note that c must be an int (or long, or some other integer type), not a char; if it is a char (or unsigned char), the wrong >> overload will be called and individual characters will be extracted from the string, not hexadecimal integer strings.
Additional error checking to ensure that the extracted value fits within a char would be a good idea.
You'll never convince me that this operation is a performance bottleneck.
The efficient way is to make good use of your time by using the standard C library:
static unsigned char gethex(const char *s, char **endptr) {
assert(s);
while (isspace(*s)) s++;
assert(*s);
return strtoul(s, endptr, 16);
}
unsigned char *convert(const char *s, int *length) {
unsigned char *answer = malloc((strlen(s) + 1) / 3);
unsigned char *p;
for (p = answer; *s; p++)
*p = gethex(s, (char **)&s);
*length = p - answer;
return answer;
}
Compiled and tested. Works on your example.
Iterate through all the characters.
If you have a hex digit, the number is (ch >= 'A')? (ch - 'A' + 10): (ch - '0').
Left shift your accumulator by four bits and add (or OR) in the new digit.
If you have a space, and the previous character was not a space, then append your current accumulator value to the array and reset the accumulator back to zero.
If you know the length of the string to be parsed beforehand (e.g. you are reading something from /proc) you can use sscanf with the 'hh' type modifier, which specifies that the next conversion is one of diouxX and the pointer to store it will be either signed char or unsigned char.
// example: ipv6 address as seen in /proc/net/if_inet6:
char myString[] = "fe80000000000000020c29fffe01bafb";
unsigned char addressBytes[16];
sscanf(myString, "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx
%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx", &addressBytes[0],
&addressBytes[1], &addressBytes[2], &addressBytes[3], &addressBytes[4],
&addressBytes[5], &addressBytes[6], &addressBytes[7], &addressBytes[8],
&addressBytes[9], &addressBytes[10], addressBytes[11],&addressBytes[12],
&addressBytes[13], &addressBytes[14], &addressBytes[15]);
int i;
for (i = 0; i < 16; i++){
printf("addressBytes[%d] = %02x\n", i, addressBytes[i]);
}
Output:
addressBytes[0] = fe
addressBytes[1] = 80
addressBytes[2] = 00
addressBytes[3] = 00
addressBytes[4] = 00
addressBytes[5] = 00
addressBytes[6] = 00
addressBytes[7] = 00
addressBytes[8] = 02
addressBytes[9] = 0c
addressBytes[10] = 29
addressBytes[11] = ff
addressBytes[12] = fe
addressBytes[13] = 01
addressBytes[14] = ba
addressBytes[15] = fb
use the "old" sscanf() function:
string s_hex = "E8 48 D8 FF FF 8B 0D"; // source string
char *a_Char = new char( s_hex.length()/3 +1 ); // output char array
for( unsigned i = 0, uchr ; i < s_hex.length() ; i += 3 ) {
sscanf( s_hex.c_str()+ i, "%2x", &uchr ); // conversion
a_Char[i/3] = uchr; // save as char
}
delete a_Char;
For a pure C implementation I think you can persuade sscanf(3) to do what you what. I believe this should be portable (including the slightly dodgy type coercion to appease the compiler) so long as your input string is only ever going to contain two-character hex values.
#include <stdio.h>
#include <stdlib.h>
char hex[] = "E8 48 D8 FF FF 8B 0D";
char *p;
int cnt = (strlen(hex) + 1) / 3; // Whether or not there's a trailing space
unsigned char *result = (unsigned char *)malloc(cnt), *r;
unsigned char c;
for (p = hex, r = result; *p; p += 3) {
if (sscanf(p, "%02X", (unsigned int *)&c) != 1) {
break; // Didn't parse as expected
}
*r++ = c;
}
The old C way, do it by hand ;-) (there is many shorter ways, but I'm not golfing, I'm going for run-time).
enum { NBBYTES = 7 };
char res[NBBYTES+1];
const char * c = "E8 48 D8 FF FF 8B 0D";
const char * p = c;
int i = 0;
for (i = 0; i < NBBYTES; i++){
switch (*p){
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
res[i] = *p - '0';
break;
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
res[i] = *p - 'A' + 10;
break;
default:
// parse error, throw exception
;
}
p++;
switch (*p){
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
res[i] = res[i]*16 + *p - '0';
break;
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
res[i] = res[i]*16 + *p - 'A' + 10;
break;
default:
// parse error, throw exception
;
}
p++;
if (*p == 0) { continue; }
if (*p == ' ') { p++; continue; }
// parse error, throw exception
}
// let's show the result, C style IO, just cout if you want C++
for (i = 0 ; i < 7; i++){
printf("%2.2x ", 0xFF & res[i]);
}
printf("\n");
Now another one that allow for any number of digit between numbers, any number of spaces to separate them, including leading or trailing spaces (Ben's specs):
#include <stdio.h>
#include <stdlib.h>
int main(){
enum { NBBYTES = 7 };
char res[NBBYTES];
const char * c = "E8 48 D8 FF FF 8B 0D";
const char * p = c;
int i = -1;
res[i] = 0;
char ch = ' ';
while (ch && i < NBBYTES){
switch (ch){
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
ch -= '0' + 10 - 'A';
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
ch -= 'A' - 10;
res[i] = res[i]*16 + ch;
break;
case ' ':
if (*p != ' ') {
if (i == NBBYTES-1){
printf("parse error, throw exception\n");
exit(-1);
}
res[++i] = 0;
}
break;
case 0:
break;
default:
printf("parse error, throw exception\n");
exit(-1);
}
ch = *(p++);
}
if (i != NBBYTES-1){
printf("parse error, throw exception\n");
exit(-1);
}
for (i = 0 ; i < 7; i++){
printf("%2.2x ", 0xFF & res[i]);
}
printf("\n");
}
No, it's not really obfuscated... but well, it looks like it is.

Resources