Im trying to make a simple function which can convert a number with a thousand separator to an integer without the separator. All my numbers are within the range of 0 to 999.999, so my initial though was to just handle it like a double and then multiply it by 1000 and call it a day, but is there a more generel way of doing this?:
#include <stdio.h>
main() {
double a;
a=369.122;
int b;
b = a * 1000;
printf("b is %d", b);
}
Where is my current solution:
#include <stdio.h>
main() {
char *XD = "113.321";
int s1, s2;
sscanf(XD, "%i.%i", &s1, &s2);
printf("%i", s1 * 1000 + s2);
}
Using a double for this is not appropriate due to floating point imprecision: you might find that when multiplied by 1000 and truncate to an int, you end up with a number that is 1 less than you really want.
Also note that the largest value for an int can be as small as 32767. On such a platform, you would overflow b.
If I were you, I'd use a long throughout and introduce the 1000s separator when you want to display the value. For a positive number x, the first 1000 is attained using x / 1000, the final 1000 using x % 1000.
You can simply parse the input yourself and ignore the separators.
Parsing integers is easy:
#include <stdio.h>
int main()
{
int c;
unsigned n = 0, acc = 0;
while(EOF!=(c=getchar())){
if(c>='0' && c<='9')
acc = 10*n + c-'0';
else if(c == '.') //ignore your separator
continue;
else
break; //not a digit and not a separator -- end parsing
if(acc < n)
fprintf(stderr, "overflow\n");
n = acc;
}
printf("got %d\n", n);
}
If you want very hi-perf., avoid the getchar and parse a buffered string (or at least use getchar_unlocked).
Alternatively, you can lex the string, copy legal characters to a buffer, and then run strtoul or similar on that buffer.
You should only only need like 22 characters for the buffer max (assuming base 10) or else 64 bit integers would start overflowing if you parsed them from a buffer that needed more digits.
A rugged, generic solution is to use a string, then simply skip everything that is not a digit. That way you don't have to worry about locale etc. (Several countries use , for decimals and . for thousand separator, while English-speaking counties do the opposite. And spaces are also sometimes used for thousand separator.)
#include <stdint.h>
#include <inttypes.h>
#include <ctype.h>
#include <stdio.h>
uint32_t digits_only (const char* str_number)
{
uint32_t result = 0;
for(size_t i=0; str_number[i] != '\0'; i++)
{
if(isdigit(str_number[i]))
{
result *= 10;
result += (uint32_t)str_number[i] - '0';
}
}
return result;
}
int main (void)
{
printf("%" PRIu32 "\n", digits_only("123,456"));
printf("%" PRIu32 "\n", digits_only("123.456"));
printf("%" PRIu32 "\n", digits_only("blabla 123 blabla 456 blabla"));
}
Related
I need to make simple function that converts binary number (string) to decimal number (long). When it returns result, it's nonsense. I've tried to return all others variables and it returned correct numbers. There is something wrong with my result variable.
#include "stdio.h"
#include "string.h"
#include "math.h"
long bintodec(const char *bin_num) {
long DIGIT, SUBTOTAL, RESULT = 0, I, LEN;
LEN = strlen(bin_num);
for(I = 0; I != LEN; I++) {
sscanf(&bin_num[I], "%li", &DIGIT);
SUBTOTAL = DIGIT * pow(2, LEN - I - 1);
RESULT = RESULT + SUBTOTAL;
}
return RESULT;
}
main() {
clrscr();
printf("%li", bintodec("101"));
getch();
}
sscanf is expecting a C string:
During the first iteration it receives "101" and 101 * 4 is 404
During the second iteration it receives 01 and 1 * 2 is 2
During the third iteration it receives 1 and 1 * 1 is 1
404 + 2 + 1 is 407 which must be the nonsense you are seeing
What you want is to convert each character:
DIGIT = bin_num[I] - '0';
You can convert string to long in one go, no need to iterate in loop. Changing your code like below can give you desired output
#include <stdio.h>
#include <string.h>
#include <math.h>
long bintodec(const char *bin_num)
{
long DIGIT, SUBTOTAL, RESULT = 0, I, LEN, REM;
LEN = strlen(bin_num);
sscanf(bin_num, "%li", &DIGIT);
printf("DIGIT = %li\n", DIGIT);
for (I = 0; I < LEN; I++)
{
REM = DIGIT%10;
RESULT += REM * pow(2, I);
DIGIT /= 10;
}
return RESULT;
}
int main() {
printf("%li", bintodec("101"));
}
Rather than debug your code, I'll present a more elegant solution. Consider:
long bintodec(const char *bin_num)
{
long sum = 0;
for (; *bin_num != '\0'; bin_num++) /* move pointer through string */
{
sum <<= 1; /* shift bits left (meaningless on first pass) */
sum |= (*bin_num == '1'); /* conditionally tack on new least significant bit */
}
return sum;
}
Some notes:
The key point is that the bits that encode integer type variables are identical to the binary sequence that you pass in as a string. Thus: bitwise operators. The only ones we need here are left bit-shift, which shifts each of the underlying bits one place to the left, and bitwise-or, which logically or's the bits of two numbers against one another. The equivalent representations render valid a pictorial understanding of the problem.
Rather than having to pass through the entire string to determine its length, and using that to inform the pow function, we can slot incoming bits in on the right.
Here's what's going on within the for loop:
1st pass:
sum <<= : 00000 /* more zero's contained in a long */
string: "10101"
ptr: ^
sum |= : 00001
2nd pass:
sum: 00010
string: "10101"
ptr: ^
sum: 00010
3rd pass:
sum: 00100
string: "10101"
ptr: ^
sum: 00101
... and so forth.
In general, rather than invoking
pow(2, arg)
you should leverage the bit-shift operator, which exactly accomplishes multiplication by some power of two. (Appending a zero is multiplication by 10 in base 10).
I have been trying to make a program in C/C++ that creates files until the process is stopped.
The file names start from 0 and follow an arithmetic sequence.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
long cifre(long x) //returns the number of digits a number has
{
int nr = 0;
while (x != 0)
{
x = x/10;
nr++;
}
return nr;
}
int main()
{
long i=0;
FILE* g;
char* v;
char buffer[1025];
int j=0;
for (j=0;j<1024;j++)
buffer[j] = 'x';
while (1)
{
v = (char*)malloc(cifre(i)+10);
snprintf(v,sizeof(v),"%ld",i);
g = fopen(v,"w");
fprintf(g,"%s",buffer);
free(v);
fclose(g);
i++;
}
return 0;
}
The problem is that the program creates only 1000 files.
The sizeof(v) in the call to sprintf is the size of a char pointer, in your case probably 4, which means that the formatted string will contain at most 3 characters, or the numbers from 0 to 999. To fix this use the same length you used to allocate memory:
size_t len = cifre(i)+10;
v = (char*)malloc(len);
snprintf(v,len,"%ld",i);
snprintf(v,sizeof(v) doesn't make much sense because sizeof(v) returns the size of the pointer (v is char*), not the size of the dynamically allocated array. And so snprintf() is limited to only printing sizeof(v)-1 characters, or 3 digits and the NUL string terminator. 3 digits give you values from 000 to 999, exactly 1000.
I have a simple code to convert binary to decimal numbers. In my compiler, the decomposition works just fine for number less than 1000, beyond the output is always the same 1023. Anybody has an idea ?
#include <stdio.h>
#include <stdlib.h>
// how many power of ten is there in a number
// (I don't use the pow() function to avoid trouble with floating numbers)
int residu(int N)
{
int i=0;
while(N>=1){
N=N/10;
i++;
}
return i;
}
//exponentiating a number a by a number b
int power(int a, int b){
int i;
int res=1;
for (i=0;i<b;i++){res=a*res;}
return res;
}
//converting a number N
int main()
{
int i;
//the number to convert
int N;
scanf("%d",&N);
//the final decimal result
int res=0;
//we decompose N by descending powers of 10, and M is the rest
int M=0;
for(i=0;i<residu(N);i++){
// simple loop to look if there is a power of (residu(N)-1-i) in N,
// if yes we increment the binary decomposition by
// power(2,residu(N)-1-i)
if(M+ power(10,residu(N)-1-i) <= N)
{
M = M+power(10,residu(N)-1-i);
res=power(2,residu(N)-1-i)+res;
}
}
printf("%d\n",res);
}
Yes try this :
#include <stdio.h>
int main(void)
{
char bin; int dec = 0;
while (bin != '\n') {
scanf("%c",&bin);
if (bin == '1') dec = dec * 2 + 1;
else if (bin == '0') dec *= 2; }
printf("%d\n", dec);
return 0;
}
Most likely this is because you are using an int to store your binary number. An int will not store numbers above 2^31, which is 10 digits long, and 1023 is the largest number you can get with 10 binary digits.
It would be much easier for you to read your input number as a string, and then process each character of the string.
After a little experimentation, I think that your program is intended to accept a number consisting of 1's and 0's only as a base-10 number (the %d reads a decimal number). For example, given input 10, it outputs 2; given 1010, it outputs 10; given 10111001, it outputs 185.
So far, so good. Unfortunately, given 1234, it outputs 15, which is a little unexpected.
If you are running on a machine where int is a 32-bit signed value, then you can't enter a number with more than 10 digits, because you overflow the limit of a 32-bit int (which can handle ±2 billion, in round terms). The scanf() function doesn't handle overflows well.
You could help yourself by echoing your inputs; this is a standard debugging technique. Make sure the computer got the value you are expecting.
I'm not going to attempt to fix the code because I think you're going about the problem in completely the wrong way. (I'm not even sure whether it's best described as binary to decimal, or decimal to binary, or decimal to binary to decimal!) You would do better to read the input as a string of (up to 31) characters, then validate that each one is either a 0 or a 1. Assuming that's correct, then you can process the string very straight-forwardly to generate a value which can be formatted by printf() as a decimal.
Shift left is the same than multiply by 2 and is more efficient, so I think it is a more c-like answer:
#include <stdio.h>
#include <stdlib.h>
int bin2int(const char *bin)
{
int i, j;
j = sizeof(int)*8;
while ( (j--) && ((*bin=='0') || (*bin=='1')) ) {
i <<= 1;
if ( *bin=='1' ) i++;
bin++;
}
return i;
}
int main(void)
{
char* input = NULL;
size_t size = 0;
while ( getline(&input, &size, stdin) > 0 ) {
printf("%i\n", bin2int(input));
}
free(input);
}
#include <stdio.h> //printf
#include <string.h> //strlen
#include <stdint.h> //uintX_t or use int instead - depend on platform.
/* reverse string */
char *strrev(char *str){
int end = strlen(str)-1;
int start = 0;
while( start<end ){
str[start] ^= str[end];
str[end] ^= str[start];
str[start] ^= str[end];
++start;
--end;
}
return str;
}
/* transform binary string to integer */
uint32_t binstr2int(char *bs){
uint32_t ret = 0;
uint32_t val = 1;
while(*bs){
if (*bs++ == '1') ret = ret + val;
val = val*2;
}
return ret;
}
int main(void){
char binstr[] = "1010101001010101110100010011111"; //1428875423
printf("Binary: %s, Int: %d\n", binstr, binstr2int(strrev(binstr)));
return 0;
}
I am looking for a (relatively) simple way to parse a random string and extract all of the integers from it and put them into an Array - this differs from some of the other questions which are similar because my strings have no standard format.
Example:
pt112parah salin10n m5:isstupid::42$%&%^*%7first3
I would need to eventually get an array with these contents:
112 10 5 42 7 3
And I would like a method more efficient then going character by character through a string.
Thanks for your help
A quick solution. I'm assuming that there are no numbers that exceed the range of long, and that there are no minus signs to worry about. If those are problems, then you need to do a lot more work analyzing the results of strtol() and you need to detect '-' followed by a digit.
The code does loop over all characters; I don't think you can avoid that. But it does use strtol() to process each sequence of digits (once the first digit is found), and resumes where strtol() left off (and strtol() is kind enough to tell us exactly where it stopped its conversion).
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
int main(void)
{
const char data[] = "pt112parah salin10n m5:isstupid::42$%&%^*%7first3";
long results[100];
int nresult = 0;
const char *s = data;
char c;
while ((c = *s++) != '\0')
{
if (isdigit(c))
{
char *end;
results[nresult++] = strtol(s-1, &end, 10);
s = end;
}
}
for (int i = 0; i < nresult; i++)
printf("%d: %ld\n", i, results[i]);
return 0;
}
Output:
0: 112
1: 10
2: 5
3: 42
4: 7
5: 3
More efficient than going through character by character?
Not possible, because you must look at every character to know that it is not an integer.
Now, given that you have to go though the string character by character, I would recommend simply casting each character as an int and checking that:
//string tmp = ""; declared outside of loop.
//pseudocode for inner loop:
int intVal = (int)c;
if(intVal >=48 && intVal <= 57){ //0-9 are 48-57 when char casted to int.
tmp += c;
}
else if(tmp.length > 0){
array[?] = (int)tmp; // ? is where to add the int to the array.
tmp = "";
}
array will contain your solution.
Just because I've been writing Python all day and I want a break. Declaring an array will be tricky. Either you have to run it twice to work out how many numbers you have (and then allocate the array) or just use the numbers one by one as in this example.
NB the ASCII characters for '0' to '9' are 48 to 57 (i.e. consecutive).
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
int main(int argc, char **argv)
{
char *input = "pt112par0ah salin10n m5:isstupid::42$%&%^*%7first3";
int length = strlen(input);
int value = 0;
int i;
bool gotnumber = false;
for (i = 0; i < length; i++)
{
if (input[i] >= '0' && input[i] <= '9')
{
gotnumber = true;
value = value * 10; // shift up a column
value += input[i] - '0'; // casting the char to an int
}
else if (gotnumber) // we hit this the first time we encounter a non-number after we've had numbers
{
printf("Value: %d \n", value);
value = 0;
gotnumber = false;
}
}
return 0;
}
EDIT: the previous verison didn't deal with 0
Another solution is to use the strtok function
/* strtok example */
#include <stdio.h>
#include <string.h>
int main ()
{
char str[] = "pt112parah salin10n m5:isstupid::42$%&%^*%7first3";
char * pch;
printf ("Splitting string \"%s\" into tokens:\n",str);
pch = strtok (str," abcdefghijklmnopqrstuvwxyz:$%&^*");
while (pch != NULL)
{
printf ("%s\n",pch);
pch = strtok (NULL, " abcdefghijklmnopqrstuvwxyz:$%&^*");
}
return 0;
}
Gives:
112
10
5
42
7
3
Perhaps not the best solution for this task, since you need to specify all characters that will be treated as a token. But it is an alternative to the other solutions.
And if you don't mind using C++ instead of C (usually there isn't a good reason why not), then you can reduce your solution to just two lines of code (using AXE parser generator):
vector<int> numbers;
auto number_rule = *(*(axe::r_any() - axe::r_num())
& *axe::r_num() >> axe::e_push_back(numbers));
now test it:
std::string str = "pt112parah salin10n m5:isstupid::42$%&%^*%7first3";
number_rule(str.begin(), str.end());
std::for_each(numbers.begin(), numbers.end(), [](int i) { std::cout << "\ni=" << i; });
and sure enough, you got your numbers back.
And as a bonus, you don't need to change anything when parsing unicode wide strings:
std::wstring str = L"pt112parah salin10n m5:isstupid::42$%&%^*%7first3";
number_rule(str.begin(), str.end());
std::for_each(numbers.begin(), numbers.end(), [](int i) { std::cout << "\ni=" << i; });
and sure enough, you got the same numbers back.
#include <stdio.h>
#include <string.h>
#include <math.h>
int main(void)
{
char *input = "pt112par0ah salin10n m5:isstupid::42$%&%^*%7first3";
char *pos = input;
int integers[strlen(input) / 2]; // The maximum possible number of integers is half the length of the string, due to the smallest number of digits possible per integer being 1 and the smallest number of characters between two different integers also being 1
unsigned int numInts= 0;
while ((pos = strpbrk(pos, "0123456789")) != NULL) // strpbrk() prototype in string.h
{
sscanf(pos, "%u", &(integers[numInts]));
if (integers[numInts] == 0)
pos++;
else
pos += (int) log10(integers[numInts]) + 1; // requires math.h
numInts++;
}
for (int i = 0; i < numInts; i++)
printf("%d ", integers[i]);
return 0;
}
Finding the integers is accomplished via repeated calls to strpbrk() on the offset pointer, with the pointer being offset again by an amount equaling the number of digits in the integer, calculated by finding the base-10 logarithm of the integer and adding 1 (with a special case for when the integer is 0). No need to use abs() on the integer when calculating the logarithm, as you stated the integers will be non-negative. If you wanted to be more space-efficient, you could use unsigned char integers[] rather than int integers[], as you stated the integers will all be <256, but that isn't a necessity.
The program I wrote works in demographics consisting of only single Hexadecimal values. (Probably not the most elegant solution, but I'm a new programmer) My question is, how would I go about handling of multiple hexadecimal digits, such as 0xAF, or 0xFF, etc? I'm not exactly sure, and I've seemed confuse myself greatly, in the attempt. I'm not asking for someone to hold my hand, but to give me a tip where I've gone wrong in this code and thoughts on how to fix it.
Thanks :)
/* Exercise 2-3. Write the function htoi(s), which converts a string of
* hexadecimal digits (including an optional 0x or 0X) into it's equivalent
* integer value. The allowable digits are 0...9 - A...F and a...f.
*
*/
#include <stdio.h>
#include <string.h>
#define NL '\n'
#define MAX 24
int htoi(char *hexd);
int
main(void)
{
char str[MAX] = {0};
char hex[] = "0123456789ABCDEFabcdef\0";
int c;
int i;
int x = 0;
while((c = getchar()) != EOF) {
for(i = 0; hex[i] != '\0'; i++) {
if(c == hex[i])
str[x++] = c;
}
if(c == NL) {
printf("%d\n", htoi(str));
x = 0, i = x;
}
}
return 0;
}
int
htoi(char *hexd)
{
int i;
int n = 0;
for(i = 0; isdigit(hexd[i]); i++)
n = (16 * i) + (hexd[i] - '0');
for(i = 0; isupper(hexd[i]); i++) /* Let's just deal with lowercase characters */
hexd[i] = hexd[i] + 'a' - 'A';
for(i = 0; islower(hexd[i]); i++) {
hexd[i] = hexd[i] - 'a';
n = (16 + i) + hexd[i] + 10;
n = hexd[i] + 10;
}
return n;
}
Someone has alredy asked this (hex to int, k&r 2.3).
Take a look, there are many good answers, but you have to fill in the blanks.
Hex to Decimal conversion [K&R exercise]
Edit:
in
char hex[] = "0123456789ABCDEFabcdef\0";
The \0 is not necesary. hex is alredy nul terminated. Is len (0...f) + 1 = 17 bytes long.
I'll pick on one loop, and leave it to you to rethink your implementation. Specifically this:
for(i = 0; isdigit(hexd[i]); i++)
n = (16 * i) + (hexd[i] - '0');
doesn't do what you probably think it does...
It only processes the first span of characters where isdigit() is TRUE.
It stops on the first character where isdigit() is FALSE.
It doesn't run past the end because isdigit('\0') is known to be FALSE. I'm concerned that might be accidentally correct, though.
It does correctly convert a hex number that can be expressed solely with digits 0-9.
Things to think about for the whole program:
Generally, prefer to not modify input strings unless the modification is a valuable side effect. In your example code, you are forcing the string to lower case in-place. Modifying the input string in-place means that a user writing htoi("1234") is invoking undefined behavior. You really don't want to do that.
Only one of the loops over digits is going to process a non-zero number of digits.
What happens if I send 0123456789ABCDEF0123456789ABCDEF to stdin?
What do you expect to get for 80000000? What did you get? Are you surprised?
Personally, I wouldn't use NL for '\n'. C usage pretty much expects to see \n in a lot of contexts where the macro is not convenient, so it is better to just get used to it now...
I think that the MAX size of string should be either 10 or 18 instead of 24. (If you have already checked the int on your machine and followed the reasoning bellow, it would be beneficial to include it as a comment in your code.)
10 : since htoi() returns an int , int is usually 4 bytes (check your system's too), so the hexadecimal number can be atmost 8 digits in length (4bits to 1 hex digit, 8 bits to a byte), and we want to allow for the optional 0x or 0X.
18 : would be better if htoi() returned a long and its 8 bytes (again, check your system's), so the hexadecimal number can be atmost 16 digits in length, and we want to allow for the optional 0x or 0X.
Please note that that sizes of int and long are machine dependent, and please look at exercise 2.1 in the K&R book to find them.
Here is my version of a classic htoi() function to convert multiple hexadecimal values into decimal integers. It's a full working program compile it and run.
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
int htoi(const char*);
int getRawInt(char);
int main(int argc, char **argv) {
char hex[] = " ";
printf("Enter a hexadecimal number (i.e 33A)\n");
scanf("%s", hex);
printf("Hexedecimal %s in decimal is %d\n", hex, htoi(hex)); // result will be 826
return 0;
}
int htoi(const char *hex) {
const int LEN = strlen(hex) -1;
int power = 1;
int dec = 0;
for(int i = LEN; i >= 0; --i) {
dec += getRawInt(hex[i]) * power;
power *= 16;
}
return dec;
}
int getRawInt(char c) {
if(isalpha(c)) {
return toupper(c) - 'A' + 10;
} return c-'0';
}