How to convert string representation of octal number to decimal? - c

I want to make a program that converts binary number to decimal, octal and hexadecimal.
While taking input I am considering their standard representation. For example: octal is "o10"
So I convert 10 into decimal, which gives 8.
Here's my code for inputting string and converting it to decimal:
int main()
{
int ch=0;
char str[1000];
printf("Enter the number\n");
scanf(" %s",str);
l=strlen(str);
for(int j=0;j<l;j++)
{
if(str[j]>=48 && str[j]<=57)
n=n*10+(str[j]-48);
}
}
But the problem is that it doesn't work for octal. How to take the input correctly?

On the post you are taking about creating Binary/Octal/Hexadecimal to Decimal converter, but you code only address Octal, My answer will try to be generic so you could implement the other cases with it, but will focus on Octal.
First of all, your code has some minor issues not related to the algorithm itself:
You call printf and strlen function, which does not come built in with C and need to be included with their respective libraries:
#include <stdio.h>
#include <string.h>
You assign l to the length of the string, but you never declare it type, so this is needed:
l = strlen(str);
Same problem for n, which is never declared. Not only that, you say n=n*10 ... so noy only not declaring it, you use it value.. what do you think n*10 will return? My guess is garbage. Since you use it in the loop, you should declare it outside the loop itself, so I would suggest:
int l = strlen(str), n = 0;
Okay not that we got this out of the way, your Octal converted code is actually almost done.
Only problem with the algorithm, is the n*10 ... part. If you multiply n by 10, you acually get decimal converted.. so Decimal to Decimal converted, if you input for example 48 you will get 48 as output. What do we need to fix it? change it to 2 for Binary converted, 8 for Octal, and 16 for Hexa. Your code only speak about octal, so if you change this line to:
n = n * 8 + (str[j] - 48);
You will get a working Octal converted. For example, if run the program and input 10, you will get 8 which is what we want.
Now as I mentioned earlier, if you want to make it more generic you should have a variable called int base = 10; which you can set according to the first character, for example:
int base = 10; // default value
if (str[0] == 'o')
{
base = 8;
}
Of course you can do the same for other bases, and it will pretty much work the same. Finally, you never did actually with the value of n after you calculated it, So someting like that would work to check the answer we got:
printf("In Decimal => %d\n", n);
This kinda works, but we still need to check digit boundaries. For example, octal number can't have a digit larger then 7, and Hexa number can have A as a digit. In the for loop, we do not check for anything like that. For example, if you input o48 in your code it will print an answer, 40, which is not correct since 48 is not an octal number.
So you in order to complete the program, you need to check if boundaries, and implement the rest of the bases check (h for hexa, b for binary), This I will leave to you.
GOOD LUCK~!

Related

Why does multiplying a character produce other seemingly random characters?

I can't understand why this code output is weird. I wrote this out of curiosity and now if I enter 55 it shows a leaf. And also many other things depending on number. I searched it in google but didn't find any possible explanation.
#include <stdio.h>
int main(){
char input='*';
int x;
scanf("%d",&x);
printf("%c",input*x);
return 0;
}
Characters are encoded as integers, usually 8-bit by default in C. Some are defined by ASCII and others depend on your OS, screen font, etc.
The * character has code 42. If you enter 55, your code computes 42*55=2310 and uses the low 8 bits of this value, which is 6, as the character to print. Character 6 is ACK which is not defined as a printable character by ASCII, but it sounds like your system is using something like the legacy IBM code page 437, in which character 6 displays as the spade symbol ♠.
Multiplying a character code by an integer is not a very useful thing to do. I'm not sure what you were expecting to accomplish with this program. If you thought it would print 55 copies of the * character, like Perl's x operator, well it doesn't. C has no built-in way to do that; you would just write a loop that prints * once per iteration, and iterates 55 times.

how to get multiple character in one input in C

