From uint8_t to hex string array? - c

I know it's a simple question, but I am completely lost.
I have in input a string:
input: 220209
I want:
output: uint8_t myarr[8]={0x22,0x02,0x09,0x00, 0x00, 0x00,0x00,0x00}
So myarr has always a dimension of 8, and if I have a lower input string I have to complete with 0x00. Can someone give me any idea?
Sorry for bothering you, any help will be appreciated.
Regards

Using strtol() to convert 2 characters at a time, explicitly using base 16 makes it easy:
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
// Assume s has an even number of hexdigit chars (at most 16) followed by a nul
void convert(const char *s, uint8_t out[static 8]) {
int i = 0;
// Handle 2 chars at a time
while (*s) {
char byte[3] = { *s, *(s + 1), 0 };
out[i++] = strtol(byte, NULL, 16);
s += 2;
}
// Fill the rest of the array with nuls
for (; i < 8; i += 1) {
out[i] = 0;
}
}
int main(void)
{
const char *input = "220209";
uint8_t myarr[8];
convert(input, myarr);
// Pretty-print the array using hex values
fputs("uint8_t myarr[8] = { ", stdout);
for (int i = 0; i < 8; i += 1) {
printf("0x%02" PRIx8, myarr[i]);
if (i < 7) {
fputs(", ", stdout);
}
}
puts(" };");
return 0;
}

Another option is to use sscanf() to parse two characters at a time:
void convert(const char *s, uint8_t out[8])
{
memset(out, 0, 8);
while (sscanf(s, "%2"SCNx8, out++) == 1) {
s += 2;
}
}
The first line sets the 8 bytes to 0 by taking advantage of 64 bits arithmetics. Then we scan two characters from string s, reading an integer of type uint8_t from hexdecimal ASCII representation. If the read was successful, we move to the next two characters.
It looks like a code golf submission, but it's nice, because nothing gets copied.
Another version could be:
void convert(const char *s, uint8_t out[8])
{
static char tbl[] = {
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
0, 1, 2, 3, 4, 5, 6,7,8,9,0,0,0,0,0,0,
0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0,
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0,
0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0,
};
memset(out, 0, 8);
while (*s) {
*out++ = tbl[s[0]] * 16 + tbl[s[1]];
s += 2;
}
}

Hope it can work for you
memset(myarr, 0, 8);
int szLen = strlen(szInput);
for(int i = 0; i < szLen / 2; i++) {
uint8_t high = toupper(szInput[i*2]);
uint8_t low = toupper(szInput[i*2 + 1]);
if(high >= '0' && high <= '9')
high = high - '0';
if(low >= '0' && low <= '9')
low = low - '0';
if(high >= 'A' && high <= 'F')
high = high - 'A' + 10;
if(low >= 'A' && low <= 'F')
low = low - 'A' + 10;
myarr[i] = (high << 4) | low; // bit operation is faster than arithmetic
}

Related

Free invalid pointer error in C for Codewars

