Re: right padding



On Mon, 27 Oct 2008 23:58:47 +0000, Ben Bacarisse <ben.usenet@xxxxxxxxx>
wrote:

Pilcrow <Pilcrow6@xxxxxxxxx> writes:

<snip>
But, to get back to the topic. I have been working on your
(Heathfield's) submission in response to the OP's query. I fixed what I
regarded as a bug (the assert statement), used a malloc to guard against
buffer overflow, and expanded its capability to allow for padding on
either the left or right. Here is my current version, followed by some
remarks and questions.

------------------------------------------------------------------------
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>

#define PAD_RIGHT 0
#define PAD_LEFT 1

int digits(int n) /* how many digits in an integer */

I prefer to make this sort of helper function static.

{
int ct = 0;
int pow = 10;
while(n > 0) {
n -= n % pow;
pow *= 10;
ct++;
}
return ct;
}

This goes wrong for all n <= 0. It also goes wrong for those large n
that cause pow to overflow.

Quite true, but ok for n>0. pow overflow? Just counting digits. So i
should make pow a longlong? ok. And change for n <= 0 should be easy.
Thanks.



char *pad( /* func returns ptr to start of string */

I'd suggest a more descriptive name.

char *s, /* buffer for output string */

This parameter is pointless. I think (from the call you make below)
that you've forgotten that C is pass-by-value.

don't understand your point


int n, /* number to print */
size_t width, /* pad to this width */
int padch, /* character to pad with */
int rl) /* pad on right (0) or left (1) */
{
int dig = digits(n); /* space required for the number */
assert(dig <= width); /* must have at least that space */
int count = 0; /* count of characters */

You have now switched to C99 but mixing declarations and statements.

Using gcc in mingw on a windows machine.. All these varying 'standards'
have me dizzy.


s = malloc(width+1); /* get necessary memory */

I'd check the return.

ok


char *t = s; /* save ptr */
if (rl == PAD_RIGHT) {
count = sprintf(t, "%d", n); /* insert num */
t += count; /* bump ptr */
while(count++ < width) /* pad on right */
*t++ = padch;
*t = '\0'; /* finish string */
}else{
while(count++ < width-dig) /* pad on left */
*t++ = padch;
sprintf(t, "%d", n); /* insert num */
}
return s; /* return ptr to start of string */
}

#ifdef TEST_IT

int main(void)
{
char *here = NULL;
int num = 123;
printf("[%s]\n",pad(here, num, 20, '*', PAD_RIGHT));
free (here);

here is NULL at this point. The free does nothing.

But I built the string in 'here', didn't I?


printf("[%s]\n",pad(here, num, 13, '*', PAD_LEFT));
free (here);
printf("[%s]\n",pad(here, num, 3, '*', PAD_RIGHT));
free (here);
}
#endif
------------------------------------------------------------------------

My first problem with this is that the sprintf is hard-coded, which is
inappropriate for a library function.

Secondly, I was able to print the results, as you see, but I cannot
figure out how to save the result for later use. For example,

------------------------------------------------------------------------

int main(void)
{
char *here = NULL;
int num = 123;
printf("[%s]\n",pad(here, num, 20, '*', PAD_RIGHT));

------------------------------------------------------------------------
should leave the result in 'here', but I can't 'puts' it (surely my
fault?). I even tried something like this:
------------------------------------------------------------------------

int main(void)
{
char *here = NULL;
char *t = here;
int num = 123;
pad(here, num, 20, '*', PAD_RIGHT);
puts(t); /* or puts(*t) or ... */

------------------------------------------------------------------------
Now, what am I missing???

C is call-by-value. You should just leave off the first parameter and
call ths function like this:

here = pad(num, 20, '*', PAD_RIGHT);

But then I would have to declare and use another buffer inside the
subroutine, no? And then how could it be free'd? And depend on the
user to define 'here' of sufficient size.


but I would advice a different interface where the caller passes in
the buffer to be used.

Didn't 'the user pass in the buffer to be used' in my code? I was
following Mr Heathfield's manner, or so I thought.

But now I see that Mr H did not dynamically allocate the memory for the
buffer from inside the function, so the user had to do it. I thought I
made an improvement.

So, should i have defined the function so?

------------------------------------------------------------------
char *pad (char **s ...
------------------------------------------------------------------

and called it:

------------------------------------------------------------------
something = pad(&here, ...
------------------------------------------------------------------

I tried that on a previous attempt, and got into trouble..

Lemme look at that again ...

Confusing
.



Relevant Pages

  • Re: right padding
    ... int pow = 10; ... *by* a char * parameter, and that is what my version (and RH's ... But then I would have to declare and use another buffer inside the ...
    (comp.lang.c)
  • Re: right padding
    ... Isn't there a memory leak, since the buffer is not free'd? ... Now I see that I was not using a user defined buffer with my previous ... int sign = n; ... long long pow = 10; ...
    (comp.lang.c)
  • Re: right padding
    ... int pow = 10; ... char *here = NULL; ... int num = 123; ...
    (comp.lang.c)
  • Re: right padding
    ... int pow = 10; ... char *here = NULL; ... int num = 123; ...
    (comp.lang.c)
  • [PATCH] Numerous fixes to kernel-doc info in source files.
    ... static inline int ffs ... @buffer: where the data must be copied. ... * struct kfifo with kfree. ... @timer: ...
    (Linux-Kernel)