K&R2 Exercise 4-12

L

Lax

Here is my 1st attempt at the solution for K&R2 Exercise 4-12:

void itoa(int n, char *s)
{

if (n < 0)
{
*s++ = '-';
n = -n;
}

if( n/10 > 0 )
itoa( n/10, s );

*s++ = n%10 + '0';
*s = 0;
}


I realize why my code is not working, it's because the increments
don't carry forward when the recursive calls "unwind."

I can solve this this way:


void itoa2(int n, char *s)
{
static char *p = 0;

if(p == 0)
p = s;

if (n < 0)
{
*p++ = '-';
n = -n;
}

if( n/10 > 0 )
itoa2( n/10, p );

*p++ = n%10 + '0';
*p = 0;
}


This keeps the p pointer up-to-date while the recursive calls unwind.

My quesiton is, does anyone know of a solution that doesn't require
the introduction of a static duration variable? Something like a small
modifcation to my first attempt?
 
B

Bartc

Lax said:
Here is my 1st attempt at the solution for K&R2 Exercise 4-12:

void itoa(int n, char *s)
{

if (n < 0)
{
*s++ = '-';
n = -n;
}

if( n/10 > 0 )
itoa( n/10, s );

*s++ = n%10 + '0';
*s = 0;
}

Try this; it uses a local variable, and calls strlen a lot, so is a bit
slower:

void itoa(int n, char *s)
{int len;

*s=0;

if (n < 0)
{
*s++ = '-';
n = -n;
}

if( n>=10 )
itoa( n/10, s );
len=strlen(s);
s[len]= n%10 + '0';
s[len+1]=0;
}
 
B

Ben Bacarisse

Lax said:
Here is my 1st attempt at the solution for K&R2 Exercise 4-12:
I can solve this this way:

void itoa2(int n, char *s)
{
static char *p = 0;

if(p == 0)
p = s;

if (n < 0)
{
*p++ = '-';
n = -n;

Small point: in C -n can overflow. I am sure that K&R don't intend
that you deal with this here, but a real itoa would have to.
}

if( n/10 > 0 )
itoa2( n/10, p );

*p++ = n%10 + '0';
*p = 0;
}


This keeps the p pointer up-to-date while the recursive calls unwind.

My quesiton is, does anyone know of a solution that doesn't require
the introduction of a static duration variable? Something like a small
modifcation to my first attempt?

Well, not a tweak but a general idea: recursion works particularly
well with functions that have simple value parameters and return useful
results. In fact, that pattern can be grown into a whole methodology
of programming.

Since the interface of itoa is fixed, you need a helper function. The
trick is thinking up the most helpful function you can imagine. Often
that function can then be written in terms of itself and the desired
function becomes a simple call of it with a little extra
house-keeping. For example:

Given 'char *aux_itoa(int n, char *s);' that takes a positive 'n',
puts the character representation of 'n' into 's' and returns a pointer
to the end of that representation, could you write both itoa and also
aux_itoa?
 
M

Martin

Here is my 1st attempt at the solution for K&R2 Exercise 4-12:

void itoa(int n, char *s)
{

if (n < 0)
{
*s++ = '-';
n = -n;
}

if( n/10 > 0 )
itoa( n/10, s );

*s++ = n%10 + '0';
*s = 0;
}

Any comments on Tondo & Gimpel's solution, in THE C ANSWER BOOK?

#include <math.h>

/* itoa: convert n to characters in s; recursive */
void itoa(int n, char s[])
{
static int i;

if ( n / 10 )
itoa(n / 10, s);
else {
i = 0;
if (n < 0)
s[i++] = '-';
}
s[i++] = abs(n) % 10 + '0';
s = '0';
}
 
F

Flash Gordon

Martin wrote, On 15/04/08 13:44:

Any comments on Tondo & Gimpel's solution, in THE C ANSWER BOOK?

If you have correctly presented it, then it is not very good.
#include <math.h>

This header is not needed.
/* itoa: convert n to characters in s; recursive */
void itoa(int n, char s[])
{
static int i;

if ( n / 10 )
itoa(n / 10, s);
else {
i = 0;
if (n < 0)
s[i++] = '-';
}
s[i++] = abs(n) % 10 + '0';

For abs you should include stdlib.h
s = '0';
}


Now try running it with the following main function calling it...

int main(void)
{
char s1[]="abcdef",s2[]="ghijk";
itoa(1,s1);
itoa(2,s2);
printf("1='%s' 2='%s'\n",s1,s2);
return 0;
}

Then try reading the code and see if you can find the error.
 
P

Peter Nilsson

Lax said:
Here is my 1st attempt at the solution for K&R2 Exercise 4-12:

void itoa(int n, char *s)
My quesiton is, does anyone know of a solution that doesn't require
the introduction of a static duration variable? Something like a small
modifcation to my first attempt?

