i took the code from the links below to encrypt and decrypt a text
but i get segmentation fault when trying to run this any ideas??
http://etutorials.org/Programming/secure+programming/Chapter+4.+Symmetric+Cryptography+Fundamentals/4.5+Performing+Base64+Encoding/
http://etutorials.org/Programming/secure+programming/Chapter+4.+Symmetric+Cryptography+Fundamentals/4.6+Performing+Base64+Decoding/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
static char b64revtb[256] = {
-3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*0-15*/
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*16-31*/
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, /*32-47*/
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -2, -1, -1, /*48-63*/
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /*64-79*/
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, /*80-95*/
-1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /*96-111*/
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, /*112-127*/
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*128-143*/
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*144-159*/
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*160-175*/
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*176-191*/
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*192-207*/
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*208-223*/
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*224-239*/
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /*240-255*/
};
unsigned char *spc_base64_encode( unsigned char *input
, size_t len
, int wrap ) ;
unsigned char *spc_base64_decode(unsigned char *buf, size_t *len, int strict,
int *err);
static unsigned int raw_base64_decode(unsigned char *in, unsigned char *out,
int strict, int *err);
unsigned char *tmbuf = NULL;
static char tmpbuffer[] ={0};
int main(void)
{
memset( tmpbuffer, NULL, sizeof( tmpbuffer ) );
sprintf( tmpbuffer, "%s:%s" , "username", "password" );
tmbuf = spc_base64_encode( (unsigned char *)tmpbuffer , strlen( tmpbuffer ), 0 );
printf(" The text %s has been encrytped to %s \n", tmpbuffer, tmbuf );
unsigned char *decrypt = NULL;
int strict;
int *err;
decrypt = spc_base64_decode( tmbuf , strlen( tmbuf ), 0, err );
printf(" The text %s has been decrytped to %s \n", tmbuf , decrypt);
}
static char b64table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
/* Accepts a binary buffer with an associated size.
* Returns a base64 encoded, NULL-terminated string.
*/
unsigned char *spc_base64_encode(unsigned char *input, size_t len, int wrap) {
unsigned char *output, *p;
size_t i = 0, mod = len % 3, toalloc;
toalloc = (len / 3) * 4 + (3 - mod) % 3 + 1;
if (wrap) {
toalloc += len / 57;
if (len % 57) toalloc++;
}
p = output = (unsigned char *)malloc(((len / 3) + (mod ? 1 : 0)) * 4 + 1);
if (!p) return 0;
while (i < len - mod) {
*p++ = b64table[input[i++] >> 2];
*p++ = b64table[((input[i - 1] << 4) | (input[i] >> 4)) & 0x3f];
*p++ = b64table[((input[i] << 2) | (input[i + 1] >> 6)) & 0x3f];
*p++ = b64table[input[i + 1] & 0x3f];
i += 2;
if (wrap && !(i % 57)) *p++ = '\n';
}
if (!mod) {
if (wrap && i % 57) *p++ = '\n';
*p = 0;
return output;
} else {
*p++ = b64table[input[i++] >> 2];
*p++ = b64table[((input[i - 1] << 4) | (input[i] >> 4)) & 0x3f];
if (mod = = 1) {
*p++ = '=';
*p++ = '=';
if (wrap) *p++ = '\n';
*p = 0;
return output;
} else {
*p++ = b64table[(input[i] << 2) & 0x3f];
*p++ = '=';
if (wrap) *p++ = '\n';
*p = 0;
return output;
}
}
}
static unsigned int raw_base64_decode(unsigned char *in, unsigned char *out,
int strict, int *err) {
unsigned int result = 0, x;
unsigned char buf[3], *p = in, pad = 0;
*err = 0;
while (!pad) {
switch ((x = b64revtb[*p++])) {
case -3: /* NULL TERMINATOR */
if (((p - 1) - in) % 4) *err = 1;
return result;
case -2: /* PADDING CHARACTER. INVALID HERE */
if (((p - 1) - in) % 4 < 2) {
*err = 1;
return result;
}
else if (((p - 1) - in) % 4 == 2)
{
/* Make sure there's appropriate padding */
if (*p != '=') {
*err = 1;
return result;
}
buf[2] = 0;
pad = 2;
result++;
break;
} else {
pad = 1;
result += 2;
break;
}
case -1:
if (strict) {
*err = 2;
return result;
}
break;
default:
switch (((p - 1) - in) % 4) {
case 0:
buf[0] = x << 2;
break;
case 1:
buf[0] |= (x >> 4);
buf[1] = x << 4;
break;
case 2:
buf[1] |= (x >> 2);
buf[2] = x << 6;
break;
case 3:
buf[2] |= x;
result += 3;
for (x = 0; x < 3 - pad; x++) *out++ = buf[x];
break;
}
break;
}
}
for (x = 0; x < 3 - pad; x++) *out++ = buf[x];
return result;
}
/* If err is non-zero on exit, then there was an incorrect padding error. We
* allocate enough space for all circumstances, but when there is padding, or
* there are characters outside the character set in the string (which we are
* supposed to ignore), then we end up allocating too much space. You can
* realloc() to the correct length if you wish.
*/
unsigned char *spc_base64_decode(unsigned char *buf, size_t *len, int strict,
int *err) {
unsigned char *outbuf;
outbuf = (unsigned char *)malloc(3 * (strlen(buf) / 4 + 1));
if (!outbuf) {
*err = -3;
*len = 0;
return 0;
}
*len = raw_base64_decode(buf, outbuf, strict, err);
if (*err) {
free(outbuf);
*len = 0;
outbuf = 0;
}
return outbuf;
}
tmpbuffer is not properly defined/allocated.
static char tmpbuffer[] ={0};
produces a buffer which can contain only 1 character, but
sprintf( tmpbuffer, "%s:%s" , "username", "password" );
attempts to write many more bytes...
Further inspection of the code shows other errors...
unsigned char *spc_base64_decode(unsigned char *buf, size_t *len, int strict, int *err)
Note how the 2nd arg is a pointer to size_t, yet it is passed...
decrypt = spc_base64_decode( tmbuf , strlen( tmbuf ), 0, err );
an immediate value... Oops...
Related
is there a way to make this code shorter?
// Points assigned to each letter of the alphabet
int compute_score(string word);
int main(void)
{
// Get input words from both players
string word1 = get_string("Player 1: ");
string word2 = get_string("Player 2: ");
// Score both words
int score1 = compute_score(word1);
int score2 = compute_score(word2);
// TODO: Print the winner
if (score1 > score2)
{
printf("Player 1 wins!\n");
}
else if (score1 < score2)
{
printf("Player 2 wins!\n");
}
else
{
printf("Tie!\n");
}
}
the calculator function
I Haved to definition character is uppercase or lower in different loops and i think i can make that in one loop but i don't know how :)
int compute_score(string word)
{
int points[] = {1, 3, 3, 2, 1, 4, 2, 4, 1, 8, 5, 1, 3, 1, 1, 3, 10, 1, 1,1, 1, 4, 4, 8, 4, 10};
int len = strlen(word);
int i = 0;
int total = 0;
for (i = 0; i <= len; i++)
{
if (word[i] >= 65 && word[i] <= 90)
{
int ascii = word[i];
int toasc = ascii - 65;
total += (points[toasc]);
}
}
int ii = 0;
int totall = 0;
for (ii = 0; ii <= len; ii++)
{
if (word[ii] >= 97 && word[ii] <= 122)
{
int asciii = word[ii];
int toascc = asciii - 97;
totall += (points[toascc]);
}
}
int totalf = total + totall;
return totalf;
}
you can try something like this:
int compute_score(string word) {
int total = 0;
int points[] = {1, 3, 3, 2, 1, 4, 2, 4, 1, 8, 5, 1, 3, 1, 1, 3, 10, 1, 1,1, 1, 4, 4, 8, 4, 10};
int len = strlen(word);
for (i = 0; i < len; i++)
if (word[i] >= 'A' && word[i] <= 'Z')
total += points[word[i] - 'A'];
else if (word[i] >= 'a' && word[i] <= 'z')
total += points[word[i] - 'a'];
return total;
}
Normalizing the current letter to upper case which allows a fixed 'A' to be used to determine the offset into the points array. Consider changing the type of point from int to static const char [] for correctness.
#include "cs50.h"
#include <assert.h>
#include <ctype.h>
#include <stdlib.h>
#define PLAYERS 2
int compute_score(string word) {
int points[] = {1, 3, 3, 2, 1, 4, 2, 4, 1, 8, 5, 1, 3, 1, 1, 3, 10, 1, 1,1, 1, 4, 4, 8, 4, 10};
int total = 0;
for (; *word; word++)
total += isalpha(*word) ? points[toupper(*word) - 'A'] : 0;
return total;
}
int main(void) {
int scores[PLAYERS];
for(size_t i = 0; i < PLAYERS; i++) {
scores[i] = compute_score(get_string("Player %d: ", i + 1));
}
// TBD: generalize print of winners
static_assert(PLAYERS == 2);
if (scores[0] > scores[1]) {
printf("Player 1 wins!\n");
} else if (scores[0] < scores[1]) {
printf("Player 2 wins!\n");
} else {
printf("Tie!\n");
}
}
If you want to generalize the print of winners then it's more direct to just remember who the winners are as you go along. For example:
#include <string.h>
// ...
int main(void) {
int max_score = -1;
char winners[PLAYERS];
for(size_t i = 0; i < PLAYERS; i++) {
int score = compute_score(get_string("Player %d: ", i + 1));
if(score > max_score)
memset(winners, 0, sizeof(winners));
if(score >= max_score)
winners[i] = 1;
}
printf("Winner(s)");
for(size_t i = 0; i < PLAYERS; i++) {
if(winners[i]) printf(" %d", i + 1);
}
printf("\n");
}
You demonstrate that you know strings are arrays of characters (with a null terminator on the end).
The following uses a "purpose-built" array that stores the points of both upper and lowercase ASCII alphabet characters.
#include <stdio.h>
int compute_score( string word ) {
char tbl[] = { // small values fit into one byte
0, 1, 3, 3, 2, 1, 4, 2, 4, 1, 8, 5, 1, 3, 1, 1,
3, 10, 1, 1, 1, 1, 4, 4, 8, 4, 10, 0, 0, 0, 0, 0,
0, 1, 3, 3, 2, 1, 4, 2, 4, 1, 8, 5, 1, 3, 1, 1,
3, 10, 1, 1, 1, 1, 4, 4, 8, 4, 10, 0, 0, 0, 0, 0,
};
int points = 0;
for( int i = 0; word[ i ]; i++ ) { // each letter of the word
int c = word[i] - '#'; // transpose down to range 0-63
if( 0 < c && c < 4*16 ) // if still in range...
points += tbl[ c ]; // then retrieve point value of this letter
}
return points;
}
int main() { // A simple test program with a few words.
string str;
str = "Hello"; printf( "'%s' %2d pts\n", str, compute_score( str ) );
str = "world"; printf( "'%s' %2d pts\n", str, compute_score( str ) );
str = "quiz "; printf( "'%s' %2d pts\n", str, compute_score( str ) );
return 0;
}
Output
'Hello' 8 pts
'world' 9 pts
'quiz ' 22 pts
EDIT: To use an even smaller "look-up table", invoke a little "modulo arithmetic"...
int compute_score( string word ) {
// point values are arrayed correspondint to ASCII character positions
uint8_t tbl[] = {
0, 1, 3, 3, 2, 1, 4, 2, 4, 1, 8, 5, 1, 3, 1, 1,
3, 10, 1, 1, 1, 1, 4, 4, 8, 4, 10, 0, 0, 0, 0, 0,
};
int points = 0;
for( int i = 0; word[ i ]; i++ )
if( word[ i ] >= 'A' )
points += tbl[ word[ i ] % 32 ];
return points;
}
EDIT2: Since we only want the look-up value for the upper two (alphabetic) ranges of the 7-bit ASCII table, AND C guarantees that the truth value of a condition will be either 0 (false) or 1 (true), the code could be made more contemporary using a "branchless programming" technique.
for( int i = 0; word[ i ]; i++ )
points += (word[i] >= 'A') * tbl[ word[ i ] % 32 ];
For other ASCII characters like digits or SP, the condition is false so no points are awarded. For characters in the right range, the points value is multiplied by 1 (the multiplication identity value).
Eventually, one's entire program can be reduced to a few lines... :-)
EDIT3: Now, turning attention to main() and its role in running the competition. Below combines (and renames) the function and its parameters.
The primary difference in this code is to recognise that each 'round' starts with zero. Subtracting the two players' scores
will give a positive number, zero, or a negative number.
Eliminating intermediary variables, each player gets a turn, their score computed, and the difference calculated all in one statement.
Then an appropriate message displayed.
Because this is fun, a do/while() loop offers the opportunity to play again.
#include <stdio.h>
#include "cs50.h"
int score( string word ) {
char pts = 0, tbl[] = {
0, 1, 3, 3, 2, 1, 4, 2, 4, 1, 8, 5, 1, 3, 1, 1,
3, 10, 1, 1, 1, 1, 4, 4, 8, 4, 10, 0, 0, 0, 0, 0,
};
for( int i = 0; word[ i ]; i++ )
pts += (word[i] > 'A') * tbl[ word[ i ] % 32 ];
word[ i-1 ] = '\0'; // trim '\n' from end before printing
printf( "'%s' - %d points\n", word, pts );
return pts;
}
int main() {
do {
int diff
= score( get_string( "Player 1: " ) )
- score( get_string( "Player 2: " ) );
if( diff > 0 )
puts( "\nPlayer 1 wins!" );
else if( diff < 0 )
puts( "\nPlayer 2 wins!" );
else
puts( "\nTie!");
} while( get_int( "\nPlay again? (0-yes otherwise ending)" ) == 0 );
return 0;
}
Output
Player 1: house
'house' - 8 points
Player 2: car
'car' - 5 points
Player 1 wins!
Play again? (0-yes otherwise ending)0
Player 1:
Alternative main() using trenary "conditional operator":
int main() {
do {
int diff
= score( get_string( "Player 1: " ) )
- score( get_string( "Player 2: " ) );
puts( diff > 0 ? "\nPlayer 1 wins!" : diff < 0 ? "\nPlayer 2 wins!" : "\nTie!" );
} while( get_int( "\nPlay again? (0-yes otherwise ending)" ) == 0 );
return 0;
}
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
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
}
When I run this, ageProgMax comes out as 29 instead of what I want, 60. I did this for the smallest number of cafes that analysts drink and it worked but somehow this one doesn't.
int main()
{
char poste[] ={'P', 'P', 'O', 'A', 'P', 'A', 'P', 'P'};
int nbCafe[] ={5, 1, 3, 0, 5, 1, 0, 2};
int age[] ={25, 19, 27, 22, 49, 24, 60, 29};
int nbPers = sizeof(age) / sizeof(int);
int i;
int ageProgMax = 0;
for (i = 0; i < nbPers; i++)
if (poste[i] =='P' || age[i] > ageProgMax)
{
ageProgMax = age[i];
}
printf ("Max age of programmers : %d\n", ageProgMax);
return 0;
}
Any help?
Thanks
It's because of the || in your condition. Look at the condition you have set i.e. if (poste[i] =='P' || (age[i] > ageProgMax)). It says to store new value to ageProgMax if either of (age[i] > ageProgMax) or poste[i] =='P' becomes true. So for the last entry i.e. 29 even though (age[i] > ageProgMax) is false, the poste[i] =='P' is true and causes the overwrite of the ageProgMax's 60 with that of 29.
You can correct your program like this.
int main()
{
char poste[] ={'P', 'P', 'O', 'A', 'P', 'A', 'P', 'P'};
int nbCafe[] ={5, 1, 3, 0, 5, 1, 0, 2};
int age[] ={25, 19, 27, 22, 49, 24, 60, 29};
int nbPers = sizeof(age) / sizeof(int);
int i;
int ageProgMax = 0;
for (i = 0; i < nbPers; i++)
{
if (poste[i] =='P' && (age[i] > ageProgMax))
{
ageProgMax = age[i];
}
}
printf ("Max age of programmers : %d\n", ageProgMax);
return 0;
}
#define MAX(a,b) ((*(a)) > (*(b)) ? (a) : (b))
int *largest(int *arr, size_t size)
{
int *result = NULL;
if(arr && size)
{
if(size == 1)
{
retult = *arr;
}
else
{
result = MAX(arr, arr + 1)
arr += 2;
size -= 2;
while(size--)
{
result = MAX(result, arr);
arr++;
}
}
}
return result;
}
Returns NULL on error or pointer to the largest int.
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;
}