I am attempting to solve the Codewars problem "Sum Strings as Numbers" in which you are given two strings that are numbers and you need to return a string that is the sum of these numbers. My program works for the first few tests but it breaks down when encountering random tests with strings that are hundreds of digits long. If I use the same exact input on and run the program on my own computer, there are no issues. I get this error from code wars:
Test Crashed
Caught unexpected signal: 6
and this in stderr:
free(): invalid pointer
free(): invalid pointer
this is stdout:
START
Initial variables:
llu_strlen a = 236, llu_strlen(b) = 184
llu_strlen(s1) = 236, llu_strlen(s2) = 236
ret = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
a: 78917474443946915721964827121804924300830503197284695927643616893992582376123210474159778186067315502131337563007456229418171820129259461866211403468685049537996202816061990624398601182936240354459414060583378547091248670096407399362798
s1: 78917474443946915721964827121804924300830503197284695927643616893992582376123210474159778186067315502131337563007456229418171820129259461866211403468685049537996202816061990624398601182936240354459414060583378547091248670096407399362798
b: 2750702483149509093439330294177302822318268374477554716003096683744873506434616984296831843933180888658289619326781012055684240461466622908813033352854623703899221940600376950489726654
s2: 00000000000000000000000000000000000000000000000000002750702483149509093439330294177302822318268374477554716003096683744873506434616984296831843933180888658289619326781012055684240461466622908813033352854623703899221940600376950489726654
entering sum loop:
i = 0, digita = 8, digitb = 4, sumstr=12
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002
i = 1, digita = 9, digitb = 5, sumstr=15
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000052
i = 2, digita = 7, digitb = 6, sumstr=14
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000452
i = 3, digita = 2, digitb = 6, sumstr=09
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009452
i = 4, digita = 6, digitb = 2, sumstr=08
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000089452
i = 5, digita = 3, digitb = 7, sumstr=10
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000089452
i = 6, digita = 9, digitb = 9, sumstr=19
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009089452
i = 7, digita = 9, digitb = 8, sumstr=18
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000089089452
i = 8, digita = 3, digitb = 4, sumstr=08
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000889089452
i = 9, digita = 7, digitb = 0, sumstr=07
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007889089452
i = 10, digita = 0, digitb = 5, sumstr=05
(continues on like that for a while)
000000000000000000000000000121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 210, digita = 7, digitb = 0, sumstr=07
000000000000000000000000007121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 211, digita = 2, digitb = 0, sumstr=02
000000000000000000000000027121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 212, digita = 8, digitb = 0, sumstr=08
000000000000000000000000827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 213, digita = 4, digitb = 0, sumstr=04
000000000000000000000004827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 214, digita = 6, digitb = 0, sumstr=06
000000000000000000000064827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 215, digita = 9, digitb = 0, sumstr=09
000000000000000000000964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 216, digita = 1, digitb = 0, sumstr=01
000000000000000000001964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 217, digita = 2, digitb = 0, sumstr=02
000000000000000000021964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 218, digita = 7, digitb = 0, sumstr=07
000000000000000000721964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 219, digita = 5, digitb = 0, sumstr=05
000000000000000005721964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 220, digita = 1, digitb = 0, sumstr=01
000000000000000015721964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 221, digita = 9, digitb = 0, sumstr=09
000000000000000915721964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 222, digita = 6, digitb = 0, sumstr=06
000000000000006915721964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 223, digita = 4, digitb = 0, sumstr=04
000000000000046915721964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 224, digita = 9, digitb = 0, sumstr=09
000000000000946915721964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 225, digita = 3, digitb = 0, sumstr=03
000000000003946915721964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 226, digita = 4, digitb = 0, sumstr=04
000000000043946915721964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 227, digita = 4, digitb = 0, sumstr=04
000000000443946915721964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 228, digita = 4, digitb = 0, sumstr=04
000000004443946915721964827121804924300830503197284698678346100043501675815453504651462600504335689979686053566104139974291678254746243758698055336649573707827615529597074046308639062649559149167492766915207082446313189270473357889089452
i = 229, digita
here is the program that I run on code wars which throws an error:
#include <malloc.h>
#include <string.h>
unsigned long long llu_strlen(const char * s)
{
unsigned long long len = 0;
while (s[len])
len++;
return len;
}
char *strsum(const char *a, const char *b)
{
puts("START");
static char * ret;
char sumstr[] = "00";
char digita, digitb;
unsigned long long maxlen, i, carry;
if (llu_strlen(a) == 0 || llu_strlen(b) == 0)
return NULL;
maxlen = llu_strlen(a) > llu_strlen(b) ? llu_strlen(a) : llu_strlen(b);
// create ret full of maxlen+1 0s plus a '\0'. total size is maxlen+2
ret = (char *) malloc((maxlen+2) * sizeof(char));
for (i = 0; i < maxlen+1; i++)
ret[i] = '0';
ret[maxlen+1] = '\0';
// create copies of a and b of equal size by buffering with 0s
char s1[maxlen], s2[maxlen];
for (i = 0; i < maxlen - llu_strlen(a); i++)
s1[i] = '0';
strcpy(s1+i, a);
for (i = 0; i < maxlen - llu_strlen(b); i++)
s2[i] = '0';
strcpy(s2+i, b);
puts("Initial variables:");
printf("llu_strlen a = %llu, llu_strlen(b) = %llu\n", llu_strlen(a), llu_strlen(b));
printf("llu_strlen(s1) = %llu, llu_strlen(s2) = %llu\n", llu_strlen(s1), llu_strlen(s2));
printf("ret = %s\n", ret);
printf("a: %s\n", a);
printf("s1: %s\n", s1);
printf("b: %s\n", b);
printf("s2: %s\n", s2);
// sum loop
printf("entering sum loop:\n");
for (i = carry = 0; i < maxlen; i++)
{
digita = s1[maxlen-1-i] - 48;
digitb = s2[maxlen-1-i] - 48;
sprintf(sumstr, "%02llu", digita + digitb + carry);
carry = sumstr[0] - 48;
ret[maxlen-i] = sumstr[1];
printf("i = %llu, digita = %d, digitb = %d, sumstr=%s\n", i, digita, digitb, sumstr);
puts(ret);
}
printf("Done with that\n");
ret[0] = carry + 48;
// remove preceeding zeros
while (*ret == '0' && *(ret+1) != '\0')
ret++;
printf("final ret: %s\nEND\n\n", ret);
return ret;
}
and here is the program I run on my computer which finds the result successfully:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
unsigned long long llu_strlen(const char * s)
{
unsigned long long len = 0;
while (s[len])
len++;
return len;
}
char *strsum(const char *a, const char *b)
{
puts("START");
static char * ret;
char sumstr[] = "00";
char digita, digitb;
unsigned long long maxlen, i, carry;
if (llu_strlen(a) == 0 || llu_strlen(b) == 0)
return NULL;
maxlen = llu_strlen(a) > llu_strlen(b) ? llu_strlen(a) : llu_strlen(b);
// create ret full of maxlen+1 0s plus a '\0'. total size is maxlen+2
ret = (char *) malloc((maxlen+2) * sizeof(char));
for (i = 0; i < maxlen+1; i++)
ret[i] = '0';
ret[maxlen+1] = '\0';
// create copies of a and b of equal size by buffering with 0s
char s1[maxlen], s2[maxlen];
for (i = 0; i < maxlen - llu_strlen(a); i++)
s1[i] = '0';
strcpy(s1+i, a);
for (i = 0; i < maxlen - llu_strlen(b); i++)
s2[i] = '0';
strcpy(s2+i, b);
puts("Initial variables:");
printf("llu_strlen a = %llu, llu_strlen(b) = %llu\n", llu_strlen(a), llu_strlen(b));
printf("llu_strlen(s1) = %llu, llu_strlen(s2) = %llu\n", llu_strlen(s1), llu_strlen(s2));
printf("ret = %s\n", ret);
printf("a: %s\n", a);
printf("s1: %s\n", s1);
printf("b: %s\n", b);
printf("s2: %s\n", s2);
// sum loop
printf("entering sum loop:\n");
for (i = carry = 0; i < maxlen; i++)
{
digita = s1[maxlen-1-i] - 48;
digitb = s2[maxlen-1-i] - 48;
sprintf(sumstr, "%02llu", digita + digitb + carry);
carry = sumstr[0] - 48;
ret[maxlen-i] = sumstr[1];
printf("i = %llu, digita = %d, digitb = %d, sumstr=%s\n", i, digita, digitb, sumstr);
puts(ret);
}
printf("Done with that\n");
ret[0] = carry + 48;
// remove preceeding zeros
while (*ret == '0' && *(ret+1) != '\0')
ret++;
printf("final ret: %s\nEND\n\n", ret);
return ret;
}
int main(void)
{
char * res;
res = strsum("78917474443946915721964827121804924300830503197284695927643616893992582376123210474159778186067315502131337563007456229418171820129259461866211403468685049537996202816061990624398601182936240354459414060583378547091248670096407399362798",
"2750702483149509093439330294177302822318268374477554716003096683744873506434616984296831843933180888658289619326781012055684240461466622908813033352854623703899221940600376950489726654");
return 0;
}
The error always occurs while the print statement in the sum for loop is printing. The amount of stuff that print statement manages to print out before being cut off changes every time the program is run. This test has random strings of numbers as input, so the input changes each time. The error usually occurs when i approaches maxlen, but i can sometimes be 30-40 less than maxlen.
In your function you allocate ret in this line:
ret = (char *) malloc((maxlen+2) * sizeof(char));
you then return ret at the end of your function, presumably to be freed by the caller.
However within your function you also have these lines:
// remove preceeding zeros
while (*ret == '0' && *(ret+1) != '\0')
ret++;
This means that the the ret you are returning no longer has the same pointer value as the one you received from malloc. Then when you call free in the caller the free function doesn't know what the pointer is.
One way to fix this is to find a different way to remove leading zeros, one that doesn't change the value of ret.
These don't have room for the null terminator:
char s1[maxlen], s2[maxlen];
which makes your program write out of bounds and have undefined behavior, so make them:
char s1[maxlen+1], s2[maxlen+1];
And here you change ret, making it impossible for a user to free the malloced memory:
while (*ret == '0' && *(ret+1) != '\0')
ret++;
instead, move the part of the string that you want to keep:
char *tmp = ret;
while (*tmp == '0' && tmp[1] != '\0') tmp++;
memmove(ret, tmp, maxlen-(tmp-ret)+2);
Another detail: You declare ret as static which only makes it unsafe to use the function in a multithreaded program. It does not provide any benefits at all. Just make it:
char *ret;
Another possible improvement would be to not allocate s1 and s2 at all, but to read directly from a and b and to skip leading zeroes before doing the calculation. Example:
#define SWAP(type, x, y) \
do { \
type tmp = x; \
x = y; \
y = tmp; \
} while (0)
char *strsum(const char *a, const char *b) {
while(*a == '0' && a[1] != '\0') ++a; // skip leading zeroes
while(*b == '0' && b[1] != '\0') ++b; // skip leading zeroes
size_t lena = strlen(a);
size_t lenb = strlen(b);
if (lena == 0 || lenb == 0) return NULL;
if (lena < lenb) { // make `a` the longest string
SWAP(const char *, a, b);
SWAP(size_t, lena, lenb);
}
char *ret = malloc(lena + 2); // may add one digit + null terminator
ret[lena + 1] = '\0'; // null terminate the result
int carry = 0;
size_t i = 1;
// loop while both `b` and `a` have digits:
for (; i <= lenb; ++i) {
int sum = carry + (a[lena - i] - '0') + (b[lenb - i] - '0');
ret[lena - i + 1] = (sum % 10) + '0';
carry = sum / 10;
}
// loop while only `a` has digits:
for (; i <= lena; ++i) {
int sum = carry + (a[lena - i] - '0');
ret[lena - i + 1] = (sum % 10) + '0';
carry = sum / 10;
}
// if no carry, move everything one step to the left:
if (carry == 0) memmove(ret, ret + 1, lena + 2 - 1);
else ret[0] = carry + '0'; // carry goes to the first position
return ret;
}
Demo

