Adding operation between two Big numbers by only using C - c

What I want to try is Adding two big numbers under 600 digits.
So I making a struct in C.
But there is some error in the source below.
(The environment of practice is GCC Compiler, and Linux. The tool is VSCode with BASH Terminal.)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#define MAX_SIZE 600
#define SWAP(x,y,t) ((t)=(x), (x)=(y), (y)=(t)) //SWAP preprocessor
#define D_C(x) (x==0 ? 0 : x+'0') //Convert Decimal to Character
#define C_D(x) (x==0 ? 0 : x-'0') //Convert Character to Decimal
/*The structure to save BIG NUMBER*/
typedef struct _BIG_DECIMAL{
unsigned char *data;
int size;
} BIG_DECIMAL;
/*Make string reverse*/
void reverseString(char* s, size_t size) {
char temp;
for (size_t i = 0; i < size / 2; i++) SWAP(s[i], s[(size - 1) - i], temp);
}
/*Create Decimal data in BIG_DECIMAL struct*/
BIG_DECIMAL * createDecimal(unsigned char *str) {
//local variables in func.
size_t size_str;
BIG_DECIMAL * number = malloc(sizeof(BIG_DECIMAL));
//save str in buffer
char buffer[MAX_SIZE] = {'\0',};
strcpy(buffer, str);
//temporary value for size measure.
size_str = strlen(buffer);
printf("%d", size_str);
//Save reversed number data.
reverseString(buffer, size_str);
strcpy(number->data, buffer);
//Save size.
number->size = size_str;
//Return BIG_DECIMAL struct.
return number;
}
/*ADDITION BETWEEN TWO BIG NUMBERS. left argument's size value should be big.*/
BIG_DECIMAL * BD_addition(BIG_DECIMAL *dec1, BIG_DECIMAL *dec2) {
//local variable in this func.
int carry = 0;
BIG_DECIMAL *result = malloc(sizeof(BIG_DECIMAL));
//Adding loop start
for(int i = 0; i < (result -> size); i++) {
int digit_plus;
//if start
if(i < dec2->size) {
//there are digit in both dec so...
digit_plus = C_D(dec1->data[i]) + C_D(dec2->data[i]) + carry;
//nested-if start
if(digit_plus > 10) { //if the carry is occured
carry = digit_plus / 10; //carry can be (> 1)
result->data[i] = D_C(digit_plus % 10);
}
else { //if the carry is not occcured
carry = digit_plus / 10; //carry can be (> 1)
result->data[i] = D_C(digit_plus % 10);
}
//nested-if end
}
else if((i >= (dec2->size)) && (i < ((result->size)-1))){
digit_plus = C_D(dec1->data[i]) + carry;
//nested-if start
if(digit_plus > 10) { //if the carry is occured
carry = digit_plus / 10;
result->data[i] = D_C(digit_plus % 10);
}
else { //if the carry is not occcured
carry = 0;
result->data[i] = D_C(digit_plus);
}
//nested-if end
}
else { //if i == (result->size)-1 (the last index of result->data)
//nested-if start
if(carry > 0) result->data[i] = D_C(carry); //if carry occured
else { //if the carry doesn't occure in the last index of result->data
result->data[i] = D_C(0); //the last index value of result->data is NULL.
--(result->size); //result size - 1
}
//nested-if end
}
//if end
}
//Adding loop end
return result;
}
int main() {
/*data for operand*/
BIG_DECIMAL * op1;
BIG_DECIMAL * op2;
/*data for result*/
BIG_DECIMAL * result;
op1 = createDecimal("123456789");
op2 = createDecimal("12345678");
result = BD_addition(op1,op2);
printf("%s", result->data);
/*DeAllocation*/
free(op1);
free(op2);
free(result);
return 0;
}
This code makes Segmentation fault error.
I think that it might be a string access error first, so I tried to type-casting all of the char* type variable but it doesn't work.

