On Jun 6, 3:33*pm, david.chant...@googlemail.com wrote:
> Hi --
>
> Grr, I feel like such an idiot. *Just when I think I have finally
> understood something I seem to then take six steps back and have to
> start all over again. *
Don't beat yourself up. The joy and the sorrow of C is that it's a
fairly thin abstraction over the hardware. This requires you to keep
track of hardware-ish details that a more abstract language would
never let you see or express at all. When you're learning, it can
seem like whack-a-mole.
What I've done to (I hope) solve this is:
>
> char *string = malloc(4096);
>
> if (string == NULL)
> {
> * * * // Do some error condition here.}
>
> memset(string, '\0', sizeof(string));
Others have pointed out the error here. I won't do it again. I'll
point out, however, that returning a malloc'ed block is overkill
here. You can get what you want by requiring the user to allocated
the output buffer and pass it in. For convenience you can return a
pointer to the user's buffer, so the function can be called as an
actual parameter to another function. I.e. say:
static char* expand(char *buf, const char *format)
{
... yada yada
return buf;
}
Now the caller can say:
char buf[4096];
printf("result is %s\n", expand(buf, "Go for %n."));
Another point is that after practice, you'll develop character
manipulation idioms that are easy for your head to wrap around.
Personally the technique you are using of "scan and block copy" has
always seemed awkward to me. My head finds it easier to scan and copy
at the same time. I'd set it up this way:
char* expand(char *buf, const char *fmt)
{
int ibuf = 0;
int ifmt = 0;
char ch;
#define GET(C) do { C = fmt[ifmt++]; } while (0)
#define PUT(C) do { buf[ibuf++] = (C); } while (0)
#define PUTS(S) do { \
strcpy(&buf[ibuf], (S)); ibuf += strlen(S); \
} while (0)
for (;

{
GET(ch);
if (ch == '%') {
GET(ch); // Escape character.
switch (ch) {
case 'n':
PUTS("Name");
break;
case 'c':
PUTS("Country");
break;
case 'r':
PUTS("Restrictions");
break;
case '\0':
PUT('\0'); // Probably an error case.
return buf;
default:
fprintf(stderr,
"warn: bad escape %%%c @ fmt[%d]\n",
ch, ifmt);
break;
}
}
else {
// Any other character: copy and quit if it was null.
PUT(ch);
if (ch == '\0')
return buf;
}
}
}