I'm trying to figure what is wrong with my code as it always skips only to the printf("not an octal number part"); and only outputs that although has many of the other computations before it, i'm trying to debug it but can't seem to find the error. this is the summer of the problem below, also we are not allowed to use pointers yet.
A C program to input an octal number in the form of a line of characters and store the input characters in an array. Convert the octal number to a decimal integer and display the decimal integer on the standard output using printf.
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#define MAX_SIZE 100
int main() {
char my_strg[MAX_SIZE];
int c;
int res = 0;
int i = 0;
while ( (c = getchar()) != '\n') {
my_strg[i] = c;
i++;
}
int k = 0;
for(k = strlen(my_strg)-1; k >= 0; k--) {
if((my_strg[k] >= '0') && (my_strg[k] <= '7')) {
res += (pow(8, k) * (my_strg[k]-'0'));
} else if(my_strg[k] == '-') {
res *= -1;
} else {
printf("not an octal number");
break;
}
k++;
}
printf("%d\n", res);
}
You haven't null-terminated my_strg. This means that the beginning of the array contains the input, but the rest of it contains gibberish. It may also be a good idea to do bounds checking so that you don't get a buffer overflow.
while (((c = getchar()) != '\n') && (i < MAX_SIZE-1)) {
my_strg[i] = c;
my_strg[i+1] = '\0';
i++;
}
very simple function. Needs more error checking.
Note 'a' != 'A'. The base can be as big as number of chars in the digits table
static const char digits[] = "0123456789abcdefghijklmnopqrstuwxyzABCDEFGHIJKLMNOPQRTSTUWXYZ";
long long ALMOST_anybase(const char *str, int base, int *errCode)
{
long long result = 0;
int sign = 1;
if(errCode) *errCode = 0;
if(str)
{
if(*str == '-') {sign = -1; str++;}
while(*str)
{
if(*str == '-')
{
if(errCode) *errCode = 3;
break;
}
else
{
char *ch;
if((ch = strchr(digits, *str)))
{
if(ch - digits >= base)
{
if(errCode) *errCode = 2;
break;
}
result *= base;
result += (ch - digits);
}
else
{
if(errCode) *errCode = 1;
break;
}
}
str++;
}
}
return result * sign;
}
int main(void)
{
int errCode;
long long result;
result = ALMOST_anybase("-4-4", 10, &errCode);
if(errCode)
{
printf("Wrong input string ErrCode = %d\n", errCode);
}
else
{
printf("result = %lld\n", result);
}
}
Related
Is there more elegant way to do this task?
Program asks user for integer and repeats if non-digital characters are entered.
To exit loop two conditions expected:
a) all entered characters are digits
b) last character is '\n'
Short solutions like scanf don’t work properly, other approaches require lots of variables loops and if else conditions. User input is common task and I would like to have proper reusable template.
Subjective opinions are appreciated. Way to simplify this function or advice on another solution. Improve formatting. Reading for more systematic understanding.
#include <stdio.h>
int getIntOnly();
int main() {
int x = 0;
x = getIntOnly();
printf("\nvalue entered is: %d \n", x);
}
int getIntOnly() {
int ch, num, quit, abc;
do {
num = 0;
ch = 0;
quit = 0;
abc = 0;
printf("Enter the input: ");
do {
ch = getchar();
if (ch >= 48 && ch <= 57) {
num = num * 10 + (ch - 48);
}
else if (ch == '\n') {
quit = 1;
}
else {
abc = 1;
}
}
while (quit == 0);
}
while (quit == 0 || abc == 1);
return (num);
}
Using fgets() means you'll get the full text at once.
You can then examine it (and convert it too) to suit your needs.
int getIntOnly( void ) {
int value = 0, i = 0;
char buf[ 64 ];
do {
printf( "Enter integer value: " );
fgets( buf, sizeof( buf ), stdin );
value = 0;
for( i = 0; '0' <= buf[i] && buf[i] <= '9'; i++ )
value = value * 10 + buf[i] - '0';
} while( buf[i] != '\n' ); // good! reached end of line
return value;
}
May be better? Add some validity checks for the result of fgets() and strtol() according to your original code.
#include <stdio.h>
#include <limits.h>
#include <stdbool.h>
#include <stdlib.h>
int getIntOnly();
int main() {
int x = 0;
x = getIntOnly();
printf("\nvalue entered is: %d \n", x);
}
bool isDigit(char ch) {
return (ch >= '0' && ch <= '9')? true : false;
}
bool isAllDigit(char *buf) {
int i;
for (i = 0; buf[i] != '\n'; i++) {
if (isDigit(buf[i]) == false) {
return false;
}
}
return true;
}
bool isVaildInt(long int number) {
return (number >= INT_MIN && number <= INT_MAX)? true : false;
}
int getIntOnly() {
char buf[100];
long int num;
bool done = false;
do {
/* read line-by-line */
fgets(buf, 100, stdin);
if (isAllDigit(buf) == false)
continue;
num = strtol(buf, NULL, 10);
/* strtol() returns long int */
if (isVaildInt(num) == false)
continue;
done = true;
} while (done == false);
return num;
}
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.
I've build a small program which would convert the given char array to an integer:
#include <stdio.h>
int char_to_int(char* value);
int main(int argc, char* argv[])
{
if (argc != 2)
{
printf("Illegal argument count!");
return 1;
}
printf("As char array: %s\n", argv[1]);
printf("As integer: %i", char_to_int(argv[1]));
return 0;
}
int char_to_int(char* value)
{
return *value - '0';
}
The problem is that when I enter a multidigital number the integer only consists of a single digit number, which is logical, but I have no idea on how to rewrite the code. And I also have no idea why only the first char gets converted.
I know this is pretty basic stuff, but I'd like to know how to implement it correctly.
I'd also like to avoid using the ato() function in the STL.
Reworked code with error handling:
#include <stdio.h>
int char_to_int(char* value);
int illegal_conversion = 0;
int main(int argc, char* argv[])
{
if (argc != 2)
{
printf("Illegal argument count!");
return 1;
}
int result = char_to_int(argv[1]);
if (illegal_conversion)
{
printf("Illegal arguments");
return 1;
}
printf("As char array: %s\n", argv[1]);
printf("As integer: %i", result);
return 0;
}
int char_to_int(char* value)
{
int result = 0;
int negative_integer = 0;
while (*value)
{
if (*value == 43)
{
*value++;
continue;
}
else if (*value == 45)
{
*value++;
negative_integer = 1;
continue;
}
else if (*value < 48 || *value > 57)
{
illegal_conversion = 1;
return 1;
}
result *= 10;
result += *value++ - '0';
}
if (negative_integer)
result *= -1;
return result;
}
Because you only return the numerical value of the first digit.
This function converts but without any checks and it works only for the valid non negative decimal numbers, otherwise it is an UB
int char_to_int(char* value)
{
int result = 0;
while(*value)
{
result *= 10;
result += *value++ - '0';
}
return result;
}
or a bit smarter one:
int char_to_int(char* value, int *res)
{
int sign = 0;
int status = 0;
int result = 0;
if (value != NULL && res != NULL)
{
while (*value)
{
switch (*value)
{
case '+':
case '-':
if (sign) status = -1;
sign = *value == '-' ? -1 : 1;
break;
default:
if (!isdigit(*value)) status = -1;
if(!sign) sign = 1;
*result *= 10;
*result += *value - '0';
break;
}
value++;
if (status) break;
}
if(!status)*res = sign * result;
}
return status;
}
Reworked code incurs undefined behavior in a case where it can be avoided.
Example with (2's complement) int
char buf[100];
sprintf(buf, "%d", INT_MIN); // e.g. -2147483648
int y = char_to_int(buf);
The while loop in char_to_int() eventually executes
// before
// result: 214748364
// *value: '8'
result += *value++ - '0';
// after
// `int` overflow, this is undefined behavior
To avoid, rather than accumulate the answer as a positive value and then later negate if '-' found, accumulate the answer as a negative value and then later negate if '-' not found. This is less intuitive, yet avoids UB.
Using unsigned as an extended range is another way, yet that fails on rare machines where INT_MAX == UINT_MAX. I have only encountered such a machine once and that for for its widest integer.
Other improvements noted in comments.
#include <ctype.h>
int char_to_int(const char *value) { // use const
int sign = *value;
if (sign == '-' || sign == '+') {
value++;
}
bool digit_found = false;
int result = 0;
// while (isdigit(*value)) { // avoid this as it is UB when *value < 0, not EOF
while (isdigit((unsigned char) *value)) { // or (*value >= '0' && *value <= '9')
result *= 10;
result -= *value - '0'; // notice the `-=`
value++;
digit_found = true;
}
if (sign != '-') {
result = -result;
}
// Error detection
if (*value != '\0' || !digit_found) {
; //Handle_Invalid_String();
}
return result;
}
Note: overflow detection not included.
I'm extremely lost and confused.
I have to read in a float integer like 3.432 using getchar. Then, I have to print it out again as a float with a precision of 4 decimal places using printf. So 3.432 --> 3.4320 and .450 --> .4500, and 453 --> 453.0000.
I've been using getchar() and I understand that, but trying to reconvert the value as a float is where I'm just extremely lost.
float num = 0.0;
char ch;
while((ch = getchar()) != '\n'){
num = ch - '0';
printf("%.4f", num);
}
I know why that is wrong and what it outputs but that's what I have so far
EDIT: I can only use getchar to read the float values
Not tested (no time). Hope it helps.
#include <stdio.h>
int main(void)
{
float num = 0.0;
float i = 1.0;
char ch;
printf("Enter a float number: ");
while((ch = getchar()) != '\n')
{
if (ch == '.')
{
i = 0.1;
}
else if ((ch>= '0') && (ch <='9'))
{
if (i==1)
{
num *= 10;
num += ch - '0';
}
else
{
num += (ch - '0') * i;
i /= 10;
}
}
}
printf("%.4f\n", num);
return 0;
}
Ok, so you should first specify what you want - as usual keep away from the keybord until you exactly know what you want to build:
read until end of file or first new line
skip initial blank characters (optional but not expensive)
ignore trailing blank character (optional but not expensive)
reject any non blank after first trailing blank
reject any character other than blanks, digits and dot
process the integer part (until first dot) but multiplying current value by 10 and adding character code minus char '0'
ensure at most one dot
process the decimal part by adding char - '0' multiplied by 0.1 power decimal position
Once that has been stated coding is simple and could be:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
void error(int pos, char c) {
fprintf(stderr, "Unwanted character %c at %d\n", c, pos);
exit(1);
}
int main() {
double f = 0.;
int c;
bool initial = 1, final=0;
int pos = 0;
double decimal = 0;
while (((c = getchar()) != EOF) && (c != '\n')) {
pos += 1;
if (isspace(c)) { // accept spaces before and after the number
if (initial || final) continue;
else {
final = 1;
continue;
}
}
else if (final) { // do not accept anything after a space after the number
error(pos, c);
}
initial = 0; // at least one non blank char
if (c == '.') {
if (decimal) { // accept only one decimal dot
error(pos, c);
}
else decimal = 1;
}
else if (! isdigit(c)) { // only digits
error(pos, c);
}
else if (decimal == 0) {
f = f * 10 + c - '0'; // integer part
}
else {
decimal *= .1; // fractional part
f += (c - '0') * decimal;
}
}
printf("%.4f\n", f);
return 0;
}
As a bonus I showed you how to process error conditions
It would be simpler if you first write a function reading integer.
Then you can think about writing a function reading the decimal part and combine the result.
Also, you need to accumulate the read information. At the moment you are overwriting previously read digit with a new one.
Another possibility using only stdio in solving the task could be a simple two-step process:
declaring and reading the input into a character array, using some more or less sophisticated fool-proofing
"parsing" the array members on the left and right hand side of the decimal point and multiplying the ('0' offset subtracted value) by the corresponding power of 10.
_
#include <stdio.h>
int main(void)
{
float power_of_ten, num = 0.;
char c, ch[32];
int j, i = 0;
int point_pos = -1; //initialize decimal point position 'offscale'
while(((c = getchar()) != EOF) && (c != '\n')) //simple fool-proof check
if(((c >= '0')&&(c <= '9')) || (( c == '.')&&(point_pos == -1))){
ch[i] = c;
if(ch[i] == '.')
point_pos = i;
i++;
}
ch[++i] = '\0'; //length of the array
//parsing the array
if(point_pos >= 0){ //to the right of decimal point
power_of_ten = .1;
for(j = point_pos + 1; j < i-1; j++){
num += (float)(ch[j] - '0')*power_of_ten;
power_of_ten *= .1;
}
}
power_of_ten = 1.; //to the left of decimal point
if(point_pos == -1)point_pos = i-1;
for(j = point_pos - 1; j >= 0 ; j --){
num += (float)(ch[j] - '0')*power_of_ten;
power_of_ten *= 10;
}
printf("%.4f\n", num);
return 0;
}
Hope this helps!!
#include<stdio.h>
#include<string.h>
#include<math.h>
int findNumOfDigits(int num);
int main(void)
{
char c;
float f, mod, fractional;
char *buff = malloc(10), *fptr;
char *str = buff;
int digits;
printf("Enter any number\n");
c = getchar();
while(c!='\n')
{
*buff = c;
buff = buff+1;
c = getchar();
}
*buff = '\0';
mod = atoi(str);
fptr = strstr(str, ".");
if(fptr!=NULL)
fptr++;
fractional = atoi(fptr);
digits = findNumOfDigits(fractional);
f = (mod + (fractional/pow(10,digits)));
printf("Number converted to float = %f", f);
return 0;
}
int findNumOfDigits(int num)
{
int i;
for(i = 1; num >= 10; i++)
{
num = num/10;
}
return i;
}
I need to know how to convert a user input, which is a string, to a double. like if he writes in the string "23.45", it converts into double 23.45
(without any library functions).
I already got this code for integer, but don't know how to continue with double:
#include <stdio.h>
void main()
{
char input[100];
printf("Type a String which will be converted to an Integer: ");
scanf("%s", input);
int number = 0;
int i = 0;
if (input[i] >= 48 && input[i] <= 57)
{
while (input[i] >= '0' && input[i] <= '9')
{
number = number * 10;
number = number + input[i] - '0';
i++;
}
printf("string %s -> number %d \n", input, number);
}
else
{
printf("Enter a number! \n");
}
}
There's probably no reason why you'd roll out your own version of this, as strtod in stdlib.h already covers all manner of formats.
Here's a version which covers signed numbers as input and has some hints of where more suitable error handling could be placed:
#include <stdbool.h>
static void halt_and_catch_fire (void);
double strtod_homebrewn (const char* str)
{
double result = 0;
// handle signs:
bool is_negative = false;
if(*str == '-')
{
is_negative = true;
str++;
}
else if(*str == '+')
{
str++;
}
// handle the dot position:
bool is_dot_found = false;
double multiplier = 0.1;
// the actual conversion:
for(const char* s=str; *s!='\0'; s++)
{
if(*s >= '0' && *s <= '9') // ctype.h isdigit() would be preferred here
{
if(is_dot_found)
{
result += (*s - '0') * multiplier;
multiplier /= 10;
}
else
{
result *= 10;
result += *s - '0';
}
}
else if(*s == '.')
{
if(is_dot_found) // two dots?
{
halt_and_catch_fire(); // replace this with error handling
}
is_dot_found = true;
}
else if(*s != '\0') // all cases tested, some weird unknown character found
{
halt_and_catch_fire(); // replace this with error handling
}
}
if(is_negative)
{
result = -result;
}
return result;
}
static void halt_and_catch_fire (void)
{
halt_and_catch_fire();
}
#include <stdio.h>
void main()
{
char input[100];
printf("Type a String which will be converted to a double: ");
scanf("%s", input);
double number = 0.0;
double divider = 1.0;
int inFraction = 0;
int i = 0;
if (input[i] >= 48 && input[i] <= 57)
{
inFraction = 0;
while ((input[i] >= '0' && input[i] <= '9') || input[i] == '.')
{
if (input[i] == '.')
{
i++;
inFraction = 1;
continue;
}
number = number * 10.0;
number = number + input[i] - '0';
i++;
if (inFraction) divider *= 10.0;
}
number /= divider;
printf("string %s -> number %g \n", input, number);
}
else
{
printf("Enter a number! \n");
}
}
Edit: As clux pointed out, this fails when the fraction starts with zeroes. Bummer. Anyway, perhaps someone conceives a simple fix? I can only think of adding a "readzeroes()" function and let that run after the dot.
You already have a function to read an int. Simply use that. Pseudo code:
float read_float()
{
float f = read_int()
if(next is dot) skipdot else return f;
float frac = read_int()
while (frac>1) frac /= 10
return f+frac;
}
Edit: only use this approach for small number of digits after the decimal point.
Read the comments to know why it would fail for a large number of digits.
Since you mentioned without using any library functions, you could do something like this.
float number;
int decimal = 0;
int decimal_found =10;
while(input[i]!='\0')
{
if((input[i] <='0' || input[i] >='9')&&input[i]!='.' )
break;
if(input[i] == '.')
decimal = 1;
if(decimal == 1)
{
number = number + (input[i] - '0')/decimal_found;
decimal_found = decimal_found*10;
}
else
{
number = number *10;
number = number + input[i] - '0';
}
i++;
}
Simply check a decimal variable to know when decimal has been reached, then use and if else to have separate conditions for the number variable