Skip to content

Instantly share code, notes, and snippets.

@reagent
Created April 1, 2013 14:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save reagent/5285359 to your computer and use it in GitHub Desktop.
Save reagent/5285359 to your computer and use it in GitHub Desktop.
String Calculator
calc
*.o
*.dSYM
#include <stdio.h>
#include <string.h>
#include "calculator.h"
int is_numeric(char *n);
int
main(int argc, char *argv[])
{
if (argc != 3) {
fprintf(stderr, "Usage: calc <number> <number>\n");
return 1;
}
if (!is_numeric(argv[1])) {
fprintf(stderr, "Error: First argument must be a number\n");
return 1;
}
if (!is_numeric(argv[2])) {
fprintf(stderr, "Error: Second argument must be a number\n");
return 1;
}
if (!add_print(argv[1], argv[2])) {
fprintf(stderr, "Error: could not add values\n");
return 1;
}
return 0;
}
int
is_numeric(char *n)
{
int i,
success = 1,
length = strlen(n);
success = success && (length > 0);
for (i = 0; i < length; i++) {
success = success && (n[i] >= '0' && n[i] <= '9');
}
return success;
}
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <errno.h>
#include <stdarg.h>
#include "calculator.h"
#define check_mem(P) if (!P) { goto error; }
#define check(C) if (!(C)) { goto error; }
size_t max_length(char *first, ...);
int int_value(char n);
char add_digits(int a1, int a2, int *c);
char * pad(char *number, size_t width, char pad);
char *
add(char *n1, char *n2)
{
int v1, v2, ri,
carry = 0,
done = 0,
i1 = strlen(n1) - 1,
i2 = strlen(n2) - 1;
size_t max = max_length(n1, n2, NULL);
char * result = pad(NULL, max + 1, ' ');
ri = max; // set index to space before terminating NUL
while (!done && ri > 0) {
v1 = v2 = 0;
if (i1 >= 0) {
v1 = int_value(n1[i1]);
check(v1 >= 0);
}
if (i2 >= 0) {
v2 = int_value(n2[i2]);
check(v2 >= 0);
}
result[ri] = add_digits(v1, v2, &carry);
ri--;
i1--;
i2--;
if (i1 < 0 && i2 < 0) { done = 1; }
}
if (carry > 0) {
result[ri] = ('0' + carry);
}
return result;
error:
free(result);
return NULL;
}
int
add_print(char *n1, char *n2)
{
char *v1 = NULL,
*v2 = NULL,
*div = NULL,
*result = add(n1, n2);
check_mem(result);
size_t width = max_length(result, n1, n2, NULL);
v1 = pad(n1, width, ' ');
check_mem(v1);
v2 = pad(n2, width, ' ');
check_mem(v2);
div = pad(NULL, (width + 1), '-');
check_mem(div);
printf(" %s\n+%s\n%s\n %s\n", v1, v2, div, result);
free(result);
free(v1);
free(v2);
free(div);
return 1;
error:
if (result) { free(result); }
if (v1) { free(v1); }
if (v2) { free(v2); }
if (div) { free(div); }
return 0;
}
size_t
max_length(char *first, ...)
{
size_t max = strlen(first);
va_list ap;
char *next;
va_start(ap, first);
while ((next = va_arg(ap, char*)) != NULL) {
if (strlen(next) > max) { max = strlen(next); }
}
va_end(ap);
return max;
}
int
int_value(char n)
{
int result;
errno = 0;
result = strtol(&n, NULL, 10);
if (result == 0 && errno != 0) {
result = -1;
}
return result;
}
char
add_digits(int a1, int a2, int *c)
{
int sum = a1 + a2 + *c,
r = sum % 10;
*c = sum / 10;
return ('0' + r);
}
char *
pad(char *number, size_t width, char pad)
{
char *out = calloc(width + 1, sizeof(char));
int oi = width - 1,
ni = -1;
if (out == NULL) { goto error; }
memset(out, pad, width);
if (number) { ni = strlen(number) - 1; }
while (ni >= 0) {
out[oi] = number[ni];
ni--;
oi--;
}
return out;
error:
return NULL;
}
#ifndef _CALCULATOR_H
#define _CALCULATOR_H
char * add(char *n1, char *n2);
int add_print(char *n1, char *n2);
#endif
CFLAGS=-g -Wall -Wextra
all: calc
calc: calculator.o
clean:
rm -rf calc *.o *.dSYM
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment