Code:
/*
Large digit addition by Pat.
Preforms addition on 2 strings of digits.
tested on upto 2^10 digits, but capable of 2^31 digits (in theory)
set to 2^20 digits as max, but can be changed
known bugs:
1.) no (real) error checking. I don't know where to begin...
2.) if string[] or n in __add() is defined in __add(), it *may* lead to unexpected results for some reason in MSVC++. Havent tested using GCC.
3.) strcpy() doesn't work. if copied to the strings, it reports an extra '0' at the end of final_string.
most likely because the for loop in add() is REALLY bad.
4.) when compiling with GCC, it may sometimes return a letter as string[0] if there is no carry. Not exactly sure why. Works fine in MSVC++
example: (when compiled as "GCC -o add add.c") "3233213123" + 3233213123 = "P6466426246"
Also happens with single digits ("1" + "1" = "`2")
*/
#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS /* MSVC++ reports a bunch of warnings without this */
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef max
#define max(a,b) (((a) > (b)) ? (a) : (b))
#endif
#define strmalloc(x) (char*) malloc(sizeof(char) * x)
#define assert(exp, msg) (!(exp) && printf("Assert: \""#exp"\" triggered a breakpoint in file \"%s\" on line: %d.\n\nError:"#msg"\n\nPress any key to terminate this program.", __FILE__, __LINE__) && getchar() ? exit(1) : (void)0)
#define MAX_NUMBER_OF_DIGITS 1048576
/* __add() is internally by add() to process addition of single digits*/
char __add(char a, char b, char* nextcol, char string[], int n) {
/* convert to int and do calculations here */
n = atoi(&a) + atoi(&b) + atoi(nextcol);
/* carry the next number if needed
NOTE: n is guaranteed to never be over 27 because
atoi(&num) returns a maximum of 9 for single chars */
if(n >= 10 && n < 20) {
n -= 10;
*nextcol = '1';
}
else if(n >= 20) {
n -= 20;
*nextcol = '2';
}
else
*nextcol = '\0';
/* convert n to char, and return the char */
sprintf(string, "%d", n);
return *string;
}
char* add(char *number1, char *number2) {
/* define lengths, and maxlen so I don't need to call them 6 times per loop */
size_t len1 = strlen(number1) - 1;
size_t len2 = strlen(number2) - 1;
size_t maxlen = max(len1, len2);
/* define storage string,counter, int & string & nextcol for __add()
__add() is used to process each char to make addition possible */
char *string = strmalloc(maxlen + 2); /* final string */
size_t counter = 0;
char *st = strmalloc(2); /* string to be used in __add(). see Known bugs */
int n = (int) malloc(sizeof(int)); /* int to be used in __add(). see Known bugs */
char nextcol = '\0';
/*loop through both numbers and add them up */
for(; counter <= maxlen; counter++) {
/* end-of-string-ptr - counter = add(
if(counter > len1) {'\0'} else { end-of-number1-ptr - counter } ,
if(counter > len2) {'\0'} else { end-of-number2-ptr - counter }
) */
*(string + maxlen - counter+1) = __add(counter > len1 ? '\0' : *(number1 + len1 - counter), counter > len2 ? '\0' : *(number2 + len2 - counter), &nextcol, st, n);
/* FIXME: quite long, and doesn't even work 100% */
}
/* last calculation for carry over and make it a NULL terminated string */
if(nextcol != '\0')
*string = __add('\0', '\0', &nextcol, st, n);
*(string + maxlen + 1) = '\0';
/* return the final string */
return string;
}
int main() {
/*allocates 3 strings as number1, 2, and the final string*/
char *str1 = strmalloc(MAX_NUMBER_OF_DIGITS);
char *str2 = strmalloc(MAX_NUMBER_OF_DIGITS);
char *final_string = strmalloc((MAX_NUMBER_OF_DIGITS + 2));
/* assert if malloc() returned NULL */
assert(str1 != NULL && str2 != NULL && final_string != NULL, "Not enough memory can be allocated.");
/* get user input */
printf("Type in number1: ");
fgets(str1, MAX_NUMBER_OF_DIGITS, stdin);
printf("Type in number2: ");
fgets(str2, MAX_NUMBER_OF_DIGITS, stdin);
/* call add(), and print answer */
final_string = add(str1, str2);
printf("\nFinal calculation = \n%s", final_string);
getchar();
return 0;
}
Start with all this, I guess? You're doing lots of stupid stuff:
- using the reserved variable name __add
ALL tokens starting with __ or _ and a capital are reserved for use by the implementation of the standard library.
- redefining standard macros like assert()
- using atoi() inappropriately
Taking the address of a character is not enough, atoi() wants a *string*, and you'll get undefined behavior if you don't give it a string. Use the calculation (n - '0') instead.
- converting to a string in __add and then returning a single character.
The calculation (n + '0') is magical as well.
- strmalloc
This macro has no reason for existing. By #include <stdlib.h> you already have a proper declaration for malloc so the return value cast is still unnecessary (like always) and the multiplication with sizeof(char) is nothing important. char is always 1 byte.
Maybe taking a step back and not using esoteric syntax like the ternary operator is a good idea as well. I'm glad you seem to know what it does, but you wrote it in a hurry, didn't you, so it's not like you have a clue what's going on in add().