Hexadecimal input function calculates wrong values - c

I'm writing a function that can read integers expressed in hexadecimal.
This is my code. The main function should not be modified.
#include <stdio.h>
#include <ctype.h>
#define SIZE 100
main()
{
int array[SIZE], n;
int gethex(int*);
int i, sum;
for (n = 0; n < SIZE && gethex(&array[n]) != EOF; n++)
;
sum = 0;
for (i = 0; i < n; i++)
sum += array[i];
printf("The sum is %d\n", sum);
}
int gethex(int *pn)
{
int c, sign;
c = getchar();
while (isspace(c))
;
if (!isxdigit(c) && c != EOF && c != '+' && c != '-') {
ungetc(c, stdin);
return 0;
}
sign = (c == '-') ? -1 : 1;
if (c == '+' || c == '-')
c = getchar();
for (*pn = 0; isxdigit (c); c = getchar()) {
if (c >= '0' && c <= '9') {
*pn = 16 * *pn + (c - '0');
}
else if (c >= 'a' && c <= 'f') {
*pn = 16 * *pn + (c - 'a' + 10);
}
else if (c >= 'A' && c <= 'F') {
*pn = 16 * *pn + (c - 'A' + 10);
}
}
*pn *= sign;
if (c == EOF) {
*pn = c;
return c;
}
}
The result value should come out like this.
-FFec
10000
^Z
The sum is 20
However, my code outputs
The sum is 1717986860
What's wrong?

At least these problems:
Warnings not fully enabled
Warnings are not fully enabled, losing OP and others valuable time. #Jens
End of gethex() lacks a return value.
warning: control reaches end of non-void function [-Wreturn-type]
Infinite loop
Once a '\n is read, loop never ends. #Weather Vane
while (isspace(c))
;
Non hex input also set up an infinite loop with ungetc(c, stdin); as that same c will repeatedly get read on the next function call.
if (!isxdigit(c) && c != EOF && c != '+' && c != '-') {
ungetc(c, stdin);
return 0;
}
int overflow possible
Code like *pn = 16 * *pn + (c - '0'); and *pn *= sign; can lead to int overflow, which is undefined behavior (UB). Robust code would prevent that.
Some untested code to fix these issues.
// Return 0 if non-numeric input detected.
// Return 2 when input out of int range
// Return 1 on success
// Return EOF when input is only white-space, sign or none
int gethex(int *pn) {
int ch;
// Consume leading white-space
do {
ch = getchar();
} while (isspace(ch));
// Get sign, if any
int sign = ch; // remember 1st
if (ch == '-' || ch != '+') {
ch = getchar();
}
if (ch == EOF) {
return EOF;
}
if (!isxdigit(ch)) {
// Consume non-numeric input
return 0;
// Perhaps better to return EOF here to stop calling code.
}
int overflow = 0;
int sum = 0;
while (isxdigit(ch)) {
int digit = 0;
if (isdigit(ch)) {
digit = ch - '0';
} else if (isupper(ch)) {
digit = ch - 'A' + 10;
} else if (islower(ch)) {
digit = ch - 'a' + 10;
}
if (sum <= INT_MIN / 16
&& (sum < INT_MIN / 16 || digit > -(INT_MIN % 16))) {
overflow = 1;
sum = INT_MIN;
} else {
// Accumulate as a negative number as there are more
// negative vales than positive ones.
// This prevents bad code like -INT_MIN later.
sum = sum * 16 - digit;
}
}
if (sign != '-') {
if (sum < -INT_MAX) {
overflow = 1;
sum = INT_MAX;
} else {
sum = -sum;
}
}
*pn = sum;
ungetc(ch, stdin);
return overflow ? 2 : 1;
}

Related

K&R C Programming Language Exercise 2-3 code returns rubbish