I'm new to C programming so i'm trying to write a piece of code where i need to take ip address in hexadecimal but i couldn't figure out how to do. as far as i know i can't get multiple input with char but with int when user enters 'A' for example it turns out huge number.
for decimal inputs i wrote something like this
int main(){
int IP_1,IP_2,IP_3,IP_4;
printf("Enter the IP address:\n");
scanf("%d.%d.%d.%d",&IP_1,&IP_2,&IP_3,&IP_4);
i used 4 variables because later i will use those numbers for conversion.
edit: sorry for not adding this i can't use either hexadecimal %x or arrays/strings
What's the problem ?
The huge value when you enter a letter is because scanf() doesn't recognize the letter as valid input for an int, and stops reading, leaving the remaining variables unassigned.
How to solve it ?
First you should check if you've read as many variables as you've expected:
if (scanf("%d.%d.%d.%d",&IP_1,&IP_2,&IP_3,&IP_4)<4) {
printf ("Error: invalid format !\n");
}
You may then want to read the integer in hexadecimal format:
scanf("%x.%x.%x.%x",&IP_1,&IP_2,&IP_3,&IP_4);
You'll find more about the input formatting with scanf() here
Important remark: The convention for an IPv4 address, is to use dots to separate decimal components. For an hexadecimal notation, the digits are in principle consecutive, each component being 2 digits.
Edit
If you're not allowed to use %x, nor arrays, nor strings, then you can only input hex digits as char. Assuming that every hex part is entered on 2 digits, you may then have to input 8 chars:
char c1, c2, c3, c4, c5, c6, c7, c8;
scanf("%c%c.%c%c.%c%c.%c%c",&c1, &c2, &c3, &c4, &c5, &c6, &c7,&c8);
// are you sure you have to enter the dots ?
To convert two hex chars into an int, without using strings and arrays you can do:
if (c1>='A' && c1<='F')
IP_1 = c1-'A';
else if (c1>='0' && c1<='9')
IP_1 = c1-'0';
else
IP_1 = 0; // OUCH! THIS IS AN ERROR
IP_1 = IP_1 *16;
if (c2>='A' && c2<='F')
IP_1 = IP_1 + c2-'A';
else if (c2>='0' && c2<='9')
IP_1 = IP_1 + c2-'0';
else
IP_1 = 0; // OUCH! THIS IS AGAIN AN ERROR
I let as an exercise for you to add the case where the digits are lower case. I let you complete for all the characters, since you are not allowed to create functions.
FInal remark
Giving exercises that force students to massacre worldwide accepted IP address conventions, and then forcing students to copy paste code seems to me obvious signs of a completely incompetent teacher.
In your interest, you should not be as transparent and open as I am here. However, I feel obliged to warn you: go for some nice tutorials on the web. Or buy a K&R and do all the exercices contained therein. You'll learn real skills, instead of taking bad habits.
#include <stdio.h>
int main()
{
unsigned int IP_1,IP_2,IP_3,IP_4;
printf("Enter the IP address:\n");
scanf("%x %x %x %x",&IP_1,&IP_2,&IP_3,&IP_4); //storing in Hex format
printf("%x %x %x %x",IP_1,IP_2,IP_3,IP_4);
}
I think the best way is to read a string and then use the functions that already exist for converting string to IP (namely, inet_aton()).
Also, I would avoid scanf for strings, is insecure.
See https://ideone.com/aO9Nll for a live demo and the code.

Calling the 1's, 10's, 100's... columns of an integer using a string array

I'm trying to convert a long long integer to a string array with the 1's column in position 0 of the array, the 10's column in position 1, the 100's column in position 2, like this:
INPUT: 4444555566667777 -----> OUTPUT: [4,4,4,4,5,5,5,5,6,6,6,6,7,7,7,7]
To test my code, I wrote for my last line printf("%d\n",number_str[3]). I expected my program to output the value of position 4, "7". Instead, it output "52". Changing my last line to printf("%d\n",number_str[4]) yields "53" instead of "6", as I expected. Can anyone explain what's going on?
Surely 52 and 53 correspond to ASCII values, but then, how can I convert them to integers? Can I do this in line?
Where I'm headed with this part of my program is to add up all of the numbers in the 10's, 1,000's, 100,000's, 10,000,000's... columns. Every other digit in a base-10 credit card number. This is one step in my attempt at a Luhn validation.
// Libraries
#include <cs50.h>
#include <stdio.h>
#include <string.h>
// Program
int main(void)
{
// Get CC number
printf("Enter your credit card number: ");
long long number_ll = GetLongLong();
// printf("%lld\n", number_ll);
// Convert long long to string
char number_str[64];
sprintf(number_str, "%lld", number_ll);
// printf("%s\n", number_str);
// Get length of card number string
int cclength = strlen(number_str);
// Check the length of card number string
if ( ! (cclength == 13 || cclength == 15 || cclength == 16))
printf("INVALID\n");
else
printf("%d\n",number_str[3]);
To convert ascii into integer use
#include <stdlib.h>
int atoi(const char *str);
change this
printf("%d\n",number_str[3]);
to
char buf[2];
buf[0]=number_str[3];
buf[1]='\0';
printf("%d\n",atoi((const char*)buf));
Using "%d" on a char will print its ASCII code. Use "%c" to print itself.
And your string's order is reversed compared to your purpose. The rightmost digit(1's column) is at the tail of the string, and the leftmost one is in position 0.
So to print the number at position i (count from right to left), you should use:
printf("%c\n", number_str[cclength - i - 1]);
I'm going to go ahead and expand on my comment since I don't believe either of the other answers responded to your full question.
By reading the CC number into a long long, and then using sprintf to plug the number into a character array, I would say you're correctly getting the number into a form that you can use for validation. In fact, you can check the return value of sprintf to see whether or not it's a valid number (although a failure case would be unlikely since you're plugging in a long long.
Once you have the CC number in a character array, you know that each element of the array will contain one character, which corresponds to one digit in the CC number. It sounds like for your purposes, it's more useful for the values in the array to be the decimal values, rather than the ASCII values. Logically, this is the difference between the values '0' and 0. You can look up any ASCII chart to see the corresponding ASCII value for each character, but since characters can be manipulated just like integers, you can traverse the array:
for(i = 0; i < 64; i++) num_str[i] -= '0';
Note that this doesn't handle there being less than 64 characters or uninitialized values in the array after the CC number characters, so you'll need to modify it. What's important to realize is that you're just shifting the character values down by '0', which happens to have the integer value 48.
Once you do this conversion, printing out a value in the array with printf using %d as the format specifier will work like you expect; even though the array data type is char, each element may be printed as a decimal integer.
Once you've read the number into the char array and made the conversion, all you need to do is traverse the array again, performing whatever steps are involved in the CC Validation process. You may need to traverse the array in reverse if the validation method requires the digits to be in order.

New to C: whats wrong with my program?

I know my way around ruby pretty well and am teaching myself C starting with a few toy programs. This one is just to calculate the average of a string of numbers I enter as an argument.
#include <stdio.h>
#include <string.h>
main(int argc, char *argv[])
{
char *token;
int sum = 0;
int count = 0;
token = strtok(argv[1],",");
while (token != NULL)
{
count++;
sum += (int)*token;
token = strtok(NULL, ",");
}
printf("Avg: %d", sum/count);
printf("\n");
return 0;
}
The output is:
mike#sleepycat:~/projects/cee$ ./avg 1,1
Avg: 49
Which clearly needs some adjustment.
Any improvements and an explanation would be appreciated.
Look for sscanf or atoi as functions to convert from a string (array of characters) to an integer.
Unlike higher-level languages, C doesn't automatically convert between string and integral/real data types.
49 is the ASCII value of '1' char.
It should be helpful to you....:D
The problem is the character "1" is 49. You have to convert the character value to an integer and then average.
In C if you cast a char to an int you just get the ASCII value of it. So, you're averaging the ascii value of the character 1 twice, and getting what you'd expect.
You probably want to use atoi().
EDIT: Note that this is generally true of all typecasts in C. C doesn't reinterpret values for you, it trusts you to know what exists at a given location.
strtok(
Please, please do not use this. Even its own documentation says never to use it. I don't know how you, as a Ruby programmer, found out about its existence, but please forget about it.
(int)*token
This is not even close to doing what you want. There are two fundamental problems:
1) A char* does not "contain" text. It points at text. token is of type char*; therefore *token is of type char. That is, a single byte, not a string. Note that I said "byte", not "character", because the name char is actually wrong - an understandable oversight on the part of the language designers, because Unicode did not exist back then. Please understand that char is fundamentally a numeric type. There is no real text type in C! Interpreting a sequence of char values as text is just a convention.
2) Casting in C does not perform any kind of magical conversions.
What your code does is to grab the byte that token points at (after the strtok() call), and cast that numeric value to int. The byte that is rendered with the symbol 1 actually has a value of 49. Again, interpreting a sequence of bytes as text is just a convention, and thus interpreting a byte as a character is just a convention - specifically, here we are using the convention known as ASCII. When you hit the 1 key on your keyboard, and later hit enter to run the program, the chain of events set in motion by the command window actually passed a byte with the value 49 to your program. (In the same way, the comma has a value of 44.)
Both of the above problems are solved by using the proper tools to parse the input. Look up sscanf(). However, you don't even want to pass the input to your program this way, because you can't put any spaces in the input - each "word" on the command line will be passed as a separate entry in the argv[] array.
What you should do, in fact, is take advantage of that, by just expecting each entry in argv[] to represent one number. You can again use sscanf() to parse each entry, and it will be much easier.
Finally:
printf("Avg: %d", sum/count)
The quotient sum/count will not give you a decimal result. Dividing an integer by another integer yields an integer in C, discarding the remainder.
In this line: sum += (int)*token;
Casting a char to an int takes the ASCII value of the char. for 1, this value is 49.
Use the atoi function instead:
sum += atoi(token);
Note atoi is found in the stdlib.h file, so you'll need to #include it as well.
You can't convert a string to an integer via
sum += (int)*token;
Instead you have to call a function like atoi():
sum += atoi (token);
when you cast a char (which is what *token is) to int you get its ascii value in C - which is 49... so the average of the chars ascii values is in fact 49. you need to use atoi to get the value of the number represented

Char to int conversion in C

If I want to convert a single numeric char to it's numeric value, for example, if:
char c = '5';
and I want c to hold 5 instead of '5', is it 100% portable doing it like this?
c = c - '0';
I heard that all character sets store the numbers in consecutive order so I assume so, but I'd like to know if there is an organized library function to do this conversion, and how it is done conventionally. I'm a real beginner :)
Yes, this is a safe conversion. C requires it to work. This guarantee is in section 5.2.1 paragraph 2 of the latest ISO C standard, a recent draft of which is N1570:
Both the basic source and basic execution character sets shall have the following
members:
[...]
the 10 decimal digits
0 1 2 3 4 5 6 7 8 9
[...]
In both the source and execution basic character sets, the
value of each character after 0 in the above list of decimal digits shall be one greater than
the value of the previous.
Both ASCII and EBCDIC, and character sets derived from them, satisfy this requirement, which is why the C standard was able to impose it. Note that letters are not contiguous iN EBCDIC, and C doesn't require them to be.
There is no library function to do it for a single char, you would need to build a string first:
int digit_to_int(char d)
{
char str[2];
str[0] = d;
str[1] = '\0';
return (int) strtol(str, NULL, 10);
}
You could also use the atoi() function to do the conversion, once you have a string, but strtol() is better and safer.
As commenters have pointed out though, it is extreme overkill to call a function to do this conversion; your initial approach to subtract '0' is the proper way of doing this. I just wanted to show how the recommended standard approach of converting a number as a string to a "true" number would be used, here.
Try this :
char c = '5' - '0';
int i = c - '0';
You should be aware that this doesn't perform any validation against the character - for example, if the character was 'a' then you would get 91 - 48 = 49. Especially if you are dealing with user or network input, you should probably perform validation to avoid bad behavior in your program. Just check the range:
if ('0' <= c && c <= '9') {
i = c - '0';
} else {
/* handle error */
}
Note that if you want your conversion to handle hex digits you can check the range and perform the appropriate calculation.
if ('0' <= c && c <= '9') {
i = c - '0';
} else if ('a' <= c && c <= 'f') {
i = 10 + c - 'a';
} else if ('A' <= c && c <= 'F') {
i = 10 + c - 'A';
} else {
/* handle error */
}
That will convert a single hex character, upper or lowercase independent, into an integer.
You can use atoi, which is part of the standard library.
Since you're only converting one character, the function atoi() is overkill. atoi() is useful if you are converting string representations of numbers. The other posts have given examples of this. If I read your post correctly, you are only converting one numeric character. So, you are only going to convert a character that is the range 0 to 9. In the case of only converting one numeric character, your suggestion to subtract '0' will give you the result you want. The reason why this works is because ASCII values are consecutive (like you said). So, subtracting the ASCII value of 0 (ASCII value 48 - see ASCII Table for values) from a numeric character will give the value of the number. So, your example of c = c - '0' where c = '5', what is really happening is 53 (the ASCII value of 5) - 48 (the ASCII value of 0) = 5.
When I first posted this answer, I didn't take into consideration your comment about being 100% portable between different character sets. I did some further looking around around and it seems like your answer is still mostly correct. The problem is that you are using a char which is an 8-bit data type. Which wouldn't work with all character types. Read this article by Joel Spolsky on Unicode for a lot more information on Unicode. In this article, he says that he uses wchar_t for characters. This has worked well for him and he publishes his web site in 29 languages. So, you would need to change your char to a wchar_t. Other than that, he says that the character under value 127 and below are basically the same. This would include characters that represent numbers. This means the basic math you proposed should work for what you were trying to achieve.
Yes. This is safe as long as you are using standard ascii characters, like you are in this example.
Normally, if there's no guarantee that your input is in the '0'..'9' range, you'd have to perform a check like this:
if (c >= '0' && c <= '9') {
int v = c - '0';
// safely use v
}
An alternative is to use a lookup table. You get simple range checking and conversion with less (and possibly faster) code:
// one-time setup of an array of 256 integers;
// all slots set to -1 except for ones corresponding
// to the numeric characters
static const int CHAR_TO_NUMBER[] = {
-1, -1, -1, ...,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, // '0'..'9'
-1, -1, -1, ...
};
// Now, all you need is:
int v = CHAR_TO_NUMBER[c];
if (v != -1) {
// safely use v
}
P.S. I know that this is an overkill. I just wanted to present it as an alternative solution that may not be immediately evident.
As others have suggested, but wrapped in a function:
int char_to_digit(char c) {
return c - '0';
}
Now just use the function. If, down the line, you decide to use a different method, you just need to change the implementation (performance, charset differences, whatever), you wont need to change the callers.
This version assumes that c contains a char which represents a digit. You can check that before calling the function, using ctype.h's isdigit function.
Since the ASCII codes for '0','1','2'.... are placed from 48 to 57 they are essentially continuous. Now the arithmetic operations require conversion of char datatype to int datatype.Hence what you are basically doing is:
53-48 and hence it stores the value 5 with which you can do any integer operations.Note that while converting back from int to char the compiler gives no error but just performs a modulo 256 operation to put the value in its acceptable range
You can simply use theatol()function:
#include <stdio.h>
#include <stdlib.h>
int main()
{
const char *c = "5";
int d = atol(c);
printf("%d\n", d);
}

Resources