Convert array of bytes to hexadecimal string in plain old C - c

I am looking into a method to convert a byte array to a hexadecimal string here is what i coded :
unsigned char buffer[] = {0xAA,0xBB,0x01,0xAB,0x11,0x12,0x13,0x22,0x11,0x14};
int _tmain(int argc, _TCHAR* argv[])
{
char * asta = (char*)malloc(16);
memset(asta,0,16);
int k;
for (k = 0; k < 16 ; k++)
{
sprintf(&asta[k],"%X",buffer[4 + k]);
}
printf("%s",asta);
_getch();
}
Only the first byte is converted correctly the rest are not. How can i fix the code ?

You have 10 bytes in your array, so your buffer needs at least 21 bytes (2 hex digits are needed for each byte + 1 for the null terminator).
I don't understand what you are doing here:
sprintf(&asta[k],"%X",buffer[4 + k]);
Why are you starting with the fifth byte in the buffer? Also, each byte in your buffer takes two bytes in the string, so you need to print to asta[2 * k].
Putting it together you get something like:
char * asta = (char*)calloc(2 * sizeof buffer + 1, sizeof(char)); // calloc automatically zeros asta
int k;
for (k = 0; k < sizeof buffer ; k++)
{
sprintf(&asta[2 * k],"%02X", (unsigned int)buffer[k]); // Not sure if the cast is needed
}
printf("%s",asta);

You have to remember that two-digit hexadecimal numbers will still be two digits when you print it as a string, i.e. it will take up two characters.
In the loop, the second iteration will overwrite the second character of the string, the third iteration will overwrite the third characters, etc.
Also, since each two-digit number will use two characters, you must allocate memory for 32 characters, plus one for the string terminating '\0' character.
And as noted in the comments, you are accessing data outside of your array.

Related

Adding leading 'zeros' to a number without library in C

I wanted to store 'two zeros' in a value e.g. answer(which is a BYTE) and send it over to RS-485. How can I do that without any library?
Secondly, I tried by adding char '0' to zero(0) but instead it converted it to equivalent of zero which is '48' and send it over RS-485.
enter image description here
Thanks,
sprintf(buffer, sizeof buffer, "%03d", the_byte_number);
will do what you want, you can then send the buffer contents over the RS-485 using something like:
write(rs_485_file_descriptor, buffer, strlen(buffer);
if you refuse to use even the C standard library, you'll have to do the conversion yourself:
char *zero_pad(uint8_t numb, char *buffer)
{
static char tab[] = "01234567898";
/* you need to have at least three characters for the three digits in
* buffer, no check is made here for efficiency reasons.
* we advance the buffer 3 positions first, and then go backwards,
* filling with characters, from the least significant digit to the most.
* in case you want the string to be null terminated, you must start
* with the '\0' char.
*/
#if YOU_WANT_IT_NULL_TERMINATED
buffer += 4;
*--buffer = '\0';
#else
buffer += 3;
#endif
for (int i = 0; i < 3; i++) {
int dig = numb % 10;
*--buffer = tab[dig];
number /= 10;
}
return buffer;
} /* zero_pad */
What you describe as 'two zeros' are two nibbles in the hexadecimal representation of the BYTE 0. Of course if you add the ASCII character '0' to zero, you get 4810. If you just want to send the BYTE answer, no conversion is needed.
wr = write(fd, &answer, sizeof answer);

Converting massive binary input string into character string C

I'm not familiar with C at all so this might be a simple problem to solve. I'm trying to take an input char* array of binary character sequences, ex. "0100100001101001", and output its relative string ("Hi"). The problem I'm having is coming up with a way to split the input into seperate strings of length 8 and then convert them individually to ulimately get the full output string.
char* binaryToString(char* b){
char binary[8];
for(int i=0; i<8; ++i){
binary[i] = b[i];
}
printf("%s", binary);
}
I'm aware of how to convert 8-bit into its character, I just need a way to split the input string in a way that will allow me to convert massive inputs of 8-bit binary characters.
Any help is appreciated... thanks!
From what I can tell, your binaryToString() function does not do what you'd want it to. The print statement just prints the first eight characters from the address pointed to by char* b.
Instead, you can convert the string of 8 bits to an integer, utilizing a standard C function strtol(). There's no need to convert any further, because binary, hex, decimal, etc, are all just representations of the same data! So once the string is converted to a long, you can use that value to represent an ASCII character.
Updating the implementation (as below), you can then leverage it to print a whole sequence.
#include <stdio.h>
#include <string.h>
void binaryToString(char* input, char* output){
char binary[9] = {0}; // initialize string to 0's
// copy 8 bits from input string
for (int i = 0; i < 8; i ++){
binary[i] = input[i];
}
*output = strtol(binary,NULL,2); // convert the byte to a long, using base 2
}
int main()
{
char inputStr[] = "01100001011100110110010001100110"; // "asdf" in ascii
char outputStr[20] = {0}; // initialize string to 0's
size_t iterations = strlen(inputStr) / 8; // get the # of bytes
// convert each byte into an ascii value
for (int i = 0; i < iterations; i++){
binaryToString(&inputStr[i*8], &outputStr[i]);
}
printf("%s", outputStr); // print the resulting string
return 0;
}
I compiled this and it seems to work fine. Of course, this can be done cleaner and safer, but this should help you get started.
I just need a way to split the input string in a way that will allow me to convert massive inputs of 8-bit binary characters.
You can use strncpy() to copy the sequence of '0' and '1' in a chunk of 8 characters at a time from the input string, something like this:
//get the size of input string
size_t len = strlen(b);
//Your input array of '0' and '1' and every sequence of 8 bytes represents a character
unsigned int num_chars = len/8;
//Take a temporary pointer and point it to input string
const char *tmp = b;
//Now copy the 8 chars from input string to buffer "binary"
for(int i=0; i<num_chars; ++i){
strncpy(binary, tmp+(i*8), 8);
//do your stuff with the 8 chars copied from input string to "binary" buffer
}
Maybe this can help. I didnt compile it but there is the idea. You can loop every 8 bit separately with while loop. And assign 8 bit to binary array with for loop. After that send this binary array to convert8BitToChar function to get letter equivalent of 8 bit. Then append the letter to result array. I'm not writing c for 3 year if there is mistakes sorry about that. Here pseudo code.
char* binaryToString(char* b){
char* result = malloc(sizeof(256*char));
char binary[8];
int nextLetter = 0;
while (b[nextLetter*8] != NULL) { // loop every 8 bit
for(int i=0; i<8; ++i){
binary[i] = b[nextLetter*8+i];
}
result[nextLetter] = 8bitToChar(binary));// convert 8bitToChar and append yo result
nextLetter++;
}
result[nextLetter] = '\0';
return result;
}