problem in comparing string to a integer i guess

This code is not working, how many times the number 0 to 9 is repeated in a given string.
This is the question, itis from hackerrank:
Given a string, S, consisting of alphabets and digits, find the frequency of each digit in the given string.
I can't find any error in my logic.
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
int main()
{
/* Enter your code here. Read input from STDIN. Print output to STDOUT */
char s[1000];
int count[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
char temp;
scanf("%s", s);
for (int i = 0; i < 10; i++)
{
temp = i;
for (int j = 0; j < strlen(s); j++)
{
if (s[j] == i)
{
count[i] = count[i] + 1;
continue;
}
else
{
continue;
}
}
}
for (int k = 0; k < 10; k++)
{
printf("%d ", count[k]);
}
return 0;
}
At least you need to write
if (s[j] == i + '0')
Otherwise you are trying to compare a character like '0' that can have the ASCII code 48 with integer 0.
But in any case the for loops are inefficient.
It is better to write:
for (const char *p = s; *p; ++p)
{
if ('0' <= *p && *p <= '9') ++count[*p - '0'];
}
You are comparing a character to an integer. Now, char is a numeric type, so you can do this, but the results are not what you expect. The character '0' in ASCII is 48, for example.
You can convert 0 or 1 or any other single digit to its ASCII representation, by adding it to '0'.
if (s[j] == i) => here s is defined as a character and i is defined as an integer. So to solve this problem you have to convert your integer to a character. sprintf() could work or a simple +'0'.

More elegant way of searching for pattern in this uint8 array

I am using C language in an embedded system. I have this uint8 array.
static uint8_t data_array[20];
Content of data_array is terminated with '\n'.
I want to check whether the first 3 bytes are "ABC". This is how I do it.
if (data_array[0]=='A' && data_array[1]=='B' && data_array[2]=='C')
{
printf("pattern found\n");
}
Are there more elegant ways to detect the pattern? My method can be cumbersome if the pattern consists of 10 bytes.
Just use a loop:
static uint8_t data_array[20] = "ABC";
static uint8_t s[4] = "ABC";
static uint8_t length = 3;
uint8_t bool = 1;
for (int i = 0; i < length; i++) {
if (s[i] != data_array[i]) {
bool = 0;
break;
}
}
if (bool) {
printf("pattern found\n");
}
Live code here
What about strncmp()?
static uint8_t data_array[20];
if(strncmp(data_array, "ABC", 3) == 0)
{
printf("pattern found\n");
}
char small='a' ,big='A';
int i=0;
char arr[10];
//To check
for(i; i<10 ; i++)
{
if(arr[i]==small || arr[i]==big)
{
//what you want to do
}
small++;
big++;
}
You can utilize macros to generate code similar to your:
#include <stdio.h>
#define TEST_FIRST_1(arr, c0) ((c0) == *(arr))
#define TEST_FIRST_2(arr, c0, ...) (TEST_FIRST_1(arr, c0) && TEST_FIRST_1((arr) + 1, __VA_ARGS__))
#define TEST_FIRST_3(arr, c0, ...) (TEST_FIRST_1(arr, c0) && TEST_FIRST_2((arr) + 1, __VA_ARGS__))
#define TEST_FIRST_4(arr, c0, ...) (TEST_FIRST_1(arr, c0) && TEST_FIRST_3((arr) + 1, __VA_ARGS__))
#define TEST_FIRST_5(arr, c0, ...) (TEST_FIRST_1(arr, c0) && TEST_FIRST_4((arr) + 1, __VA_ARGS__))
/* continue, if need */
static unsigned char data[30] = {
1,2,3,4,5,6,7,8,9,10,11,12,13,
};
int main(int argc, char **argv)
{
/* true cases */
printf("%d\n", TEST_FIRST_1(data, 1));
printf("%d\n", TEST_FIRST_2(data, 1, 2));
printf("%d\n", TEST_FIRST_3(data, 1, 2, 3));
printf("%d\n", TEST_FIRST_4(data, 1, 2, 3, 4));
printf("%d\n", TEST_FIRST_5(data, 1, 2, 3, 4, 5));
/* false cases */
printf("%d\n", TEST_FIRST_5(data, 0, 0, 0, 0, 0));
printf("%d\n", TEST_FIRST_4(data, 0, 0, 0, 0));
printf("%d\n", TEST_FIRST_3(data, 0, 0, 0));
return 0;
}
It may appear to be not clean at first look, but anyway doesn't lead to creating of an extra string literals for pattern to compare with.

Find product of 5 consecutive integer in C

I'm trying to calculate the product of 5 consecutive integer, but the result the completely wrong. I think my logic is correct, but why it shows me an unreal number: 344362200
The sequence number is from 1 to 10, code is below (just for testing only):
void problem8()
{
char *input = "123456789";
char c;
int step = 5, i = 0, prod = 0, temp = 1;
for (; i < step; i++)
{
temp *= *(input + i);
printf("%d\n", temp);
}
}
The output is really weird! At the first loop, the result is 42 ## while it should be 1, and 1 only. I checked individual result from *(input + 0) or 1 2 4 etc., it's correct. But the product is wrong.
You need to distinguish between the codes for the digits (48 for '0', 49 for '1', etc), and the numbers 1, 2, etc. You should be getting 49 on the first iteration; indeed, I get:
49
2450
124950
6497400
344362200
If you want the first 5 factorials, you'll need to use temp *= input[i] - '0'; (where input[i] is neater than *(input + i), IMNSHO).
The codes I gave are valid for code sets such as ISO 8859-1, and also UTF-8, and many other related code sets. They're not valid for EBCDIC, though.
The problem is that you are converting a char to an int, and not taking into account the ASCII offsets in the ASCII table. Integers start at hex 0x30 for ASCII.
#include <stdio.h>
#include <string.h>
int multiplyFiveSingleDigitNumbersInAString (const char* input, size_t inputLength);
int main(void) {
int tmp = 0;
const char* buf = "12345"; /* Create null-terminated string */
tmp = multiplyFiveSingleDigitNumbersInAString(buf, strlen(buf));
printf("Result of calculation for string %s is %d\n", buf, tmp);
return 0;
}
int multiplyFiveSingleDigitNumbersInAString (const char* input, size_t inputLength) {
if (inputLength != 5) {
printf("Wrong string length (%d), should be %d\n", (int)inputLength, 5);
return 0;
}
int i;
int multiSum = 1;
for (i=0; i<inputLength; i++) {
multiSum *= (int)input[i] - 0x30;
}
return multiSum;
}
References
ASCII Table, Accessed 2014-04-08, <http://www.asciitable.com/>
IMO, the other answers approach this backwards. Simply don't use chars when you want ints. Just change
char *input = "123456789";
to
int input = { 1, 2, 3, 4, 5 };
and your code will work.
P.S. Here's a solution to the actual problem:
char digits[] = "731...";
int main(void)
{
int max = 0;
for (int len = sizeof digits - 1, i = 0; i < len - 4; i++)
{
int prod = 1;
for (int j = 0; j < 5; j++)
prod *= digits[i + j] - '0';
if (max < prod) max = prod;
}
printf("%d\n", max);
return 0;
}

Convert hex string to string of bytes

I need to convert a (potentially very long) string like char * s = "2f0a3f" into the actual bytes it represents, when decoded from the hex representation. Currently I'm doing this, but it feels clunky and wrong.
size_t hexlength = strlen(s);
size_t binlength = hexlength / 2;
unsigned char * buffer = malloc(binlength);
long i = 0;
char a, b;
for (; i < hexlength; i += 2) {
a = s[i + 0]; b = s[i + 1];
buffer[i / 2] =
((a < '9' ? a - '0' : a - 'a' + 10) << 4) + (b < '9' ? b - '0' : b - 'a' + 10);
}
Two things strike me as ugly about this:
The way I'm dividing by two each time I push into the buffer
The conditional logic to figure out the decimal value of the hex digits
Is there a better way? Preferably not using something I'd have to add a dependency on (since I want to ship this code with minimal cross-platform issues). My bitwise math is awful ;)
NOTE: The data has been pre-validated to all be lowercase and to be a correct string of hex pairs.
/* allocate the buffer */
char * buffer = malloc((strlen(s) / 2) + 1);
char *h = s; /* this will walk through the hex string */
char *b = buffer; /* point inside the buffer */
/* offset into this string is the numeric value */
char xlate[] = "0123456789abcdef";
for ( ; *h; h += 2, ++b) /* go by twos through the hex string */
*b = ((strchr(xlate, *h) - xlate) * 16) /* multiply leading digit by 16 */
+ ((strchr(xlate, *(h+1)) - xlate));
Edited to add
In 80x86 assembly lanugage, the heart of strchr() is basically one instruction - it doesn't loop.
Also: this does no bounds checking, won't work with Unicode console input, and will crash if passed an invalid character.
Also: thanks to those who pointed out some serious typos.
Not that it'd make much difference, but I'd go with a multiplication over a division. Also it's worth splitting out the digit code, as you might want to port it to a platform where a-f are not adjacent in the character set (only joking!)
inline int digittoint(char d) {
return ((d) <= '9' ? (d) - '0' : (d) - 'a' + 10);
}
#define digittoint(d) ((d) <= '9' ? (d) - '0' : (d) - 'a' + 10)
size_t hexlength = strlen(s);
size_t binlength = hexlength / 2;
unsigned char * buffer = malloc(binlength);
long i = 0;
char a, b;
for (; i < binlength; ++i) {
a = s[2 * i + 0]; b = s[2 * i + 1];
buffer[i] = (digittoint(a) << 4) | digittoint(b);
}
I've fixed a bug in your digit-to-int implementation, and replaced the + with bitwise or on the grounds that it better expresses your intent.
You can then experiment to find the best implementation of digittoint - conditional arithmetic as above, strspn, or a lookup table.
Here's a possible branchless implementation that - bonus! - works on uppercase letters:
inline int digittoint(char d) {
return (d & 0x1f) + ((d >> 6) * 0x19) - 0x10;
}
Try something like this:
const unsigned char bin[128] =
{
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
};
int hexlength = strlen(s);
int binlength = (hexlength / 2);
unsigned char * buffer = (unsigned char *) malloc(binlength);
if (buffer)
{
char *hex = s;
unsigned char *buf = buffer;
unsigned char b, c;
int ok = 1;
for (int i = 0; i < hexlength; i += 2)
{
b = bin[*hex++];
c = bin[*hex++];
if ((b == -1) || (c == -1))
{
ok = 0;
break;
)
*buf++ = ((b << 4) | c);
}
if (ok == 1)
{
// use buffer as needed, up to binlength number of bytes...
}
free(buffer);
}
If you need your number (in a string) converted from hex to decimal, you may use atol() with sprintf()
If you need to do it byte-by-byte, you can buffer each byte, and as each buffer is filled, pass it through sprintf as such:
char *hexRep;
char *decRep;
long int decVal;
...
decVal = atol(hexRep);
sprintf(decRep, "%u", decVal);
Both of these are in C's standard library. After you get the string representation of each byte, you could just concatenate them together with strcat().
Here some small improvements to be MISRA complience. The name was confusing.
static inline uint8_t HexcharToInt(char c) {
char result = 16;
if (('0' <= c) && (c <= '9')) {
result = c - '0';
} else if (('a' <= c) && (c <= 'f')) {
result = c + 10 - 'a';
} else if (('A' <= c) && (c <= 'F')) {
result = c + 10 - 'A';
}
return (uint8_t) result;
}
uint8_t *array = NULL;
size_t hexstringToArray(char *hexstring) {
size_t len = (strlen(hexstring) + 1) / 2; // Aufrunden
if (array != NULL) {
free(array);
array = NULL;
}
array = (uint8_t*) malloc(len);
uint8_t *arr = array;
for (size_t i = 0; (i < len) && (len > 0); i++) {
*arr = 0U;
for (uint8_t shift = 8U; (shift > 0U) && (len > 0); ) {
shift -= 4U;
uint8_t curInt = HexcharToInt(*hexstring++);
if (curInt >= 16U) {
len = 0;
} else {
*arr |= ((uint8_t) curInt << shift);
}
}
arr++;
}
return len;
}
I came up with a simpler function that gets the string and copies byte by byte the conversion result to a byte array for a given N size with boundary and integrity check:
int8_t convert_str_to_bytes(uint8_t *byte_array, char* str, size_t n)
{
char *hex_match = "0123456789ABCDEF";
int i, j = 0;
char cbuf[3];
long ibuf;
if (strlen(str) < n) {
printf("ERROR: String is shorter than specified size.\n");
return -1;
}
for (i = 0; i < n; i += 2) {
strncpy(cbuf, &str[i], 2);
if (strspn(cbuf, hex_match) != 2) {
printf("ERROR: String is not a hexadecimal representation. Breaking now...\n");
return -1;
}
ibuf = strtol(cbuf, NULL, 16);
byte_array[j] = (uint8_t)ibuf;
++j;
}
return 0;
}
inline char HexToChar(char c)
{
if ('0' <= c && c <= '9')
{
return c - '0';
}
else if ('a' <= c && c <= 'f')
{
return c + 10 - 'a';
}
else if ('A' <= c && c <= 'F')
{
return c + 10 - 'A';
}
return -1;
}
size_t HexToBinrary( const char* hex, size_t length, char* binrary, size_t binrary_cap )
{
if (length % 2 != 0 || binrary_cap < length / 2)
{
return 0;
}
memset(binrary, 0, binrary_cap);
size_t n = 0;
for (size_t i = 0; i < length; i += 2, ++n)
{
char high = HexToChar(hex[i]);
if (high < 0)
{
return 0;
}
char low = HexToChar(hex[i + 1]);
if (low < 0)
{
return 0;
}
binrary[n] = high << 4 | low;
}
return n;
}

Resources