Convert a string of hexadecimal digits into integer - c

I am trying to implement the htoi(s) [Dennis Ritchie chapter2 exercise 2-3 Q] which converts a string of hexadecimal digits, into its equivalent integer, can anyone help me out in the logic of this program, i dont need the code, i just need the logic for implementing it. I am not able to get the correct logic

Let's take a step back:
How would you implement a function that accepts a single hex digit and returns it's decimal equivalent?
In other words, how would you write this function:
unsigned int hextodec(char c)
{
... your code here
}
Hint: for decimal digits what happens when you calculate c -'0'?
Once you have this function it should be fairly easy to use it to calculate the conversion of longer hex strings.
Hint: 0xF is 15 and 0x10 is 16

Use the strtol function with base 16.
About this way:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
int xstrtol16(const char *s)
{
errno = 0;
char *endp = NULL;
int result = strtol(s, &endp, 16);
if (*charp || errno) {
fprintf(stderr, "Failed to convert...\n");
exit(1);
}
return result;
}

Think about what a printable number (in any base) is. Basically a list of symbols which represent simple numeric values (0...base-1), and associated "weights" of their digit positions. For decimal the symbols are "0123456789" and the weights are 1, 10 , 100, 1000...
You convert the printable number into "integer" by finding the corresponding numeric value of each symbol, multiplying it times the weight for that digit position, and summing those products together. There are tricks to doing this efficiently, but a straight-forward "dumb" implementation can get the job done perfectly well.
Hex is slightly complicated because there are two runs of symbols -- 0-9 and A-F -- and it's sometimes desired to accept both upper-case and lower-case letters. There are again tricks to handling this, but doing it in a straight-forward fashion (compare each character to the limits of each run and decide which one it fits) is perfectly fine (and more general than other approaches). You can also even use a index op, where you simply find the character's index into "0123456789ABCDEF" -- inefficient but simple.

Related

How to check whether a hexadecimal number(%x) starts with a certain number or not in C?

I'm working on an operating system related project now and there is one step which requires to check whether a hexadecimal number starts with 3 or not, using C.
Currently my idea is to convert that hexadecimal number into a string and check the initial character but just cannot find out any documentation for doing that. Anybody has any idea? Maybe just a hint.
There are lots of methods to convert a number to a hex string (sprintf comes to mind; How can I convert an integer to a hexadecimal string in C? list a few more) – but, why should you?
A full hex number is formed by converting each nibble (4 bits) to a hexadecimal 'digit'. To get just the first, you can divide your value by 16 until you have reached the final (= 'first', in the left-to-right notation common for both decimal and hexadecimal values) digit. If that's a 3 you are done.
Assuming value is an unsigned number:
while (value > 15)
value >>= 4;
and then check if value == 3.
Your idea is not bad, you can use sprintf, it functions like printf/fprintf but instead of printing
on screen (or to be more precise: writing into a FILE* buffer), it stores the contents in a char buffer.
char value[16]; // more than enough space for 4 byte values
int reg = 0x3eef;
sprintf(value, "%x", reg);
if(value[0] == '3')
printf("The hexadecimal number 0x%s starts with a 3.\n", value);

Why is printf producing strange output in my simple script?