Google comp.lang.c for itoa. This is not the first time the function
has been discussed.
 
B

Bartc

Martin said:
Here is my 1st attempt at the solution for K&R2 Exercise 4-12:

void itoa(int n, char *s)
{

if (n < 0)
{
*s++ = '-';
n = -n;
}

if( n/10 > 0 )
itoa( n/10, s );

*s++ = n%10 + '0';
*s = 0;
}

Any comments on Tondo & Gimpel's solution, in THE C ANSWER BOOK?

#include <math.h>

/* itoa: convert n to characters in s; recursive */
void itoa(int n, char s[])
{
static int i;

The OP wanted something without a 'static duration variable'.


-- Bartc
 
U

user923005

Any comments on Tondo & Gimpel's solution, in THE C ANSWER BOOK?
#include <math.h>
/* itoa: convert n to characters in s; recursive */
void itoa(int n, char s[])
{
     static int i;

The OP wanted something without a 'static duration variable'.

As a sensible solution, snprintf() springs to mind. A simpler way to
remove the static and remain recursive is to have one top level
function that calls the recursive function and passes in an
initialized counter.
 
W

Willem

Lax wrote:
) Here is my 1st attempt at the solution for K&R2 Exercise 4-12:
)
) void itoa(int n, char *s)
) {
)
) if (n < 0)
) {
) *s++ = '-';
) n = -n;
) }
)
) if( n/10 > 0 )
) itoa( n/10, s );
)
) *s++ = n%10 + '0';
) *s = 0;
) }
)
)
) I realize why my code is not working, it's because the increments
) don't carry forward when the recursive calls "unwind."
)
) I can solve this this way:
)
)
) void itoa2(int n, char *s)
) {
) static char *p = 0;
)
) if(p == 0)
) p = s;
)
) if (n < 0)
) {
) *p++ = '-';
) n = -n;
) }
)
) if( n/10 > 0 )
) itoa2( n/10, p );
)
) *p++ = n%10 + '0';
) *p = 0;
) }
)
)
) This keeps the p pointer up-to-date while the recursive calls unwind.
)
) My quesiton is, does anyone know of a solution that doesn't require
) the introduction of a static duration variable? Something like a small
) modifcation to my first attempt?

A simple way would be to have two functions and pass a pointer to pointer:

void itoa_r(int n, char **s)
{
if( n/10 > 0 )
itoa2( n/10, s );
(*s)++ = n%10 + '0';
}

void itoa(int n, char *s)
{
if (n < 0) {
*s++ = '-';
n = -n;
}
itoa_r(n, &s);
*s = 0;
}


SaSW, Willem
--
Disclaimer: I am in no way responsible for any of the statements
made in the above text. For all I know I might be
drugged or something..
No I'm not paranoid. You all think I'm paranoid, don't you !
#EOT
 
M

Martin

It has to be a typo (obviously).

Indeed. I missed out the backslash, so the incorrect line:

s = '0';

should be:

s = '\0';

But Dann's

s = 0;

will do!

That was the only typing mistake I made. T&G's response does include
But even after the obvious fix, there is still a problem with INT_MIN:

... itoa ...

#include <stdio.h>
#include <string.h>
#include <limits.h>
int main(void)
{
char s1[80] = "abcdef";
char s2[80] = "abcdef";
my_itoa(INT_MAX, s1);
my_itoa(INT_MIN, s2);
printf("INT_MAX='%s' INT_MIN='%s'\n", s1, s2);
return 0;
}

I get:

INT_MAX='2147483647' INT_MIN='-214748364('

which is puzzling.
 
B

Ben Bacarisse

Martin said:
I get:

INT_MAX='2147483647' INT_MIN='-214748364('

which is puzzling.

There is a bug (two, really). The solution should include <stdlib.h>
not <math.h> and abs(n) is undefined when n == INT_MIN on some
systems. I think this version is correct (but I prefer my other
posted solution!):

#include <stdlib.h>

void itoa(int n, char s[])
{
static int i;

if ( n / 10 )
itoa(n / 10, s);
else {
i = 0;
if (n < 0)
s[i++] = '-';
}
s[i++] = abs(n % 10) + '0'; /* Note: not abs(n) % 10. */
s = '\0';
}
 
B

Ben Bacarisse

CBFalconer said:
Sounds like a bug in limits.h.

No. There is a bug in the posted code. It may be a transcription
error, but it is the posted itoa code that turns the last '8' into a
'('.
 
P

Peter Nilsson

Walter said:
#define INT_MIN (-2137482647 - 1)

The '=' should almost certainly not be there.

It's still wrong. Assuming vanilla 32-bit ints, try...

#define INT_MIN (-2147483647 - 1)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

Forum statistics

Threads
473,990
Messages
2,570,211
Members
46,796
Latest member
SteveBreed

Latest Threads

Top