some day, i wanted to convert in C an integer into a char *, this int can be negative.
I wasn't able to use sprintf ,snprintf neither, so how do i do that ?
To roll one's own itoa()-like function, first one must address how to handle memory. The easiest is to use a large-enough memory for all possible int values (INT_MIN).
The buffer required size is mathematically ceiling(log10(-INT_MIN))+3. This can be approximated with:
#include <limits.h>
#define INT_STR_SIZE (sizeof(int)*CHAR_BIT/3 + 3)
Then build the digits up one-by-one starting with the least significant digit using %10 and then /10 to reduce the value.
By using a do loop, code catches the corner case of x==0 as at least one digit is made.
This code avoids if (x < 0) { x = -x; ... as negating INT_MIN (or multiplying by -1 leads to int overflow, which is UB.
#include <limits.h>
#define INT_STR_SIZE (sizeof(int)*CHAR_BIT/3 + 3)
char *my_itoa(char *dest, size_t size, int x) {
char buf[INT_STR_SIZE];
char *p = &buf[INT_STR_SIZE - 1];
*p = '\0';
int i = x;
do {
*(--p) = abs(i%10) + '0';
i /= 10;
} while (i);
if (x < 0) {
*(--p) = '-';
}
size_t len = (size_t) (&buf[INT_STR_SIZE] - p);
if (len > size) {
return NULL; // Not enough room
}
return memcpy(dest, p, len);
}
With C99 or later, code can handle the buffer creation with a compound literal allowing separate buffers for each mt_itoa() call.
// compound literal C99 or later
#define MY_ITOA(x) my_itoa((char [INT_STR_SIZE]){""}, INT_STR_SIZE, x)
int main(void) {
printf("%s %s %s %s\n", MY_ITOA(INT_MIN), MY_ITOA(-1), MY_ITOA(0), MY_ITOA(INT_MAX));
return (0);
}
Output
-2147483648 -1 0 2147483647
to convert from integer to char* use the function itoa().
/* itoa example */
#include <stdio.h>
#include <stdlib.h>
int main ()
{
int i;
char buffer [33];
printf ("Enter a number: ");
scanf ("%d",&i);
itoa (i,buffer,10);
printf ("decimal: %s\n",buffer);
itoa (i,buffer,16);
printf ("hexadecimal: %s\n",buffer);
itoa (i,buffer,2);
printf ("binary: %s\n",buffer);
return 0;
}
Related
I wrote this function tat checks for upper, lower and digits in a string but when I'm trying to run the code this pops up and cant seem to understand the problem.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#define size 50
void statistics(char str[], int *lower, int *upper, int *digits) {
for (int i = 0; i < size; i++) {
if (islower(str[i]) != 0) {
*lower = *lower + 1;
} else
if (isupper(str[i]) != 0) {
*upper = *upper + 1;
} else
if (isalpha(str[i])) {
*digits = *digits + 1;
}
}
}
int main() {
char str[size] = { " " };
int upper = 0, lower = 0, digits = 0;
printf("Enter a string:\n");
gets_s(str);
statistics(&str[size], &lower, &upper, &digits);
printf("Lower: %d\nUpper: %d\nDigits %d", lower, upper, digits);
return 0;
}
There are multiple problems in your code:
the gets_s() function is not portable: it is optional and not supported on many systems. You forget to pass the array size, hence causing undefined behavior. The compiler should output a diagnostic that you should not ignore. You should use fgets() instead.
you should not pass char values to the isupper() and similar functions because they are only defined for values of the type unsigned char and the special negative value EOF. Use an unsigned char variable or cast the str[i] argument as (unsigned char)str[i].
you pass the address of the end of the char array instead of the beginning. Just pass str as the argument to statistics. The statistics function reads characters beyond the end of the array, invoking undefined behavior, and one of these bytes happens to be a negative char value less than -1 triggering the diagnostic in your Visual C++ compiler runtime. The error message is difficult to interpret, the IDE should point you to the calling code.
you iterate on the whole array, beyond the null terminator. The contents of the array is undefined beyond the null terminator set by gets_s() or fgets(). Just stop at the null terminator.
you test if (isalpha(ch)) where you probably mean to use if (isdigit(ch))
the isxxx functions return a non zero value for true and zero for false. It is idiomatic in C to just write if (isdigit(c)) instead of if (isdigit(c) != 0) which seems redundant.
defining size as a macro is error prone. Use upper case and a more explicit name.
Here is a modified version:
#include <ctype.h>
#include <stdio.h>
#define LINE_SIZE 50
void statistics(const char *str, int *lower, int *upper, int *digits) {
while (*str != '\0') {
unsigned char ch = *str++;
if (islower(ch)) {
*lower += 1;
} else
if (isupper(ch)) {
*upper += 1;
} else
if (isdigit(ch) {
*digits += 1;
}
}
}
int main() {
char str[LINE_SIZE];
int upper = 0, lower = 0, digits = 0;
printf("Enter a string:\n");
if (fgets(str, sizeof str, stdin)) {
statistics(str, &lower, &upper, &digits);
printf("Lower: %d\nUpper: %d\nDigits %d", lower, upper, digits);
}
return 0;
}
This question already has answers here:
Digital Root in c
(2 answers)
Closed 11 months ago.
So you have to do:
11 = 1+1 = 2
3578 = 3+5+7+8 = 23 = 2+3 = 5
But the problem is that the number can be very large(consist of 10,000 digits)
But even with the easiest entrances it doesn't work:
Input : 11
Output: 2798 (and it always changes, but remains a 4-digit number)
Can someone explain why is this happening?
And how can I summarize each digit of a very large number?
You got that huge number becuase your program is adding the ASCII value of various characters.
Some improvements:
Don't use "%s", use "%<WIDTH>s", to avoid buffer-overflow
Use size_t to iterate through an array, instead of unsigned long long int
Instead of using bare return 0;, use return EXIT_SUCCESS;, which is defined in the header file stdlib.h.
always check whether scanf() input was successful or not
Don't check for '\n', because string from scanf() ends at both SPACES and NEWLINE.
adding +1 to array size for NULL terminating character
Use "%zu" instead of "%lld" for size_t
Final Code:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main(void) {
char buffer[10001] = {0};
if(scanf("%10000s", buffer) != 1)
{
perror("bad input");
return EXIT_FAILURE;
}
size_t result = 0;
for(size_t i = 0; buffer[i]; i++) {
if(isdigit(buffer[i])){
result += buffer[i] - '0';
}
else {
perror("only digits are valid");
return EXIT_FAILURE;
}
}
printf("%zu\n", result);
return EXIT_SUCCESS;
}
Output:
1112
5
TRY IT ONLINE
You can do it without occupying memory
#include <ctype.h>
#include <stdio.h>
int main(void) {
int sum = 0;
for (;;) {
int ch = getchar();
if (!isdigit((unsigned char)ch)) break; // leave loop with ENTER, EOF, 'a', ...
sum += ch - '0';
}
printf("sum of digits is %d.\n", sum);
return 0;
}
Edit: see code running at ideone
Wiki Digital Root provides a shortcut for getting the final single digit.
Validate your input string has only numeric digits
Find the sum of all digits in ASCII form
Make use of congruence formula to get the result.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define MAX_NUM_LEN 10000
int digitRoot (int n) {
if (0 == n) return 0;
return (0 == (n % 9)) ? 9 : (n % 9);
}
int main () {
char str_num [MAX_NUM_LEN];
printf ("Finding Digital Root\nEnter a number : ");
if (NULL == fgets (str_num, sizeof (str_num), stdin)) {
perror ("Reading input string");
return 2;
}
int slen = strlen (str_num);
// remove new line if found
if ('\n' == str_num[slen - 1]) str_num[--slen] = '\0';
// validate input
int digitSum = 0;
for (int ni = 0; ni < slen; ++ni) {
if (!isdigit ((unsigned char) str_num[ni])) {
printf ("\nERROR: Invalid digit [%c]\n", str_num[ni]);
return 1;
}
digitSum += str_num[ni] - '0';
}
printf ("\nDigital Root is [%d]\n", digitRoot (digitSum));
return 0;
}
I am trying to write a small bit of code where i can scan a binary digit, like 00110011, and get this into an integer as a number. So 00110011 would be 51.
The code i made for this goes like this
int main()
{
unsigned char byte;
int d;
scanf("%8s", &byte);
d = byte;
printf("%d,%c",d, byte);
return 0;
}
This however, give me an output of 48. 00000001 also gives me 48 and so does anything else.
I know whats going wrong, it sees the string of zeros and ones as a single 0 and since its character is 0x30, or 0d48, it outputs 48. I wont to know if there is a way to get around this adn scan this in as the binary equivelent.
Your code does not work at all:
you scan up to 8 characters plus a null terminator, passing the address of a single byte variable: this has undefined behavior.
d = byte does not perform any conversion. the character '0' was read into byte and its ASCII value is stored into d, namely 48 as output by your program.
Furthermore, there is no standard conversion specifier for binary encoding in scanf(). Reading a string is a good approach, but you should pass a larger buffer and use a loop to convert to binary:
#include <ctype.h>
#include <stdio.h>
int main() {
char buf[100];
/* read a sequence of at most 99 binary digits into buf */
if (scanf(" %99[01]", buf) == 1) {
unsigned int d = 0;
/* convert the binary digits one at a time into integer d */
for (int i = 0; buf[i]; i++) {
d = (d << 1) | (buf[i] - '0');
}
/* print value as a number */
printf("%s -> %d\n", buf, d);
if (d == (unsigned char)d && isprint(d)) {
/* print value as a character if printable */
printf("%s -> %c\n", buf, d);
}
}
return 0;
}
You can also use strtoul() to convert a number expressed as a string of binary digits (or in any other base up to 36):
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
int main() {
char buf[100];
/* read a sequence of at most 99 binary digits into buf */
if (scanf(" %99[01]", buf) == 1) {
unsigned long d = strtoul(buf, NULL, 2);
/* print value as a number */
printf("%s -> %lu\n", buf, d);
if (d == (unsigned char)d && isprint((unsigned char)d)) {
/* print value as a character if printable */
printf("%s -> %c\n", buf, (unsigned char)d);
}
}
return 0;
}
Note however that the behavior of strtoul() will differ from the first code: strtoul() will return ULONG_MAX on overflow, whereas the first example would just compute the low order bits of the binary string.
I found this simple function that should be easy to understand and it does the trick. Its a algorithm that follows how you would naturally do it in real life with a pen and paper however you're gonna need -lm when you compile it(the gcc command) to include the math library, however you can get around the pow() and include problems if you just do a for loop.
#include <stdio.h>
#include <math.h>
int todecimal(long bno){
int dno = 0, i = 0, rem;
while (bno != 0) {
rem = bno % 10;
bno /= 10;
dno += rem * pow(2, i);
++i;
}
return dno;
}
I want to check if a number given by a user is an integer or not in another way i want to verify if the input data is between −(2)^31= −2,147,483,648 and ((2)^31) - 1 =2,147,483,647
this is my code:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main()
{
int x;
int y = pow(3,31) * (-1);
int z = pow(3,32) - 1;
printf("\n\ty = %d et z = %d \n\n", y, z);
scanf("%d", &x);
if ((x < y) || (x > z)) {
printf("x is not an integer");
}
else {
printf("x is an integer");
}
return 0;
}
But while running the program the result always showing me x is integer even if x is greater than 2,147,483,647 or lesser than −2,147,483,648.
Testing whether input is a valid int decimal numeral or is a decimal numeral in [-231, 231) is actually a bit complicated. The C standard does not provide a direct way to do this. What we can do is:
Read characters and check to see whether they are in the expected form: spaces, an optional minus sign (hyphen), and digits. (Any non-digits after the digits will be allowed and ignored.)
Try using strtol to convert the numeral to a long. We use strtol because there is no C-standard library routine for converting to an int (or your fixed bounds using 231) that provides error indications.
Compare the long produced by strtol to the int bounds.
Example code for int bounds follows. If you want bounds of -2147483648 and 2147483647 instead, substitute those for INT_MIN and INT_MAX. To be completely safe, the code should actually use long long and strtoll, since the C standard does not require long to be able to represent −2147483648.
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
// Prepare a buffer.
size_t BufferSize = 100, BufferUsed = 0;
char *Buffer = malloc(BufferSize * sizeof *Buffer);
// Skip white space.
int c;
do
c = getchar();
while (isspace(c));
if (c == EOF)
{
printf("Input is not an int: EOF before \"-\" or digit seen.\n");
exit(EXIT_SUCCESS);
}
// Accept a hyphen as a minus sign.
if (c == '-')
{
Buffer[BufferUsed++] = c;
c = getchar();
}
// Accept digits.
while (isdigit(c))
{
Buffer[BufferUsed++] = c;
if (BufferSize <= BufferUsed)
{
BufferSize *= 2;
printf("Realloc: size = %zu, used = %zu.\n", BufferSize, BufferUsed);
char *NewBuffer = realloc(Buffer, BufferSize * sizeof *NewBuffer);
if (!NewBuffer)
{
fprintf(stderr, "Error, unable to allocate %zu bytes.\n",
BufferSize);
exit(EXIT_FAILURE);
}
Buffer = NewBuffer;
}
c = getchar();
}
// Ensure we saw at least one digit (input is not blank or just a hyphen).
if (BufferUsed == 0 || BufferUsed == 1 && Buffer[0] == '-')
{
printf("Input is not an int: No digits present.\n");
exit(EXIT_SUCCESS);
}
// Put back the unaccepted character, if any.
if (c != EOF)
ungetc(c, stdin);
// Terminate the string.
Buffer[BufferUsed] = 0;
// Attempt to convert the numeral to long.
char *End;
errno = 0;
long x = strtol(Buffer, &End, 10);
// Test whether strtol succeeded.
if (*End)
{
/* I do not expect this to occur since we already tested the input
characters.
*/
printf("Input is not an int: strtol rejected %c.\n", *End);
exit(EXIT_SUCCESS);
}
if (errno == ERANGE)
{
printf("Input is not an int: strtol reported out of range.\n");
exit(EXIT_SUCCESS);
}
if (x < INT_MIN || INT_MAX < x)
{
printf("Input is not an int: Value is outside bounds.\n");
exit(EXIT_SUCCESS);
}
printf("Input is an int, %ld.\n", x);
free(Buffer);
}
Maybe i think i should store the number on a char array and check if it contains the float character '.'
#include<stdio.h>
#include<string.h>
#include <stdlib.h>
int main(){
char number[10];
int flag=0,i = 0;
printf("\n\nEnter a number: ");
scanf("%s", number);
while(number[i++] != '\0'){
if(number[i] == '.'){
flag = 1;
break;}}
if(flag)
printf("\n\n\n\tyou Entered a Floating Number not an integer number\n\n");
else
printf("\n\n\n\t you Entered an integer Number\n\n");
return 0;}
I'm trying to create a function which can determine if an input can be converted perfectly into a double and then be able to store it into an array of doubles. For example, an input of "12.3a" is invalid. From what I know, strtod can still convert it to 12.3 and the remaining will be stored to the pointer. In my function doubleable, it filters whether the input string consists only of digits. However, I'm aware that double has "." like in "12.3", and my function will return 'X' (invalid).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char doubleable (char unsure[], int length){
int i;
int flag;
for (i=0; i<length; i++ ){
if(isdigit(unsure[i]==0)){
printf("You have invalid input.\n");
flag=1;
break;
}
}
//check for '.' (?)
if(flag==1)
return 'X';
else
return 'A';
}
int main(){
char input [10];
double converted[5];
char *ptr;
int i;
for(i=0; i<5; i++){
fgets(input, 10, stdin);
//some code here to replace '\n' to '\0' in input
if(doubleable(input, strlen(input))=='X'){
break;
}
converted[i]=strtod(input, &ptr);
//printf("%lf", converted[i]);
}
return 0;
}
I'm thinking of something like checking for the occurrence of "." in input, and by how much (for inputs like 12.3.12, which can be considered invalid). Am I on the right track? or are there easier ways to get through this? I've also read about the strtok function, will it be helpful here? That function is still quite vague to me, though.
EDIT:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
double HUGE_VAL= 1000000;
void string_cleaner (char *dirty){
int i=0;
while(1){
if (dirty[i]=='\n'){
dirty[i]='\0';
break;
}
i++;
}
}
int doubleable2(const char *str)
{
char *end_ptr;
double result;
result = strtod(str, &end_ptr);
if (result == HUGE_VAL || result == 0 && end_ptr == str)
return 0; // Could not be converted
if (end_ptr < str + strlen(str))
return 0; // Other input in the string after the number
return 1; // All of the string is part of the number
}
int main(){
char input [10];
double converted[10];
char *ptr;
int i;
for(i=0; i<5; i++){
while (1){
printf("Please enter:");
fgets(input, 10, stdin);
string_cleaner(input);
if (doubleable2(input)==0)
continue;
else if (doubleable2(input)==1)
break;
}
converted[i]=strtod(input, &ptr);
printf("%lf\n", converted[i]);
}
return 0;
}
thank you! It works just fine! I have a follow up question. If I enter a string that is too long, the program breaks. If I am to limit the input to, let's say, a maximum of 9 characters in input[], how am I to do that?
from what I understand about fgets(xx, size, stdin), it only gets up to size characters (including \n, \0), and then stores it to xx. In my program, I thought if I set it to 10, anything beyond 10 will not be considered. However, if I input a string that is too long, my program breaks.
You can indeed use strtod and check the returned value and the pointer given as the second argument:
int doubleable(const char *str)
{
const char *end_ptr;
double result;
result = strtod(str, &end_ptr);
if (result == HUGE_VAL || result == 0 && end_ptr == str)
return 0; // Could not be converted
if (end_ptr < str + strlen(str))
return 0; // Other input in the string after the number
return 1; // All of the string is part of the number
}
Note that you need to remove the newline that fgets most of the time adds to the string before calling this function.
From what I know, strtod can still convert it to 12.3 and the remaining will be stored to the pointer.
That is correct – see its man page:
If endptr is not NULL, a pointer to the character after the last character used in the conversion is stored in the location referenced by endptr.
So use that information!
#include <stdio.h>
#include <stdbool.h>
#include <errno.h>
bool doable (const char *buf)
{
char *endptr;
errno = 0;
if (!buf || (strtod (buf, &endptr) == 0 && errno))
return 0;
if (*endptr)
return 0;
return 1;
}
int main (void)
{
printf ("doable: %d\n", doable ("12.3"));
printf ("doable: %d\n", doable ("12.3a"));
printf ("doable: %d\n", doable ("abc"));
printf ("doable: %d\n", doable (NULL));
return 0;
}
results in
doable: 1
doable: 0
doable: 0
doable: 0
After accept answer
Using strtod() is the right approach, but it has some challenges
#include <ctype.h>
#include <stdlib.h>
int doubleable3(const char *str) {
if (str == NULL) {
return 0; // Test against NULL if desired.
}
char *end_ptr; // const char *end_ptr here is a problem in C for strtod()
double result = strtod(str, &end_ptr);
if (str == end_ptr) {
return 0; // No conversion
}
// Add this if code should accept trailing white-space like a \n
while (isspace((unsigned char) *endptr)) {
endptr++;
}
if (*end_ptr) {
return 0; // Text after the last converted character
}
// Result overflowed or maybe underflowed
// The underflow case is not defined to set errno - implementation defined.
// So let code accept all underflow cases
if (errno) {
if (fabs(result) == HUGE_VAL) {
return 0; // value too large
}
}
return 1; // Success
}
OP's code
No value with result == 0 in result == 0 && end_ptr == str. Simplify to end_ptr == str.
Instead of if (end_ptr < str + strlen(str)), a simple if (*end_ptr) is sufficient.
if (result == HUGE_VAL ... is a problem for 2 reasons. 1) When result == HUGE_VAL happens in 2 situations: A legitimate conversion and an overflow conversion. Need to test errno to tell the difference. 2) the test should be if (fabs(result) == HUGE_VAL ... to handle negative numbers.