Assigning part of a string to a char * in C

I want to copy X to Y words of a string to the out char * array.
unsigned char * string = "HELLO WORLD!!!" // length 14
unsigned char out[9];
size_t length = 9;
for(i=0 ;i < length ;++i)
{
out[i] = string[i+3];
}
printf("%s = string\n%s = out\n", string, out);
When looking at the output of out, why is there gibberish after a certain point of my string? I see the string of out as LO WORLD!# . Why are there weird characters appearing after the content I copied, isn't out supposed to be a an array of 9? I expected the output to be
LO WORLD!
In C you need to terminate your string with a 0x00 value so a string of length 9 needs ten bytes to store it with the last set to 0. Otherwise your print statements run off into random data.
unsigned char * string = "HELLO WORLD!!!" // length 14
unsigned char out[10];
size_t length = 9;
for(i=0 ;i < length ;++i)
{
out[i] = string[i+3];
}
out[length] = 0x00;
printf("%s = string\n%s = out\n", string, out);
A minor point, but string literals have type char* (or const char* in C++), not unsigned char* -- these might be the same in your implementation, but they don't need to be.
Furthermore, this is not true:
unsigned char * string = "HELLO WORLD!!!" // length 14
The string actually occupies 15 bytes -- there is an extra, hidden '\0' at the end, called a nul byte, which marks the end of the string. These nul terminators are very important, because if they're not present, then many C library functions which manipulate strings will keep going until they hit a byte with a value equal to '\0' -- and so can end up reading or trampling over bits of memory they shouldn't do. This is called a buffer overrun, and is a classic bug (and exploitable security problem) in C programmes.
In your example, you haven't included this nul terminator in your copied string, so printf() just keeps going until it finds one, hence the gibberish you're seeing. In general, it's a good idea only to use C library functions to manipulate C strings if possible, as these are careful to add the terminator for you. In this case, strncpy from string.h does exactly what you're after.
A 9 character string needs 10 bytes because it must be null ( 0 ) terminated. Try this:
unsigned char out[10]; // make this 10
size_t length = 9;
for(i=0 ;i < length ;++i)
{
out[i] = string[i+3];
}
out[i] = 0; // add this to terminate the string
A better approach would be just the line:
strncpy(out, string+3, 9);
C strings must be null terminated. You only created an array large enough for 8 characters + the null terminator, but you never added the terminator.
So, you need to allocate the length plus 1 and add the terminator.
// initializes all elements to 0
char out[10] = {0};
// alternatively, add it at the end.
out[9] = '\0';
Think of it this way; you're passed a char* which represents a string. How do you know how long it is? How can you read it? Well, in C, a sentinel value is added to the end. This is the null terminator. It is how strings are read in C, and passing around unterminated strings to functions which expect C strings results in undefined behavior.
And then... just use strncpy to copy strings.
If you want to have copy 9 characters from your string, you'll need to have an array of 10 to do that. It is because a C string needs to have '\0' as null terminated character. So your code should be rewritten like this:
unsigned char * string = "HELLO WORLD!!!" // length 14
unsigned char out[10];
size_t length = 9;
for(i=0 ;i < length ;++i)
{
out[i] = string[i+3];
}
out[9] = 0;
printf("%s = string\n%s = out\n", string, out);