As pointer in comments, you can correct your code by allocating enough space for data, you can use strdup for this:
/*Create Decimal data in BIG_DECIMAL struct*/
BIG_DECIMAL * createDecimal(unsigned char *str) {
//local variables in func.
size_t size_str;
BIG_DECIMAL * number = malloc(sizeof(BIG_DECIMAL));
//save str in buffer
char buffer[MAX_SIZE] = {'\0',};
strcpy(buffer, str);
//temporary value for size measure.
size_str = strlen(buffer);
//Save reversed number data.
reverseString(buffer, size_str);
/* here: copy buffer in a new allocated memory stored in number->data. */
number->data = strdup(buffer);
//Save size.
number->size = size_str;
//Return BIG_DECIMAL struct.
return number;
}
And do not forget to free them correctly:
/*DeAllocation*/
free(op1->data);
free(op1);
free(op2->data);
free(op2);
There are stell some errors in your code: the beginning of BD_addition function should looks like:
BIG_DECIMAL * BD_addition(BIG_DECIMAL *dec1, BIG_DECIMAL *dec2) {
//local variable in this func.
int carry = 0;
BIG_DECIMAL *result = malloc(sizeof(BIG_DECIMAL));
/* compute the size of result */
result->size = (dec1->size < dec2->size) ? dec1->size : dec2->size;
/* take in account an eventual carry */
result->size += 1;
/* allocate */
result->data = malloc(result->size+1);
//Adding loop start
....
And your macro D_C does not seem valid (0 is not converted to '0').

If you like, this comes without struct, strdup, reverse etc. just one malloc.
#include <stdlib.h>
#define toI(x) ((x)-'0')
#define toC(x) ((x)+'0')
#define max(a,b) ((a)>(b)) ? (a):(b)
char *add(char *buf1, char *buf2) {
int size, v1, v2, r, carry=0;
char *ap1, *ep1, *ap2, *ep2, *ap3, *ep3, *rp, *result;
for(ep1=ap1=buf1; *ep1; ep1++);
for(ep2=ap2=buf2; *ep2; ep2++);
size=max(ep2-ap2, ep1-ap1);
ap3=ep3=rp=result=malloc(size+10);
ep3+=size+10;
rp=ep3-1;
*rp='\0';
for(ep1--, ep2--, rp--; ep1>=ap1 || ep2>=ap2; ep1--, ep2--, rp--) {
v1 = ep1>=ap1 ? toI(*ep1) : 0;
v2 = ep2>=ap2 ? toI(*ep2) : 0;
r = v1+v2+carry;
*rp=toC(r%10);
carry=r/10;
}
if(carry!=0) *rp-- = toC(carry);
for(rp++;rp<ep3; rp++, ap3++)
*ap3=*rp;
return result;
}
int main() {
char *result = add("123456789", "12345678");
printf("\n%s\n", result);
free(result);
}

Related

Memcpy in C causes STM to freeze after turning power off and on

I have a problem with STM32F401CCU. After executing a code disconnecting and connecting power the STM freezes and to unfreeze it I need to reload the build.
I have a complex set of functions that are used to turn an array of int values into a single very long char array. The char array is then written to the long term Flash memory. In order to execute that I do many operations with char arrays and they appear to be executed properly, as saving to Flash is done correctly - I tested Flash content with ST LINK and they are what they should be. But after turning power off/on to actually test if long term Flash memory works I encounter a fatal bug - upon powering STM back on it freezes and the only way to unfreeze it is to reload the build.
After many hours of tests I figured that the problem is with memcpy usage in StringCreateStrForFlashOneProduct. Presumably I created a sort of memory leak, but I don't get what's wrong.
A piece of example operation that causes STM to freeze:
static char send_save_string_final[2048];
char sssssend_char[2048] = "000000NewProduct";
char *StringCreateStrForFlashOneProduct(const int someint)
{
memcpy(sssssend_char, "000000008888008000000000888800800000000088880080", 48);
memcpy(send_save_string_final, sssssend_char, 48);
return send_save_string_final;
}
The code I actually use:
FUNCTION ONE - Creates a single array of chars and then saves it to flash memory
static char output_all_sorts[6001] = "";
char all_save_string[6001] = "";
char sssssend_char_all_sorts[2048] = "00000AllProducts";
char append_char_numz_all_sorts[17] = "0000000000000000";
void FlashSaveAllSorts(void)
{
strcpy(sssssend_char_all_sorts, "00000AllProducts");
sssssend_char_all_sorts[2047] = 0;
strcpy(output_all_sorts, "0");
output_all_sorts[6000] = 0;
strcpy(all_save_string, "00000AllProducts");
all_save_string[6000] = 0;
strcpy(append_char_numz_all_sorts, "0000000000000000");
append_char_numz_all_sorts[16] = 0;
for (int doin_int = 0; doin_int <= 6; doin_int++)
{
strcpy(sssssend_char_all_sorts, StringCreateStrForFlashOneProduct(doin_int));
strcat(all_save_string, sssssend_char_all_sorts);
strcpy(output_all_sorts, all_save_string);
}
strcpy(output_all_sorts, all_save_string);
output_all_sorts[strlen(output_all_sorts)] = 0;
Flash_Write_Data(0x08020000, output_all_sorts, 3000);
}
FUNCTION TWO - Creates a single line with all data for one product
static char send_save_string_final[2048] = "0";
char sssssend_char[2048] = "000000NewProduct";
char append_char_numz[17] = "0000000000000000";
char *StringCreateStrForFlashOneProduct(const int someint)
{
strcpy(send_save_string_final, "0");
send_save_string_final[2047] = 0;
strcpy(sssssend_char, "000000NewProduct");
sssssend_char[2047] = 0;
strcpy(append_char_numz, "0000000000000000");
append_char_numz[16] = 0;
strncpy(append_char_numz, StringCreateStringFromIntTwo(someint), 17);
append_char_numz[16] = 0;
strcat(sssssend_char, append_char_numz);
for (int kk = 0; kk < 3; kk = kk + 1)
{
char append_char_one[17] = "0000000000000000";
for (int jj = 0; jj < 12; jj = jj + 1)
{
char append_char[17] = "0000000000000000";
memcpy(append_char, StringCreateStringFromIntTwo(tunable_vars_machine_for_flash[someint][kk][jj]), 17);
strcat(sssssend_char, append_char);
}
memcpy(append_char_one, "000000000MenuEnd", 17);
strcat(sssssend_char, append_char_one);
}
char append_char_end_zeros[17] = "0000000000000000";
memcpy(append_char_end_zeros, StringCreateStringFromIntTwo(0), 17);
strcat(sssssend_char, append_char_numz);
memcpy(send_save_string_final, sssssend_char, 2047);
return send_save_string_final;
}
FUNCTION THREE - Creates a 16-chars array with a following format 000000000000001333, zeros are required to have consistent length of saved string, 1333 is example data value:
char *StringCreateStringFromIntTwo(int base_int_base)
{
//clearprint("StringCreateStri");
int base_int = base_int_base;
if (base_int == 0)
{
base_int = 999999; /// avoid saving zero to flash memory
}
static char send_char_final[17] = "0000000000000000";
char send_char[16] = "00000000";
static char send_char_sixteen_zeros[17] = "0000000000000000";
int legnewpigwphjh = strlen(send_char);
char str_zero[2] = "0";
char str_two_zeros[3] = "00";
char str_three_zeros[4] = "000";
char str_four_zeros[5] = "0000";
char str_five_zeros[6] = "00000";
char str_six_zeros[7] = "000000";
char str_seven_zeros[8] = "0000000";
char str_eight_zeros[9] = "00000000";
char str_sixteen_zeros[17] = "0000000000000000";
int int_mem_length = countDigits(base_int);
char str_mem_write_int[9];
sprintf(str_mem_write_int, "%d", base_int);
if (int_mem_length == 7)
{
strcat(send_char, str_zero);
}
if (int_mem_length == 6)
{
strcat(send_char, str_two_zeros);
}
if (int_mem_length == 5)
{
strcat(send_char, str_three_zeros);
}
if (int_mem_length == 4)
{
strcat(send_char, str_four_zeros);
}
if (int_mem_length == 3)
{
strcat(send_char, str_five_zeros);
}
if (int_mem_length == 2)
{
strcat(send_char, str_six_zeros);
}
if (int_mem_length == 1)
{
strcat(send_char, str_seven_zeros);
}
strcat(send_char, str_mem_write_int);
strcpy(send_char_final, str_sixteen_zeros);
strcpy(send_char_final, send_char);
return send_char_final;
}
Your code is way too complicated. There are too many string copies and concatenations, and countless useless operations. You do not seem to master pointers, nor basic memory layout concepts. Above all, given your skill level, you should absolutely avoid strncpy and memcpy.
Here is a simpler approach with functions that construct the appropriate string format at the end of the buffer and return the number of characters written. With this method, composing a long string is much simpler and much less error prone:
// function to construct a fixed length string of digits with leading 0s
// buffer must point to an array at least 17 bytes long
// returns the number of characters, ie: 16
int FormatNumber16(char *buffer, int someint) {
if (someint == 0) {
// This test seems bogus: the product number 0 will be written as 999999
// and so will the MenuEnd number
someint = 999999; // avoid writing 0 ???
}
return snprintf(buffer, 17, "%016d", someint);
}
// function to construct the product string to store to flash
// buffer must point to an array at least 641 bytes long
// returns the number of characters, ie: 640
int FormatOneProduct(char *buffer, int product_nb) {
int pos = 0;
pos += snprintf(buffer + pos, 17, "%016s", "NewProduct");
pos += FormatNumber16(buffer + pos, product_nb);
for (int kk = 0; kk < 3; kk++) {
for (int jj = 0; jj < 12; jj++) {
pos += FormatNumber16(buffer + pos,
tunable_vars_machine_for_flash[product_nb][kk][jj]);
}
}
pos += snprintf(buffer + pos, 17, "%016s", "MenuEnd");
// vvv this will actually append 0000000000999999 ?
pos += FormatNumber16(buffer + pos, 0);
// pos should be 640 = 16 + 16 + 12*3*16 + 16 + 16
return pos;
}
// function to write all product data to flash (7 products)
void FlashSaveAllSorts(void) {
char buffer[6001] = ""; // no need for global data
int pos = 0;
pos += snprintf(buffer + pos, 17, "%016s", "AllProducts");
// append the description of all 7 products (0 to 6 included)
for (int product_nb = 0; product_nb <= 6; product_nb++) {
pos += FormatOneProduct(buffer + pos, product_nb);
}
// buffer contains 4496 = 16 + 640*7 characters, why write 3000 bytes?
Flash_Write_Data(0x08020000, buffer, 3000);
}
Some example functions:
char *StringCreateStrForFlashOneProduct(char *buff, size_t len, int someint)
{
int mask = 1000000000;
char *wrk = buff;
if(!someint) someint = 999999;
memset(buff, '0', len - 10);
wrk += len - 10;
while(mask)
{
*wrk++ = '0' + abs(someint / mask);
someint %= mask;
mask /= 10;
}
*wrk = 0;
return buff;
}
example usage:
int main(void)
{
char str[17];
printf("`%s`\n", StringCreateStrForFlashOneProduct(str, 16, 1234));
}

How output a numbers with write() (only #include <unistd.h> allowed) [duplicate]

It is possible to convert integer to string in C without sprintf?
There's a nonstandard function:
char *string = itoa(numberToConvert, 10); // assuming you want a base-10 representation
Edit: it seems you want some algorithm to do this. Here's how in base-10:
#include <stdio.h>
#define STRINGIFY(x) #x
#define INTMIN_STR STRINGIFY(INT_MIN)
int main() {
int anInteger = -13765; // or whatever
if (anInteger == INT_MIN) { // handle corner case
puts(INTMIN_STR);
return 0;
}
int flag = 0;
char str[128] = { 0 }; // large enough for an int even on 64-bit
int i = 126;
if (anInteger < 0) {
flag = 1;
anInteger = -anInteger;
}
while (anInteger != 0) { 
str[i--] = (anInteger % 10) + '0';
anInteger /= 10;
}
if (flag) str[i--] = '-';
printf("The number was: %s\n", str + i + 1);
return 0;
}
Here's an example of how it might work. Given a buffer and a size, we'll keep dividing by 10 and fill the buffer with digits. We'll return -1 if there is not enough space in the buffer.
int
integer_to_string(char *buf, size_t bufsize, int n)
{
char *start;
// Handle negative numbers.
//
if (n < 0)
{
if (!bufsize)
return -1;
*buf++ = '-';
bufsize--;
}
// Remember the start of the string... This will come into play
// at the end.
//
start = buf;
do
{
// Handle the current digit.
//
int digit;
if (!bufsize)
return -1;
digit = n % 10;
if (digit < 0)
digit *= -1;
*buf++ = digit + '0';
bufsize--;
n /= 10;
} while (n);
// Terminate the string.
//
if (!bufsize)
return -1;
*buf = 0;
// We wrote the string backwards, i.e. with least significant digits first.
// Now reverse the string.
//
--buf;
while (start < buf)
{
char a = *start;
*start = *buf;
*buf = a;
++start;
--buf;
}
return 0;
}
Unfortunately none of the answers above can really work out in a clean way in a situation where you need to concoct a string of alphanumeric characters.There are really weird cases I've seen, especially in interviews and at work.
The only bad part of the code is that you need to know the bounds of the integer so you can allocate "string" properly.
In spite of C being hailed predictable, it can have weird behaviour in a large system if you get lost in the coding.
The solution below returns a string of the integer representation with a null terminating character. This does not rely on any outer functions and works on negative integers as well!!
#include <stdio.h>
#include <stdlib.h>
void IntegertoString(char * string, int number) {
if(number == 0) { string[0] = '0'; return; };
int divide = 0;
int modResult;
int length = 0;
int isNegative = 0;
int copyOfNumber;
int offset = 0;
copyOfNumber = number;
if( number < 0 ) {
isNegative = 1;
number = 0 - number;
length++;
}
while(copyOfNumber != 0)
{
length++;
copyOfNumber /= 10;
}
for(divide = 0; divide < length; divide++) {
modResult = number % 10;
number = number / 10;
string[length - (divide + 1)] = modResult + '0';
}
if(isNegative) {
string[0] = '-';
}
string[length] = '\0';
}
int main(void) {
char string[10];
int number = -131230;
IntegertoString(string, number);
printf("%s\n", string);
return 0;
}
You can use itoa where available. If it is not available on your platform, the following implementation may be of interest:
https://web.archive.org/web/20130722203238/https://www.student.cs.uwaterloo.ca/~cs350/common/os161-src-html/atoi_8c-source.html
Usage:
char *numberAsString = itoa(integerValue);
UPDATE
Based on the R..'s comments, it may be worth modifying an existing itoa implementation to accept a result buffer from the caller, rather than having itoa allocate and return a buffer.
Such an implementation should accept both a buffer and the length of the buffer, taking care not to write past the end of the caller-provided buffer.
int i = 24344; /*integer*/
char *str = itoa(i);
/*allocates required memory and
then converts integer to string and the address of first byte of memory is returned to str pointer.*/

Code to print the Longest Common Substring in C

I wrote the code to print the longest common substring in C language perogramming. When I run the code it says "segmentation core dumped". Please help me I want to know the problem because it was working at first and then it suddenly gave this error.
#include<string.h>
#include <stdio.h>
#define new_max(x,y) (((x) >= (y)) ? (x) : (y))
#define new_min(x,y) (((x) <= (y)) ? (x) : (y))
void LCSubStr(char *X, char *Y, int m, int n)
{
int LCSuff[m+1][n+1];
int result = 0;
int end;
for (int i=0; i<=m; i++)
{
for (int j=0; j<=n; j++)
{
if (i == 0 || j == 0)
LCSuff[i][j] = 0;
else if (X[i-1] == Y[j-1])
{
LCSuff[i][j] = LCSuff[i-1][j-1] + 1;
result = new_max(result, LCSuff[i][j]);
end = i - 1;
}
else{
LCSuff[i][j] = 0;
}
}
}
if(result = 0){
printf("No common substring");
}else{
char subbuff[5];
memcpy(subbuff, &X[end - result + 1], result);
subbuff[result] = '\0';
printf("%s",subbuff);
}
}
int main()
{
char X[] = "Sandile";
char Y[] = "andile";
int m = strlen(X);
int n = strlen(Y);
LCSubStr(X, Y, m, n);
return 0;
}
Instead of copying to a fixed length string, you can directly specify the length with printf.
char subbuff[5];
memcpy(subbuff, &X[end - result + 1], result);
subbuff[result] = '\0';
printf("%s",subbuff);
Instead, try:
printf("%.*s",result, &X[end-result+1])
(The '.*s' syntax uses a limit in the parameter list - the result or length of match in this case)
Also, be careful of =.
if(result = 0){
printf("No common substring");
It's traditional to reverse comparisons in C to avoid this typo.
if (0 == result) {
printf("No common substring");
I believe, in this statement
if(result = 0){
= is typo and you mean == i.e. if (result == 0) ....
Your program is accessing an array beyond its size, which is an undefined behaviour:
char subbuff[5];
memcpy(subbuff, &X[end - result + 1], result);
the size of subbuff is 5 and the size of longest common substring, for the given input (X = "Sandile" and Y = "andile"), is 6. The memcpy, while copying the bytes, end up accessing the array subbuff beyond its size. You need a destination buffer of minimum size 7 (6 characters + 1 null terminating character) to hold the common substring (for the given input).
As #Halt State suggested, you can print the specific number of characters of input string, starting from a position in the string:
if(result = 0){
printf("No common substring");
}else{
printf("%.*s",result, &X[end-result+1]);
}
Alternatively, you can allocate the memory dynamically and copy the longest common string in that memory. In this case, instead of printing longest common string in LCSubStr() function, you may return it from LCSubStr() function which enables the calling function to process something based on the returned string, if required. It's implementation:
....
#include <stdlib.h> // for malloc
....
char * LCSubStr (char *X, char *Y, int m, int n) {
....
....
char * subbuff = NULL;
if (result > 0) {
subbuff = malloc (result + 1);
if (subbuff == NULL) {
fprintf (stderr, "Failed to allocate memory\n");
exit (EXIT_FAILURE);
}
memcpy (subbuff, &X[end - result + 1], result);
subbuff[result] = '\0';
}
return subbuff;
}
// In the calling function
int main (void) {
....
....
char * lcs = LCSubStr (X, Y, m, n);
if (lcs != NULL) {
printf ("%s\n", lcs);
// Once the calling function done with returned buffer, free it
free (lcs);
} else {
printf ("No common substring\n");
}
return 0;
}

How to iteratively generate all possible combinations of letters and numbers for matching with a variable length string?

I wish to write a iterative logic program where there is an input string and the program starts from length 1 and tries all possible combinations of letters and numbers. If the match is not found, it tries all possible combinations of letters and numbers for length 2 and so on until it finds a match with the input string.
For example,
string input = "xG7a";
// loop all possible combinations for length 1, i.e., 0-9 then A-Z, then a - z
// check for all if matches the input string
// loop all possible combinations for length 2, i.e., 00-09, then 0A-0Z, then 0a - 0z. Then
// for 10-19, then 1A-1Z, then 1a - 1z ... till z0-z9, then zA-zZ, then za - zz
// again check for all if matches the input string
// Keep doing this for lengths 3, 4, 5 and so on till it matches with the input string.
// exit with status success if match else keep going till infinity
// This example would exit at length 4 when it matches with "xG7a"
Number of all possible combinations being matched here are (10 + 26 + 26 = 62) = 62^1 + 62^2 + 62^3 + ... till there is a match.
EDIT
More details:
This is part of an exercise on writing brute-forcing logic
The input string is not known beforehand. The above example is for illustration. I've figured out the rest of the logic. The generated string is being passed into a hash function that generates a hash to match with a password hash in a database. Hence the dynamic nature of the string to be generated.
It is known beforehand that the password string is only comprised of numbers and lower and upper case letters.
Thank you in advance for all the help.
You say - a bit of pseudocode, I say - full working program!
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MARGIN 5
// if you're getting errors due to redeclaration of 'strdup', just remove that
const char *strdup(const char *string) {
const size_t len = strlen(string);
char *dst = calloc(len + 1, sizeof(char));
memmove(dst, string, len);
return dst;
}
struct NumeralSystem {
char *alphabet;
size_t base;
};
struct Word {
struct NumeralSystem ns;
char *data; // the current combination, null-terminated
unsigned int *_internal; // indices of the characters of 'data' in 'ns.alphabet'
size_t length, maxLength;
};
struct NumeralSystem NewSystem(const char *alpha) {
struct NumeralSystem ret = {strdup(alpha), strlen(alpha)};
return ret;
}
struct Word NewWordEmpty(const struct NumeralSystem ns, const size_t maxLength) {
struct Word ret;
ret.ns = ns;
ret.data = calloc(maxLength + 1, sizeof(char));
ret._internal = calloc(maxLength + 1, sizeof(unsigned int));
ret.maxLength = maxLength;
*ret._internal = 0;
*ret.data = *ret.ns.alphabet;
ret.length = 1;
return ret;
}
struct Word NewWordPreset(const struct NumeralSystem ns, const char *data) {
struct Word ret;
ret.length = strlen(data);
const size_t maxLength = ret.length + MARGIN;
ret.ns = ns;
ret.data = calloc(maxLength + 1, sizeof(char));
ret._internal = calloc(maxLength + 1, sizeof(unsigned int));
ret.maxLength = maxLength;
memmove(ret.data, data, ret.length);
for (size_t i = 0; i < ret.length; ++i) {
const char *found = strchr(ns.alphabet, ret.data[i]);
if (found == NULL) return NULL;
ret._internal[i] = found - ns.alphabet;
}
return ret;
}
void EnlargeWord(struct Word *wrd) { // here, wrd->length - wrd->maxLength == 1
const size_t newSize = wrd->maxLength + MARGIN;
wrd->data = realloc(wrd->data, newSize * sizeof(char));
wrd->_internal = realloc(wrd->_internal, newSize * sizeof(int));
memset(wrd->data + wrd->maxLength + 1, 0, MARGIN);
memset(wrd->_internal + wrd->maxLength + 1, 0, MARGIN);
wrd->maxLength = newSize;
}
void DestroyWord(struct Word *wrd) {
free(wrd->data), free(wrd->_internal);
}
struct Word *next(struct Word *wrd) {
int len = (int)(wrd->length - 1); // this can be negative, see below
// handle the overflow if current digit is equal to the last_digit of the alphabet
// 1. last_digit -> first_digit
// 2. go to previous position
while ((len >= 0) && (wrd->_internal[len] == wrd->ns.base - 1)) {
wrd->_internal[len] = 0;
wrd->data[len--] = *wrd->ns.alphabet;
}
// if all the digits in the word were equal to the last_digit of the alphabet,
// 'len' will be exactly (-1), and the word's length must increase
if (len == -1) {
wrd->data[wrd->length++] = *wrd->ns.alphabet;
// UH-OH, we're about to run out of bounds soon!
if (wrd->length > wrd->maxLength)
EnlargeWord(wrd);
return wrd;
}
// if 'len' is still nonnegative, it's the position of the digit
// that we haven't increased yet
wrd->data[len] = wrd->ns.alphabet[++wrd->_internal[len]];
return wrd;
}
int main(void) {
const struct NumeralSystem ns = NewSystem("abcdef");
struct Word wrd = NewWordPreset(ns, "deadbeef");
printf("%s\n", wrd.data);
for (unsigned int i = 0; i < 30; ++i)
printf("%s\n", next(&wrd)->data);
DestroyWord(&wrd);
return 0;
}
Create a string with all possible characters in the proper order:
char charlist[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
Then for each character you want to check, loop through this string build your test string and compare:
int i, found;
char str_to_test[5];
for (i=0, found=0; !found && i<strlen(charlist); i++) {
str_to_test[0] = charlist[i];
str_to_test[1] = 0;
if (!strcmp(str_to_test, target_string)) {
found = 1;
}
}
if (found) {
printf("found it!\n");
} else {
printf("not found\n");
}
Repeat in nested loops for each substring.

A Function that will convert number bases and Errors for illegal inputs

I have written a function that will convert strings between different user specified number bases. For example octal is 8, decimal is 10. Letters A to Z could be considered up to base 26.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include<stdlib.h>
#include<string.h>
#include<ctype.h>
#include<math.h>
#define MAXBUF 64
int baseconv(char s[], int sb, char d[], int db);
void main()
{
char s[MAXBUF+1], d[MAXBUF+1]; // source, destination value (as char string)
int sb,db; // source, destination base
int decval; // calculated decimal value
char buf[MAXBUF+10]; // temp buffer
char *p; // pointer to string
printf("Enter src value, src base, dst base: ");
gets(buf);
p=strtok(buf," ,");
while(stricmp(p,"END"))
{
strcpy(s,p);
p=strtok(NULL," ,"); // or sb=atoi(strtok(NULL," ,"))
sb=atoi(p);
p=strtok(NULL," ,"); // or db=atoi(strtok(NULL," ,"))
db=atoi(p);
decval = baseconv(s,sb,d,db);
printf("%s|%d = %d|10 = %s|%d\n", s,sb,decval,d,db);
printf("Enter src value, src base, dst base: ");
gets(buf);
p=strtok(buf," , ");
}
}
// actual baseconv() function
int baseconv(char s[], int sb, char d[], int db)
{
char t1[MAXBUF+10];
char t[MAXBUF+10];
int v=0,i=0,j=0,temp,k=0;
while(s[i])
{
if(s[i]>=48 && s[i] < 58)
v = v * sb + (s[i]-48);
else if(s[i]>=65 && s[i]<71)
v = v * sb + (s[i]-65)+10;
else if(s[i]>=97 && s[i]<103)
v = v * sb + (s[i]-97)+10;
i++;
}
temp=v;
while(v)
{
if(v%db+48 >= 48 && v%db+48 < 58)
t[j] =(v%db)+48;
else if(v%db+55 >=65)
t[j] =(v%db)+55;
else if(v%db+87 >=97)
t[j] =(v%db)+87;
v = v/db;
j++;
}
for(int n=j-1;n>=0;n--)
{
t1[k]=t[n];
k++;
}
t1[j]='\0';
strcpy(d,t1);
return temp;
}
Output is like this-
Enter source value, source base, dest base: 1234, 8, 16
1234|8 = 668|10 = 29C|16"
And
Enter source value, source base, dest base: face, 16, 8
face|16 = 64206|10 = 175316|8"
However, I cannot get it to specify if the source value is illegal for the specified source base (for example 1234|3, return -1, and place the value "ERROR" in d[].
Output WOULD be like this-
Enter source value, source base, dest base: 12345, 5, 10
12345|5 = -1|10 = ERROR|10"
How would I implement the return -1 and ERROR?
You can write a function that maps a character to its ordinal value for a given base.
int map_digit_to_ordinal (int x) {
static int map[MAX_CHAR];
const char *digits = "0123456789abcdefghijklmnopqrstuvwxyz";
const char *p;
if (x < 0 || x >= MAX_CAR) return -1;
if (map['1'] == 0) {
for (p = digits; *p; ++p) {
map[*p] = 1 + p - digits;
map[toupper(*p)] = 1 + p - digits;
}
}
return map[x] - 1;
}
You can have a different function to check if the digit falls within your desired base.
int digit_in_base (int digit, int base) {
if (base > 36) return -1;
if (digit < base) return digit;
return -1;
}
Then, your conversion function can use this function to map the potential digit to the right value. If the returned value is -1, your function should return early, writing "ERROR" to the destination.
Now, your conversion function loop can make the appropriate checks.
while(s[i]) {
temp = map_digit_to_ordinal(s[i]);
temp = digit_in_base(temp, sb);
if (temp == -1) {
strcpy(d, "ERROR");
return -1;
}
v = v * sb + temp;
i++;
}
/* rest of function ... */

Resources