Note that in the code posted in the question, string[]
is declared in the test()
function using sizeof(hex_arr)
. But hex_arr
is a pointer to char
, not an array, so this will not give the correct size for string[]
. Also, here string
is an automatic variable whose lifetime is limited to the function test()
; that is fine if the only goal is to print the results, but another solution must be found if the results need to be used elsewhere in the code.
One way to approach this is to pass an output array along with an input array into a conversion function. The function can return -1
if the input format is not acceptable, otherwise returning 0
, and the output array can hold the identifier string resulting from the hex number input string.
Each pair of digits in the input represents a number in hexadecimal, which could be a three-digit decimal number, and each three-digit decimal number (except the last one, which is followed by a null-terminator) has an added delimiter added after it; so each pair of input digits converts to at most four characters. That means that allocating output[]
to be twice the size of input
will be sufficient to store any result, including space for the null-terminator. This in fact provides a little extra space, which will be needed.
The method used here by the id_from_hexstring()
function to perform the conversion involves using sscanf()
in a loop to read a pair of characters as a string from the input into the temporary buffer val_str[]
. The %n
conversion specifier is used to keep track of the location reached after each successful conversion, storing the number of successful matches in offset
and using this value to increment a pointer into input[]
in preparation for the next conversion.
The strtoul()
function is used to convert the two-digit hex strings stored in val_str[]
to unsigned long
values. When the first pair of characters in input[]
is converted, if the converted value does not match IN_PREFIX
, the function returns with an error code. Otherwise, OUT_PREFIX
is printed to the beginning of output[]
instead of the converted value. After this first pair, the remaining conversion values are printed to the end of the output[]
string.
After the conversion loop terminates, a trailing .
delimiter is left at the end of output[]
, and the last task is to remove this before returning 0
to indicate success. By doubling the size (instead of the string length) of the input[]
array to determine the size of the output[]
array, it is guaranteed that output[]
can hold the extra .
delimiter.
This code could do more to validate the input. As it is now, the id_from_hexstring()
function expects the input to be composed of valid hex characters. Here is the complete program and its output:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define IN_PREFIX 0x2b
#define OUT_PREFIX "1.3."
#define ID_PREFIX_ERR -1
#define ID_PREFIX_OK 0
int id_from_hexstring(char *out, char *in);
int main(void)
{
char input[] = "2b06010201010300";
char output[sizeof input * 2] = "";
if (id_from_hexstring(output, input) == -1) {
fprintf(stderr, "Error in input format\n");
} else {
printf("Input: %s\n", input);
printf("Output: %s\n", output);
}
return 0;
}
/* Expects that out points to a suitably sized array containing an empty
* string, and in points to a string containing only unsigned hex digits */
int id_from_hexstring(char *out, char *in)
{
int ret_val = ID_PREFIX_OK;
int offset;
char *ptr = in;
char val_str[3];
while (sscanf(ptr, "%2s%n", val_str, &offset) == 1) {
unsigned long dec_val = strtoul(val_str, NULL, 16);
/* Handle prefix; return error code if invalid */
if (ptr == in) {
if (dec_val != IN_PREFIX) {
ret_val = ID_PREFIX_ERR;
break;
} else {
sprintf(out, OUT_PREFIX);
ptr += offset;
continue;
}
}
/* Print next value to identifier string */
size_t end = strlen(out);
sprintf(out + end, "%lu.", dec_val);
ptr += offset;
}
/* Replace trailing point */
size_t out_len = strlen(out);
if (out_len > 0) {
out[out_len - 1] = '\0';
}
return ret_val;
}
Input: 2b06010201010300
Output: 1.3.6.1.2.1.1.3.0