I tried to write a solution from exercise 2-3. After compilation, it returns random numbers on output. I don't really understand where this issue is coming from.
Any help appreciated.
StackOverflow keeps asking for more details. The purpose of the program is listed in the code bellow.
More delails.
Purpose of the code:
Write the function htoi(s), which converts a string of hexa-
decimal digits (including an optional 0x or 0X) into its
equivalent integer value. The allowable digits are 0 through 9,
a through f, and A through F.
/*
* Write the function htoi(s), which converts a string of hexa-
* decimal digits (including an optional 0x or 0X) into its
* equivalent integer value. The allowable digits are 0 through 9,
* a through f, and A through F.
*/
#include <stdio.h>
#include <math.h>
int hti(char s)
{
const char hexlist[] = "aAbBcCdDeEfF";
int answ = 0;
int i;
for (i=0; s != hexlist[i] && hexlist[i] != '\0'; i++)
;
if (hexlist[i] == '\0')
answ = 0;
else
answ = 10 + (i/2);
return answ;
}
unsigned int htoi(const char s[])
{
int answ;
int power = 0;
signed int i = 0;
int viable = 0;
int hexit;
if (s[i] == '0')
{
i++;
if (s[i] == 'x' || s[i] == 'X')
i++;
}
const int stop = i;
for (i; s[i] != '\0'; i++)
;
i--;
while (viable == 0 && i >= stop)
{
if (s[i] >= '0' && s[i] <= '9')
{
answ = answ + ((s[i] - '0') * pow(16, power));
}
else
{
hexit = hti(s[i]);
if (hexit == 0)
viable = 1;
else
{
hexit = hexit * (pow(16, power));
answ += hexit;
}
}
i--;
power++;
}
if (viable == 1)
return 0;
else
return answ;
}
int main()
{
char test[] = "AC";
int i = htoi(test);
printf("%d\n", i);
return 0;
}
answ is not initialized in htoi. Initialize it to zero.

C hex to dec conversion, I don't understand what's wrong with my code