How to convert a character from a file into an ascii integer into an array?

I am attempting to put a list of characters AND integers into an array of just integers. The file.txt looks like:
a 5 4 10
4 10 a 4
In the array I want the values to come out as {97,5,4,10,4,10,97,4}
This is part of my code:
int * array = malloc(100 * sizeof(int));
FILE* file;
int i=0;
int integer = 1;
file=fopen(filename,"r");
while (fscanf(file,"%d",&integer) > 0)
{
array[i] = integer;
i++;
}
Your problem is that, at first read, your while condition will exit because first element in the file is a char and fscanf won't interpret it as an integer, returning 0. I would suggest, if you are sure that your separator is a space, reading a string (it will automatically stop at space) and convert read value to int with strtol.
Something like:
int * array = malloc(100 * sizeof(int));
FILE* file;
int i=0;
char tmp[2], *pEnd;
file=fopen("./test.txt","r");
while (fscanf(file,"%s",tmp) > 0)
{
if( !(array[i] = strtol(tmp, &pEnd,10)))
array[i] = tmp[0];
i++;
}
Note that I assumed that you'll have no integer bigger than one digit (tmp array size) and that I check strtol response for detecting non integer chars.
It seems to me that what you want to do is use fscanf("%s", some_string) since numerics can be received as strings but strings cannot be received as numerics. Then with each input, you need to decide if the string is actually numeric or not, and then derive the value you want to place into the array accordingly.

sscanf doesn't move, scanning same integer everytime

I have a string that has ints and I'm trying to get all the ints into another array. When sscanf fails to find an int I want the loop to stop. So, I did the following:
int i;
int getout = 0;
for (i = 0; i < bsize && !getout; i++) {
if (!sscanf(startbuffer, "%d", &startarray[i])) {
getout = 1;
}
}
//startbuffer is a string, startarray is an int array.
This results in having all the elements of startarray to be the first char in startbuffer.
sscanf works fine but it doesn't move onto the next int it just stays at the first position.
Any idea what's wrong? Thanks.
The same string pointer is passed each time you call sscanf. If it were to "move" the input, it would have to move all the bytes of the string each time which would be slow for long strings. Furthermore, it would be moving the bytes that weren't scanned.
Instead, you need to implement this yourself by querying it for the number of bytes consumed and the number of values read. Use that information to adjust the pointers yourself.
int nums_now, bytes_now;
int bytes_consumed = 0, nums_read = 0;
while ( ( nums_now =
sscanf( string + bytes_consumed, "%d%n", arr + nums_read, & bytes_now )
) > 0 ) {
bytes_consumed += bytes_now;
nums_read += nums_now;
}
Convert the string to a stream, then you can use fscanf to get the integers.
Try this.
http://www.gnu.org/software/libc/manual/html_node/String-Streams.html
You are correct: sscanf indeed does not "move", because there is nothing to move. If you need to scan a bunch of ints, you can use strtol - it tells you how much it read, so you can feed the next pointer back to the function on the next iteration.
char str[] = "10 21 32 43 54";
char *p = str;
int i;
for (i = 0 ; i != 5 ; i++) {
int n = strtol(p, &p, 10);
printf("%d\n", n);
}
This is the correct behavior of sscanf. sscanf operates on a const char*, not an input stream from a file, so it will not store any information about what it has consumed.
As for the solution, you can use %n in the format string to obtain the number of characters that it has consumed so far (this is defined in C89 standard).
e.g. sscanf("This is a string", "%10s%10s%n", tok1, tok2, &numChar); numChar will contain the number of characters consumed so far. You can use this as an offset to continue scanning the string.
If the string only contains integers that doesn't exceed the maximum value of long type (or long long type), use strtol or strtoll. Beware that long type can be 32-bit or 64-bit, depending on the system.

Resources