I am writing a bit of an operating system, and I require the ability to print the addition of a variable. I have a working atoi function and so I reversed it to give me an itoa function. There is no way to access free memory, so I need to figure out the the number of digits in order to create the proper sized char array. I figured I would need to divide by 10 to get that, and then modulus the values into the correct spot. This is my c code so far:
char* itoa(int res) {
int size = 0;
int t = res;
while(t / 10 != 0) {
t = t/10;
size ++;
}
char ret[size+1];
ret[size] = '\0';
t = res;
int i = size - 1;
while(i > 0) {
ret[i] = t % 10;
t = t/10;
i--;
}
return ret;
}
As of right now, it prints nothing. What is wrong with it?
It has a few bugs. Here's a working version for positive numbers at least:
char* itoa(int res) {
int size = 0;
int t = res;
while(t / 10 != 0) {
t = t/10;
size++;
}
static char ret[64];
size++;
ret[size] = '\0';
t = res;
int i = size - 1;
while(i >= 0) {
ret[i] = (t % 10) + '0';
t = t/10;
i--;
}
return ret;
}
There are a lot of things wrong here. Most obviously:
You're returning the value of a temporary. ret is on the stack and doesn't exist after popping.
You're trying to dynamically allocate something on the stack. This might actually work, but you shouldn't unless you know what you're doing.
Put together, these basically kill your implementation. So, to be helpful, here's some untested code:
void putc(char c) {
/*Output "c" via BIOS interrupt or VGA write. Or whatever.*/
}
void print(int num) {
if (num!=0) {
/*Largest num is `2,147,483,64(7|8)`*/
char temp[10];
int i = 0;
if (num<0) { putc('-'); num=-num; }
if (num>0); else { temp[i++]='8'; num=-(num/10); } //signed wraparound
while (num>0) {
temp[i++] = num%10 + '0';
num /= 10;
}
while (--i>=0) putc(temp[i]);
} else putc('0');
}
If you can put up with the caller providing a buffer large enough for all expected outputs, then you can:
#include <stdio.h>
char * rIntToAscii(int num, char * result){
if( num == 0 ) return result;
else{
result=rIntToAscii( num/10, result );
*result = '0'+num%10;
return result+1;
}
};
void intToAscii(int num,char *output){
if (num==0){
*output++='0';
*output='\0';
}
else
{
if(num<0){
*output++='-';
num=-num;
};
*rIntToAscii(num, output) = '\0';
};
};
int main(void)
{
int test = -10;
char testOutput[ 32 ];
intToAscii(test,testOutput);
printf( "%s", testOutput );
return 0;
}
Related
I have to make a program in which I have to add the result of x dices with n faces plus or minus a constant(C). The input should be a string like this: "xDn+-C" (x, n and C must be a decimal number). For example: "4D5+6" or "6D9-5". The D just means "Dice".
I used a function to randomize the rolls but I don't know how to continue...
void initD6(void) {
srand((unsigned)time( NULL ) );
}
int D6(void) {
return ((rand()%6)+1);
}
int main(){
char Dice[4];
for(i=0; i<5; i++){
Dice[i] = D6();
return 0;
}
I don't know how should I take that input as a string and the adding or substracting, and also don't know what should I do next.
Add a struct:
struct rules
{
int dices;
int facesPerDice;
int offset;
};
Solve the dice problem:
int throwDice(int faces)
{
return (rand() % faces) + 1;
}
int playGame(struct rules rules)
{
int result = 0;
for (int i = 0; i < rules.dices; i++)
result += throwDice(rules.facesPerDice);
return result + rules.offset;
}
Solve the parsing problem:
/**
Converts a string to a unsigned int until an invalid character is found or a null character is found.
You should replace this with the function you normally use to convert a string to a integer.
*/
unsigned int stringToUInt(char *str)
{
unsigned int result = 0;
int charindex = 0;
char currentchar;
while ((currentchar = str[charindex++]) != '\0')
{
if (currentchar < '0' || currentchar > '9')
break;
result *= 10;
result += currentchar - '0';
}
return result;
}
/**
Reads a string and generates a struct rules based on it.
The string is expected to be given in the following format:
[uint]'D'[uint]['+' or '-'][uint]
where:
the first uint is the number of dices to roll
the second uint is the number of faces per dice
the third uint is the offset
Terminates the program if something goes wrong.
*/
struct rules parse(char *str)
{
struct rules result;
result.dices = stringToUInt(str);
while (*(str++) != 'D')
if (*str == '\0')
exit(1);
result.facesPerDice = stringToUInt(str);
while (*(str++) != '+' && *(str-1) != '-')
if (*str == '\0')
exit(1);
result.offset = stringToUInt(str);
result.offset *= (*(str-1) == '+' ? 1 : -1);
return result;
}
Put everything together:
int main(int argc, char *argv[])
{
srand(time(NULL));
char input[] = "3D6+9"; //You could use console input if you want
struct rules rules = parse(input);
int gameResult = playGame(rules);
printf("Game result: %d\n", gameResult);
return 0;
}
Assuming no errors in the input, a function which solves your task is:
int throw_dice(const char* s)
{
int num, sides, res;
sscanf(s,"%iD%i%i", &num, &sides, &res);
for (int i = 0; i < num; ++i) {
res += rand() % sides + 1;
}
return res;
}
For simple string parsing sscanf() is a pretty good function. For more complex tasks it's better to use a regular expression library.
As usual, don't relay on rand() for anything but the most simple dice games, with no money involved.
You can try it with the following full example:
#include <stdio.h>
int throw_dice(const char* s)
{
int num, sides, res;
sscanf(s,"%iD%i%i", &num, &sides, &res);
for (int i = 0; i < num; ++i) {
res += rand() % sides + 1;
}
return res;
}
void throw_multiple_times(const char* s, int times)
{
printf("%s: ", s);
for (int i = 0; i < times; ++i) {
printf("%i ", throw_dice(s));
}
printf("\n");
}
int main(void)
{
srand((unsigned)time(NULL));
const char* s;
throw_multiple_times("4D5+6", 100);
throw_multiple_times("6D9-5", 100);
return 0;
}
Test it here.
I'm trying to convert an integer to a char* pointer so I can properly send the argument into another function. Is there anyway to do this without atoi?
int number=2123, number2= 1233;
char* arg[];
arg[0] = number;
arg[1] = number2;
**Sorry for not making things clear so basically I want the arg[0] to equal the string rep of the number, so that i can send it into a function like this: converted(char* arg);
i would change the parameter data type but it has to be that pointer to send in.
If you assume that a pointer is always at least the same size as an integer (are there any exceptions to this?) you can safely convert integers to pointers and back with these macros:
#define INT2POINTER(a) ((char*)(intptr_t)(a))
#define POINTER2INT(a) ((int)(intptr_t)(a))
Or if that other function isn't your function, but a function that wants the integers as string you could use asprintf() like this:
asprintf(&arg[0],"%d",number);
asprintf(&arg[1],"%d",number2);
But asprintf is not posix standard so it might not be available on all systems. You could use sprintf() (or snprintf() so be on the safe side) instead, but then you need to calculate the string length first.
to convert an integer to a char* pointer so I can properly send the argument into another function.
Create a string representation of the number by calling a helper function with a char array via a compound literal to convert the number. The string will be valid for the function and to the end of the block of code. Adequate sizing of the string is important - leave that for a separate exercise. Code here uses 41, enough for 128 bit int. No need for a memory management via malloc()/free() for such a small buffer.
char *my_itoa(char *dest, int i) {
sprintf(dest, "%d", i);
return dest;
}
#define ITOA(n) my_itoa((char [41]) { 0 }, (n) )
int main(void) {
int number=2123, number2= 1233;
printf("<%s> <%s>\n", ITOA(number), ITOA(number2));
printf("<%s> <%s> <%s>\n", ITOA(INT_MIN), ITOA(0), ITOA(INT_MAX));
}
Output
<2123> <1233>
<-2147483648> <0> <2147483647>
Here is the function you"re looking for:
char *int_to_char(int nb)
{
int div;
char *str;
int i;
int size;
int sign;
i = -1;
sign = 1;
size = get_int_lenght(nb);
if (!(str = malloc(sizeof(char) * (size + 1))))
return (NULL);
if (nb < 0)
{
sign *= -1;
nb *= -1;
}
if (nb == 0)
{
str[++i] = '0';
str[i + 1] = 0;
return (str);
}
while (nb > 0)
{
str[++i] = (nb % 10) + '0';
nb /= 10;
}
if (sign < 0)
str[++i] = '-';
str[i + 1] = 0;
return (my_revstr(str));
}
With revstr function:
char *my_revstr(char *str)
{
int i;
int j;
char tmp;
i = -1;
j = strlen(str);
while (++i < j)
{
tmp = str[i];
str[i] = str[--j];
str[j] = tmp;
}
return (str);
}
And get_int_lenght function:
int get_int_lenght(int nb)
{
int size;
size = 0;
if (nb <= 0)
{
size++;
nb *= -1;
}
while (nb > 0)
{
size++;
nb /= 10;
}
return (size);
}
Task is to convert int to char . Here is my code for converting
#include <conio.h>
#include <stdio.h>
main(void)
{
int number,reserve ;
scanf_s("%d",&number);
if (number > 0 || number == 0)
{
do
{
reserve = number % 10;
printf("%c", reserve + '/0');
number /= 10;
} while (number != 0);
}
else
{
number *= -1;
printf("-");
do
{
reserve = number % 10;
printf("%c", reserve + '/0');
number /= 10;
} while (number != 0);
}
_getch();
return 0;
}
The problem is this is printing the result in the reversed of what I want. So I'm searching for a way to reverse it back. However my code is printing char by char. Probably I just need to save all chars into some string but I`m not sure of how do it. Appreciate any help.
Have you tried storing them in an array and printing the array in reverse?
#include <stdio.h>
int main(void)
{
int number,reverse,i ;
scanf("%d",&number);
char string[20];
int index = 0;
if (number< 0){
number *= -1;
printf("-");
}
do
{
reverse = number % 10;
//printf("%c", reverse);
string[index++] = reverse;
number /= 10;
} while (number != 0);
for (i = index ; i >= 0 ; i--)
printf("%c", string[i]);
return 0;
}
As you assumed in your question, you need to store the characters to print them reverse.
Using an array for this task is quite simple:
// I never know how much memory I need ...
char reverse[200];
int i = 0;
reverse[i++] = next calculated character
later
while (i) {
print reverse[--i];
}
This method should suffice in converting an integer to a string without using any standard library functions.
void ReverseString(char *sBuf, int iLength)
{
char *String1 = NULL;
char *String2 = NULL;
for (String1 = sBuf, String2 = sBuf + iLength - 1; String2 > String1; ++String1, --String2)
{
*String1 ^= *String2;
*String2 ^= *String1;
*String1 ^= *String2;
}
}
int YourVeryOwn_itoa(int iINValue, char *sOUTValue)
{
unsigned short writePosition = 0;
if (iINValue < 0)
{
sOUTValue[writePosition++] = '-';
}
do
{
sOUTValue[writePosition++] = (unsigned char)48 + (iINValue % 10);
} while ((iINValue /= 10) > 0);
sOUTValue[writePosition] = '\0';
ReverseString(sOUTValue, writePosition);
return writePosition;
}
void main()
{
char buf[255];
YourVeryOwn_itoa(123456789, buf);
printf("%s", buf);
}
My homework requires me to write a program that takes a string from the terminal (argc and argv) and print every possible permutation. I have tried to use Heap's Algorithm, but it doesn't seem to be working out. Below is my function.
char **getPermutation(char * in)
{
//n is the size of the input string.
int n = strlen(in);
int count[n];
int counter= 0;
char copy[n];
char **permutations = malloc(sizeof(char*)*(factorial(n)));
permutations[0] = in;
strcpy(in, copy);
counter++;
for( int i = 1; i < n;)
{
if (count[i] < i){
if (i%2==0){
swap(&in[0],&in[i]);
}
else
{
swap(&in[count[i]],&in[i]);
}
permutations[counter] = in;
strcpy(in, copy);
counter++;
count[i]++;
i = 1;
}
else
{
count[i] = 0;
i++;
}
}
return permutations;
}
The function must return the pointer to the character pointer as specified by the instructions. That's also why there are so many variables (although, I'm not really sure what to do with the copy of the string. I'm fairly sure I need it). Testing shows that the program will loop, often too much and eventually hit a seg fault. It doesn't seem like the swapped strings make it into the returned array on top of that.
Below is a rework of your code with cleaned up memory allocation and it addresses some problems mentioned in the above comments. Additionally, you have a bug in your algorithm, this statement strcpy(in, copy); keeps you from getting all the permutations (causes repeats instead.) This code works but isn't finished, it can use more error checking and other finishing touches:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
unsigned int factorial(unsigned int n)
{
/* ... */
}
void swap(char *a, char *b)
{
/* ... */
}
char **getPermutations(const char *input)
{
char *string = strdup(input);
size_t length = strlen(string);
char **permutations = calloc(factorial(length), sizeof(char *));
int *counts = calloc(length, sizeof(int)); // point to array of ints all initialized to 0
int counter = 0;
permutations[counter++] = strdup(string);
for (size_t i = 1; i < length;)
{
if (counts[i] < i)
{
if (i % 2 == 0)
{
swap(&string[0], &string[i]);
}
else
{
swap(&string[counts[i]], &string[i]);
}
permutations[counter++] = strdup(string);
counts[i]++;
i = 1;
}
else
{
counts[i++] = 0;
}
}
free(counts);
free(string);
return permutations;
}
int main(int argc, char *argv[])
{
char *string = argv[1];
char **permutations = getPermutations(string);
unsigned int total = factorial(strlen(string));
for (unsigned int i = 0; i < total; i++)
{
printf("%s\n", permutations[i]);
}
free(permutations);
return 0;
}
OUTPUT
> ./a.out abc
abc
bac
cab
acb
bca
cba
>
I am doing the easy challenge on /r/dailyprogrammer in C. I actually managed to write over a hundred lines of code, and spend a couple hours total on it (usually I end up chickening out), and figure out all the compiler errors. But now, when I run it, I immediately get a segfault. What I'm doing wrong?
Yes, it's sort of homework help, but at least I tried before coming here.
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#define MAXLEN 50
#define LIMIT 20
#define TRUE 1
#define FALSE 0
char* reverse(char *a);
char* ltoa(long i);
long atol(char *a); /* NOTE: Handle leading zeros. */
long palindromize(long p);
int ispalindrome(long p);
/* Meat. */
int main(int argc, char *argv[])
{
long p;
int count, limr;
p = (long) argv[1];
count = 0;
limr = FALSE;
while (TRUE)
{
p = palindromize(p);
count++;
if (ispalindrome(p))
{
break;
} else if (count == LIMIT) {
limr = TRUE;
break;
}
}
if (limr)
{
printf("It might be a palindrome, but it'd take quite a while to find out.\nLast number reached: %ld\n", p);
} else {
printf("Palindrome found! After %d steps, we've found %ld.\n", count, p);
}
}
long palindromize(long p)
{
return (atol(reverse(ltoa(p)))) + p;
}
int ispalindrome(long p)
{
char *t, *r;
t = ltoa(p);
r = reverse(ltoa(p));
if (t == r)
{
return TRUE;
} else {
return FALSE;
}
}
/* Utility functions. */
/* Converts string to long integer. */
long atol(char *a)
{
int i, sign;
long r;
for (i = 0; a[i] == '0'; i++)
{
i++;
}
if (a[0] == '-' || a[-1] == '-')
{
sign = -1;
}
else
{
sign = 1;
}
for (; isdigit(a[i]); i++)
{
r = 10 * r + (a[i] - '0');
}
return r * sign;
}
/* Converts long integer to string.
This and reverse are based on the ones in K&R. */
char* ltoa(long n)
{
char *a;
int i, sign;
if ((sign = n) < 0)
{
n = -n;
}
i = 0;
do
{
a[i++] = n % 10 + '0';
} while ((n /= 10) > 0);
if (sign < 0)
{
a[i++] = '-';
}
a[i] = '\0';
return reverse(a);
}
char* reverse(char *s)
{
int i, j;
char c;
for (i = 0, j = strlen(s)-1; i<j; i++, j--) {
c = s[i];
s[i] = s[j];
s[j] = c;
}
return s;
}
In ltoa you declare char *a; but never malloc any space for it. When you access a[i] it crashes. For problems like this, remember a simple first debugging step is to add print statements everywhere so you can at least pinpoint where the error is occurring.
Looks like your ispalindrome is wrong too, but not in a seg fault way. I'll let you figure out why =D
char* ltoa(long n)
{
char *a;
int i, sign;
This is, in fact, a very common error. char *a is a pointer to a character (possibly a character array). But you don't tell it where the character are in memory. So it is pointing to some random location.
You can either reserve characters locally by using char a[100] or so, but that will land you with problems on returning from the function. Or you can reserve memory with char *a = (char *)malloc(100). Or you could consider palindromize the input string itself, and leave the memory problems to the caller.