My code should find hex numbers in a user input (followed or not by 0x), copy them in an array as a string and, every time it finds a non 1-9 a-f A-F character or EOF, it should execute the htoi function converting the characters in the string into a decimal number, proceeding from right to left and using a multiplier to account for the position. It doesn't do what it's supposed to do. It generates numbers that have nothing to do with the decimal equivalent of my hex numbers.
#include <stdio.h>
#include <string.h>
#include <math.h>
int htoi(char num[]);
int main()
{
int c,i = 0;
char num[1000];
while ((c = getchar()) != EOF)
{
if ((c > '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'a' && c <= 'f'))
{
num[i] = c;
i++;
}
else if (c == '0')
{
if ((c = getchar) == 'x' || c == 'X')
{
num[i] = '\0';
printf("%d", htoi(num));
i=0;
}
else
{
num[i] = c;
i++;
}
}
else
{
num[i] = '\0';
if (num[0] != '\0')
{
printf("%d", htoi(num));
}
i=0;
}
}
num[i] = '\0';
if (num[0] != '\0')
{
printf("%d", htoi(num));
}
i=0;
return 0;
}
int htoi(char num[])
{
int c,i, dig;
int dec;
int multiplier = 1;
for (i = strlen(num)-1; i >= 0; i--)
{
c = num[i];
if (c > '0' && c <= '9')
{
dig = c - '0';
}
else if (c > 'a' && c <= 'f')
{
dig = c - 'a' + 10;
}
else if (c > 'A' && c <= 'F')
{
dig = c - 'A' + 10;
}
dec = dec + dig * multiplier;
multiplier * 16;
return dec;
}
}
Three problems:
multiplier * 16; just throws away the result. You'd want multiplier *= 16
return dec returns immediately with the current value of dec. You should have that after the loop.
The variable dec is uninitialized, which means it will have an indeterminate value. Using it without initialization, like you do, will lead to undefined behavior.
There are other problems as well, some of which would have been caught by the compiler leading to errors or warnings. The three above was just what I found after a quick glance.

faster input output of floating numbers in c

For faster integer input in c we can use http://abhisharlives.blogspot.in/2012/06/really-fast-io-methods-for-programming.html methods ,but how to take faster input of floating numbers in c?
Using ideas from the link you provided, I wrote up my own fast floating number input technique. Here's the code (including the main() to test it):
#include <stdio.h>
#define gc getchar_unlocked
int neg;
int scandigits(double *x, int div) {
register int c = gc();
register double pow10 = 1;
if ( x == NULL ) {
return -1;
}
*x = 0;
while ( (c < '0' || c > '9') && c != '-' ) {
c = gc();
}
if ( c == '-' ) {
neg = 1;
c = gc();
}
while ( !(c < '0' || c > '9') ) {
*x *= 10;
*x += (c - '0');
pow10 *= 10;
c = gc();
}
if ( neg )
*x = -*x;
if ( div )
*x /= pow10;
return c;
}
void scandouble(double *x) {
double left, right = 0;
if ( x == NULL ) {
return;
}
neg = 0;
int ret = scandigits(&left, 0);
if ( ret == '.' )
scandigits(&right, 1);
*x = left + right;
}
int main() {
double d;
scandouble(&d);
printf("%f", d);
return 0;
}
Note: In general, most competitive coding contests do NOT require fast IO. Instead, they require much better algorithms etc. However, in some very rare cases you require fast IO to eke out that last 0.01s to make your code get accepted. I would suggest using such trickery (that's what I call it) in only such cases.
Often using integer math is faster than double. The below uses integer math to compose the significand and optional exponent.
double getdouble(void) {
int ch = getchar();
int sign = ch;
if (sign == '-' || sign == '+') {
ch = getchar();
}
long long sum = 0;
int digit_count = 0;
int dp_offset = -1;
int power10 = 0;
int dp = '.';
for (;;) {
while (ch >= '0' && ch <= '9') {
digit_count++;
if (sum < LLONG_MAX / 10) {
sum = sum * 10 + ch - '0';
} else {
power10++;
}
ch = getchar();
}
if (ch == dp) {
dp = '0';
dp_offset = digit_count;
ch = getchar();
} else {
break;
}
}
if (dp_offset >= 0) {
power10 -= digit_count - dp_offset;
}
if (ch == 'e' || ch == 'E') {
ch = getchar();
int esign = ch;
if (esign == '-' || esign == '+') {
ch = getchar();
}
int expo = 0;
while (ch >= '0' && ch <= '9') {
expo = expo * 10 + ch - '0';
ch = getchar();
}
if (esign == '-') expo = -expo;
power10 += expo;
}
double y = sum;
if (power10) {
// combine these 2 steps for speed with `pow(10,power10)`.
// leave separate for better handling of very large/very tiny numbers
y *= pow(5, power10); //
y = ldexp(y, power10);
}
if (sign == '-') y = -y;
return y;
}
Same answer as atof() 86% of the time.
When in error, 1 bit error.
Worse case: 1 bit.
Handles exponential notation and sub-normals, -0.0.
Does not handle NAN, INF.
Returns INF on +/-DBL_MAX, works on all smaller values.

Get whole number from input using only getchar() and convert to int

For a school assignment i have to make a C program that reads a whole number, that may be preceded by a '+' or '-'. i can only use getchar().
I can convert a single char to an int using int i = ch - '0' but I want to read in multiple chars. besides that I need to check if the input is correct (eq. no not-numerical charachters)
I have this so far:
int main(void) {
int i;
char ch;
printf("voer een getal in: ");
while ((ch = getchar()) != '\n') {
i = ch - '0';
}
printf("het ingevoerde getal is: %d\n", i);
return EXIT_SUCCES;
}
Edit: I get that this isn't really the place for problems like this (I should learn to fix it myself, not get others to fix it for me) but I didn't know what to do anymore. thanks you for guiding me to the right path
This should get you started:
int main(void) {
int i = 0;
int ch;
printf("voer een getal in: ");
while ((ch = getchar()) != '\n') {
if (ch > '9' || ch < '0')
continue; // or print an error and exit
i *= 10;
i += ch - '0';
}
printf("het ingevoerde getal is: %d\n", i);
return EXIT_SUCCES;
}
I'll leave detecting the potential + / - sign as an exercise.
If your school allows you to use shift operators then here is a quick way to get integer from the user and as per their requirements you can show the + or - sign preceding the integer. But remember not to just copy paste it. Understand the code first.
int main(){
int i = 0;
char c;
char sign = 43;
printf("voer een getal in:\n");
c = getchar();
if(c == 45)
sign = 45;
for(; (c<48 || c>57); c = getchar());
for(; c>47 && c<58 ; c = getchar()){
i = (i<<1) + (i<<3) + c - 48;
}
printf("het ingevoerde getal is: %c%d\n",sign, i);
return 0;
}
Reading in multiple characters, and determine whether positive, negative, and value:
int sign = 1;
ch = getchar(); //look at first char (might be a sign indicator)
if((ch == '-') || (ch == '+')) //consume first char if either `-` or `+`
{
if(ch == '-') sign = -1;
}
else //first char non-sign - handle as digit
{
if (ch > '9' || ch < '0')
continue; // or print an error and exit
i *= 10;
i += ch - '0';
}
while ((ch = getchar()) != '\n') //get remaining chars (assume no embedded sign chars)
{
if (ch > '9' || ch < '0')
continue; // or print an error and exit
i *= 10;
i += ch - '0';
}
i *= sign; //apply sign to value
I think this will work.
while ((ch = getchar()) != '\n') {
i = ch - '0' + i * 10;
The problem in your code is that you are overwriting i every time you read a new character. You need to store the digit you read, and then add to it.
You should take care about not number characters :
while((ch=getchar()) != '\n')
if(ch >= '0' && ch <= '9')
i += 10* i + (ch - '0');
For the '-' or '+' at the begining you could store the first getchar(). A solution could be :
#include <stdlib.h>
#include <stdio.h>
int main(void) {
int i = 0;
char ch,first_ch;
printf("voer een getal in: ");
ch = first_ch = getchar();
while (ch != '\n') {
if(ch >= '0' && ch <= '9')
i = 10* i + (ch - '0');
ch = getchar();
}
if(first_ch == '-')
i *= -1;
printf("het ingevoerde getal is: %d\n", i);
return EXIT_SUCCESS;
}

getint and getch

"As written, getint treats a + or - not followed by a digit as a valid representation of zero. Fix it to push such a character back on the input."
Ok, well this is the original version:
int getint2(int *pn)
{
int c, sign;
while(isspace(c=getch()))
;
if(!isdigit(c) && c!= EOF && c!= '+' && c!= '-') {
ungetch(c);
return 0;
}
sign = (c == '-') ? -1 : 1;
if(c == '+' || c == '-') {
c = getch();
}
for(*pn = 0; isdigit(c); c = getch())
*pn = 10 * *pn + (c - '0');
*pn *= sign;
ungetch(c);
return c;
}
And i edited this way:
int getint2(int *pn)
{
int c, sign;
while(isspace(c=getch()))
;
if(!isdigit(c) && c!= EOF && c!= '+' && c!= '-') {
ungetch(c);
return 0;
}
sign = (c == '-') ? -1 : 1;
if(c == '+' || c == '-') {
c = getch();
if(!isdigit(c)) {
ungetch(c);
return 0;
}
}
for(*pn = 0; isdigit(c); c = getch())
*pn = 10 * *pn + (c - '0');
*pn *= sign;
ungetch(c);
return c;
}
So im not sure what did the author want. Should i unget the +/- aswell, or just the character after it? Should i return 0 in case there's no digits after +/- or -1?
I also have a question about getch and ungetch functions:
since EOF on my sistem is -1, this is how i wrote getch and ungetch:
int buf = EOF;
int getch()
{
int temp;
if(buf == -2)
return EOF;
if(buf == EOF)
temp = getchar();
else
{
temp = buf;
buf = EOF;
}
return temp;
}
void ungetch(int c)
{
if(c == EOF)
buf = -2;
buf = c;
}
So i was told by some people that EOF can be -2. What should i do to avoid this sort of 'problem'.
To answer your second question, about EOF and -2, I can think of a couple of solutions:
you could have an array of characters in the "buffer", and an "index" in the position (i.e., have a rudimentary stack). I believe that arrays are introduced in K&R by that point. That will give you flexibility in that you can ungetch() more than one character. An added advantage of this scheme is that your code in part 1, where you might need to ungetch() twice, becomes easier as well.
you could store the 'state' in another int variable, such as int buffered = 0;, and then getch() would return buf only when buffered == 1. ungetch() sets buffered = 1, getch() sets buffered = 0:
static int buf;
static int buffered = 0;
int getch()
{
if (buffered) {
buffered = 0;
return buf;
}
return getchar();
}
void ungetch(int c)
{
buffered = 1;
buf = c;
}

Resources