I am an intermediate Python programmer, but I am trying to learn C. It is an extremely frustrating experience so far.
Why does this simple code...
#include <stdio.h>
#include <string.h>
char name[15] = "George Lopez"; /* string representing your name */
char birthday[6] = "01-30-92"; /* string representing your bday */
int phone_number; /* declair int representing phone number */
int main() {
phone_number = 2222223333; /* int representing your phone number */
printf("You said your name was: %s\n", name);
printf("And your birthday is %s?\n", birthday);
printf("And, so I can call you, your number is %d\n", phone_number);
return(0); /* exit program normally */
}
produce this output when the phone number is 2222223333:
You said your name was: George Lopez
And your birthday is 01-30-92?
And, so I can call you, your number is -2072743963
This output when the phone number is 9992223333:
error: 4_1_myinfo.c:16:3: warning: overflow in implicit constant conversion [-Woverflow]
phonenumber = 9992223333;
And this output when the phone number is 1112223333:
You said your name was: George Lopez
And your birthday is 01-30-92?
And, so I can call you, your number is 1112223333
I suspect this has to do with how C deals with integers. Perhaps, ints in C have a smaller maximum length than ints in python and this is resulting in wanky output?
You have a couple of major issues here.
First, when using C-strings, avoid defining the size of the buffer if you can, like so:
char name[] = "George Lopez"; /* string representing your name */
char birthday[] = "01-30-92"; /* string representing your bday */
If you MUST pre-defined the maximum string length, use a common limit, like so:
#define MAX_STR_LEN 256
char name[MAX_STR_LEN] = "George Lopez"; /* string representing your name */
char birthday[MAX_STR_LEN] = "01-30-92"; /* string representing your bday */
If you don't plan on modifying them in the future, make them const like so:
const char* name = "George Lopez"; /* string representing your name */
const char* birthday = "01-30-92"; /* string representing your bday */
In your case, you defined a character array that could only hold 6 characters, but tried to stuff 9 characters in it "01-30-92", plus the trailing \0 character included automatically. Big mistake.
The second major issue is that you are attempting to fit an integer literal into a data type which can not hold it. In C, the maximum signed 32-bit value, 2,147,483,647, is defined as INT_MAX in <limits.h>. You should make your code like so:
long long int phone_number = 2222222222L;
Notice the trailing numeric literal suffix, L? That's to allow your code to compile, and using a long long int is necessary to create a variable that can actually store the value itself.
Finally, you should consider using strings to hold the phone number. You aren't doing any algebraic/mathematical manipulations on it, so there's no need to use an integral data type to represent it.
Code Listing (Modified)
#include <stdio.h>
#include <string.h>
char name[] = "George Lopez"; /* string representing your name */
char birthday[] = "01-30-92"; /* string representing your bday */
long long int phone_number; /* declair int representing phone number */
int main() {
phone_number = 2222223333L; /* int representing your phone number */
printf("You said your name was: %s\n", name);
printf("And your birthday is %s?\n", birthday);
printf("And, so I can call you, your number is %lld\n", phone_number);
return(0); /* exit program normally */
}
Sample Output
You said your name was: George Lopez
And your birthday is 01-30-92?
And, so I can call you, your number is 2222223333
I think the better way to deal with phone numbers is to consider them as a string. You'll need a string type for "formatting" your outputs and also to verify that a phone number follow a certain "regular expression" when considering user inputs.
In C all datatypes have a fixed size. Typically an int is a 32 bit value (but it doesn't have to be) so it will have a maximum value of 2,147,483,647.
Your value, 9,992,223,333 exceeds this value, which it why you are getting a warning. You need to use a bigger datatype like a 64 bit number. This will typically either be a long long if you're on Windows, or a long if you're on Linux.
To understand why this is happening, you need to understand how the numbers are represented in memory. I will try to give you a glimpse of the basic way they work and some further references in case you are interested. As the computer understands just 0 and 1, base 2 is the obvious choice. But there is a problem with representing negative numbers. There are some representations, like the sign-magnitude representation (basically, have a bit that represents the sign - if it is set, the number is negative), that are very simple. The problem is that such representations have 2 ways of representing 0: +0 and -0. So, a clever representation, called two's complement is used. For a binary number abcd (where a, b, c, d represent its bits), the base 10 value is a*2^3+b*2^2+c*2^1+d*2^0. If this number was a 2's complement 4-bit representation, its base 10 value would be -a*2^3+b*2^2+c*2^1+d*2^0. So, in two's complement, the first bit has a negative weight. In a 4-bit two's complement representation, if you have 0111 (decimal 7) and you try to add 1, you will get 1000, which is -8. This is called an overflow. Overflow arises just when adding numbers with the same sign and obtaining a result of different sign (adding 2 positive numbers results a negative number or adding 2 negative numbers results a positive number).
In your program, something similar happens. The only difference is that int has 32 bits, not 4.
Further references:
http://en.wikipedia.org/wiki/Binary_number
http://en.wikipedia.org/wiki/Signed_number_representations
The range of a signed 32-bit integer is [-2147483648, 2147483647]. You try to represent your phone number as a signed integer.
a. When phone num is 1112223333, it's less than the max 2147483647, so you get theright output.
b. 2222223333 is greater than the max 2147483647, but can still be represented as a 32-bit number, you get the 2's complement number which is -2072743963
c. 9992223333 cannot be represented by a 32-bit number, i.e. it's even bigger than (2^32 - 1), that's why you such error.

Convert Int to Hexdecimal without using 'printf' (C Programming)

Is it possible to Convert Int to Hexdecimal without using 'printf'?
Best if the all the value are placed in the variable itself and some sample code with explanation.
The decimal and hexadecimal systems are just ways of expressing the value of the int. In a way "it is already a hexadecimal".
I think you can use itoa in stdlib.h :
char * itoa ( int value, char * str, int base ); or sprintf(str,"%x",value);
The documentation : itoa documentation
Of course it is possible. Just think about how printf itself was originally implemented...
I won't give you a full solution, only hints, based on which you can experiment with the implementation in code:
An 8-bit number can be expressed as 2 hex digits, which contain the higher and lower 4 bits, respectively. To get these bits, you can use the bit-shift (>>) and mask (&) operators.
Once you have a 4-bit value, you can easily map it to the correct hex digit using a sequence of ifs, or (as a more elegant solution) by indexing into a character array.
Hexdecival vs Decimal vs Binary..etc.. are only different bases that represent the same number. printf doesn't convert your number, it generates an hexdecimal string representation of your number. If you want to implement your own study how to make a conversion between decimal and hexdecimal bases.
Yes, it is definitely possible to convert an integer to a hexadecimal string without using the "printf" family of formatting functions.
You can write such a function by converting the number from base-10 (as we think about it) to base-16 (hexadecimal) and printing the digits in that representation (0-9A-F). This will require you to think a lot about the bases we use to represent numbers.
If you are referring to displaying an int as a hexadecimal number in C, than you will have to write a function that does the same thing as printf.
If you are referring to casting or internal representation, it can't be done because hexadecimal is not a data type.
An int is stored in your computer as a binary number. In fact, since hex can be interpreted as a shorthand for writing binary, you might even say that when you print out a decimal number using printf, it has to be converted from hex to decimal.
it's an example for convert a char array to hex string format
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
unsigned char d=255;
char hex_array[16]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
char *array_to_hex_string(uint8_t data[],int size);
char test_data[3] = {'0',188,255};
int main()
{
printf("%s",array_to_hex_string(test_data,3));
return 0;
}
char *array_to_hex_string(uint8_t data[],int size){
int i,j;
char *hex_string = (char *)malloc((2*size) * sizeof(data[0]));
for(i=0;i<size;i++){
hex_string[j] = hex_array[(data[i]>>4)];
hex_string[j+1] = hex_array[(data[i] & 15)];
j +=2;
}
return (char *)hex_string;
}
cout << hex << intvar << endl;
But if you want an answer that gives you an A for your homework, you're not going to get lucky :)

Dynamic allocation in C

I'm writing a program and I have the following problem:
char *tmp;
sprintf (tmp,"%ld",(long)time_stamp_for_file_name);
Could someone explain how much memory allocate for the string tmp.
How many chars are a long variable?
Thank you,
I would appreciate also a link to an exahustive resource on this kind of information.
Thank you
UPDATE:
Using your examples I got the following problem:
root#-[/tmp]$cat test.c
#include <stdio.h>
int
main()
{
int len;
long time=12345678;
char *tmp;
len=snprintf(NULL,0,"%ld",time);
printf ("Lunghezza:di %ld %d\n",time,len);
return 0;
}
root#-[/tmp]$gcc test.c
root#-[/tmp]$./a.out
Lunghezza:di 12345678 -1
root#-[/tmp]$
So the len result from snprintf is -1, I compiled on Solaris 9 with the standard compiler.
Please help me!
If your compiler conforms to C99, you should be able to do:
char *tmp;
int req_bytes = snprintf(NULL, 0, "%ld",(long)time_stamp_for_file_name);
tmp = malloc(req_bytes +1); //add +1 for NULL
if(!tmp) {
die_horrible_death();
}
if(snprintf(tmp, req_bytes+1, "%ld",(long)time_stamp_for_file_name) != req_bytes) {
die_horrible_death();
}
Relevant parts of the standard (from the draft document):
7.19.6.5.2: If n is zero, nothing is written, and s may be a null pointer.
7.19.6.5.3: The snprintf function returns the number of characters that would have been written
had n been sufficiently large, not counting the terminating null character, or a negative
value if an encoding error occurred. Thus, the null-terminated output has been
completely written if and only if the returned value is nonnegative and less than n.
If this is not working, I'm guessing your compiler/libc does not support this part of c99, or you might need to explicitly enable it. Wh I run your example (with gcc version 4.5.0 20100610 (prerelease), Linux 2.6.34-ARCH), I get
$./example
Lunghezza:di 12345678 8
The number of chars actually used obviously depends on the value: if time_stamp_for_file_name is 0 you only actually need 2 bytes. If there's any doubt, you can use snprintf, which tells you how much space you need:
int len = snprinf(0, 0, "%ld", (long)time_stamp_for_file_name) + 1;
char *tmp = malloc(len);
if (tmp == 0) { /* handle error */ }
snprintf(tmp, len, "%ld", (long)time_stamp_for_file_name);
Beware implementations where snprintf returns -1 for insufficient space, rather than the space required.
As Paul R says, though, you can figure out a fixed upper bound based on the size of long on your implementation. That way you avoid dynamic allocation entirely. For example:
#define LONG_LEN (((sizeof(long)*CHAR_BIT)/3)+2)
(based on the fact that the base-2 log of 10 is greater than 3). That +2 gives you 1 for the minus sign and 1 for the fact that integer division rounds down. You'd need another 1 for the nul terminator.
Or:
#define STRINGIFY(ARG) #ARG
#define EXPAND_AND_STRINGIFY(ARG) STRINGIFY(ARG)
#define VERBOSE_LONG EXPAND_AND_STRINGIFY(LONG_MIN)
#define LONG_LEN sizeof(VERBOSE_LONG)
char tmp[LONG_LEN];
sprintf(tmp, "%ld", (long)time_stamp_for_file_name);
VERBOSE_LONG might be a slightly bigger string than you actually need. On my compiler it's (-2147483647L-1). I'm not sure whether LONG_MIN can expand to something like a hex literal or a compiler intrinsic, but if so then it could be too short, and this trick won't work. It's easy enough to unit-test, though.
If you want a tight upper bound to cover all possibilities within the standard, up to a certain limit, you could try something like this:
#if LONG_MAX <= 2147483647L
#define LONG_LEN 11
#else
#if LONG_MAX <= 4294967295L
#define LONG_LEN 11
#else
#if LONG_MAX <= 8589934591L
... etc, add more clauses as new architectures are
invented with bigger longs
#endif
#endif
#endif
But I doubt it's worth it: better just to define it in some kind of portability header and configure it manually for new platforms.
It's hard to tell in advance, although I guess you could guesstimate that it'll be at the most 64 bits, and thus "18,446,744,073,709,551,615" should be the largest possible value. That's 2+6*3 = 20 digits, the commas are generally not included. It'd be 21 for a negative number. So, go for 32 bytes as a nice and round size.
Better would be to couple that with using snprintf(), so you don't get a buffer overflow if your estimate is off.
It depends on how big long is on your system. Assuming a worst case of 64 bits then you need 22 characters max - this allows for 20 digits, a preceding - and a terminating \0. Of course if you're feeling extravagant you could always allow a little extra and make it a nice round number like 32.
It takes log210 (~3.32) bits to represent a decimal digit; thus, you can compute the number of digits like so:
#include <limits.h>
#include <math.h>
long time;
double bitsPerDigit = log10(10.0) / log10(2.0); /* or log2(10.0) in C99 */
size_t digits = ceil((sizeof time * (double) CHAR_BIT) / bitsPerDigit);
char *tmp = malloc(digits+2); /* or simply "char tmp[digits+2];" in C99 */
The "+2" accounts for sign and the 0 terminator.
Octal requires one character per three bits. You print to base of ten which never gives more digits than octal for same number. Therefore, allocate one character for each three bits.
sizeof(long) gives you amount of bytes when compiling. Multiply that by 8 to get bits. Add two before dividing by three so you get ceiling instead of floor. Remember the C strings want a final zero byte to their end, so add one to the result. (Another one for negative, as described in comments).
char tmp[(sizeof(long)*8+2)/3+2];
sprintf (tmp,"%ld",(long)time_stamp_for_file_name);
3*sizeof(type)+2 is a safe general rule for the number of bytes needed to format an integer type type as a decimal string, the reason being that 3 is an upper bound on log10(256) and a n-byte integer is n digits in base-256 and thus ceil(log10(256^n))==ceil(n*log10(256)) digits in base 10. The +2 is to account for the terminating NUL byte and possible minus sign if type is very small.
If you want to be pedantic and support DSPs and such with CHAR_BIT!=8 then use 3*sizeof(type)*((CHAR_BIT+7)/8)+2. (Note that for POSIX systems this is irrelevant since POSIX requires UCHAR_MAX==255 and CHAR_BIT==8.)

How do I prevent buffer overflow converting a double to char?

I'm converting a double to a char string:
char txt[10];
double num;
num = 45.344322345
sprintf(txt, "%.1f", num);
and using ".1f" to truncate the decimal places, to the tenths digit.
i.e. - txt contains 45.3
I usually use precision in sprintf to ensure the char buffer is not overflowed.
How can I do that here also truncating the decimal, without using snprintf?
(i.e. if num = 345694876345.3 for some reason)
Thanks
EDIT If num is > buffer the result no longer matters, just do not want to crash. Not sure what would make the most sense in that case.
EDIT2 I should have made it more clear than in just the tag, that this is a C program.
I am having issues using snprintf in a C program. I don't want to add any 3rd party libraries.
Use snprintf() , which will tell you how many bytes were not printed. In general, you should size your array to be large enough to handle the longest string representation of the target integer type. If not known in advance, use malloc() (or asprintf(), which is non-standard, but present on many platforms).
Edit
snprintf() will fail gracefully if the format exceeds the given buffer, it won't overflow. If you don't need to handle that, then simply using it will solve your problem. I can't think of an instance where you would not want to handle that, but then again, I'm not working on whatever you are working on :)
Why not just make your buffer big enough to hold the largest possible string representation of a double?
Assuming a 64-bit double using the IEEE standard for floating point arithmetic, which uses 52 bits for a mantissa: 2^52 = 4,503,599,627,370,500. So we need 16 characters to hold all the digits before and after the decimal point. 19 considering the decimal point, sign character and null terminator.
I would just use a buffer size of at least 20 characters and move on.
If you need to print a double using scientific notation, you will need to add enough space for the exponent. Assuming a 11 bit signed exponent, that's another 4 characters for the exponent plus a sign for the exponent and the letter 'E'. I would just go with 30 characters in that case.
If you absolutely must do it on your own, count the digits in the number before trying to convert:
int whole = num;
int wholeDigits = 0;
do {
++wholeDigits;
}
while (whole /= 10);
double fraction = num - (int) num;
int decimallDigits = 0;
while (fraction > 0) {
++decimalDigits;
fraction *= 10;
fraction = fraction - (int) fraction;
}
int totalLength = decimalDigits ? wholeDigits + decimalDigits + 1 : wholeDigits;
You should probably verify that this ad-hoc code works as advertised before relying on it to guard against crashes. I recommend that you use snprintf or something similar instead of my code, as others have said.
Why do you want to do it without snprintf? You should be using snprintf regardless of whether your format string contains a double, another string or anything else, really. As far as I can see, there's no reason not to.

Resources