Path: csiph.com!news.swapon.de!eternal-september.org!feeder3.eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail
From: Tim Rentsch
Newsgroups: comp.lang.c
Subject: Re: Recursion, Yo
Date: Wed, 10 Apr 2024 10:14:01 -0700
Organization: A noiseless patient Spider
Lines: 142
Message-ID: <86cyqx16p2.fsf@linuxsc.com>
References: <87edbestmg.fsf@bsb.me.uk>
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Injection-Date: Wed, 10 Apr 2024 19:14:03 +0200 (CEST)
Injection-Info: dont-email.me; posting-host="5ec1c0fb8572bf9a2af34710c5b65b61"; logging-data="1153169"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1/XoCz5xSZ97t+vu2y8Wnrpv2ghKU9Ge34="
User-Agent: Gnus/5.11 (Gnus v5.11) Emacs/22.4 (gnu/linux)
Cancel-Lock: sha1:/rqkl0CRnmwiOCav2mj5haEqGBs= sha1:2X4d97gERzP2amSobOnYct3EgSo=
Xref: csiph.com comp.lang.c:384263
Lawrence D'Oliveiro writes:
> On Tue, 09 Apr 2024 11:44:23 +0100, Ben Bacarisse wrote:
>
>> It's significant (or at least note worthy) that the code in the
>> original post was not ISO C ...
>
> Interesting that GCC?s C compiler allows nested routine definitions,
> but the C++ compiler does not.
>
>> and re-writing it in ISO C would show up some of the issues involved
>> ...
>
> Ask and you shall receive ...
>
> /*
> Generate permutations of a list of items.
> Pass a list of arbitary words as command arguments, and this
> program will print out all possible orderings of them.
> */
>
> #include
> #include
> #include
> #include
>
> typedef void (*permute_action)
> (
> unsigned int nrwords,
> const char * const * words,
> void * arg
> );
>
> struct permute_ctx
> {
> unsigned int nrwords;
> const char * const * words;
> permute_action action;
> void * action_arg;
> const char ** permbuf;
> bool * used;
> } /*permute_ctx*/;
>
> static void permute1
> (
> struct permute_ctx * ctx,
> unsigned int depth
> )
> {
> if (depth < ctx->nrwords)
> {
> for (unsigned int i = 0; i < ctx->nrwords; ++i)
> {
> if (not ctx->used[i])
> {
> ctx->permbuf[depth] = ctx->words[i];
> ctx->used[i] = true;
> permute1(ctx, depth + 1);
> ctx->used[i] = false;
> } /*if*/
> } /*for*/
> }
> else
> {
> ctx->action(ctx->nrwords, ctx->permbuf, ctx->action_arg);
> } /*if*/
> } /*permute1*/
>
> void permute
> (
> unsigned int nrwords,
> const char * const * words,
> permute_action action,
> void * action_arg
> )
> {
> if (nrwords > 0)
> {
> struct permute_ctx ctx;
> ctx.nrwords = nrwords;
> ctx.words = words;
> ctx.action = action;
> ctx.action_arg = action_arg;
> ctx.permbuf = (const char **)malloc(nrwords * sizeof(char *));
> ctx.used = (bool *)malloc(nrwords);
> for (unsigned int i = 0; i < nrwords; ++i)
> {
> ctx.used[i] = false;
> } /*for*/
>
> permute1(&ctx, 0);
>
> free(ctx.permbuf);
> free(ctx.used);
> } /*if*/
> } /*permute*/
>
> [...]
More complicated than it needs to be. Besides that, in a beauty
contest this coding style would lose out even to Frankenstein.
Simpler:
#include
#include
typedef void *Voidp;
typedef struct array_CB_s ArrayCB;
struct array_CB_s {
void (*run)( ArrayCB *cb, unsigned n, const Voidp[ n ] );
};
static void permute_r( unsigned n, Voidp[n], unsigned, ArrayCB * );
static void voidp_exchange( Voidp [], unsigned, unsigned );
void
permute( unsigned n, const Voidp in_array[n], ArrayCB *cb ){
for( Voidp *pva = malloc( n * sizeof *pva ); pva; pva = 0 ){
memcpy( pva, in_array, n * sizeof *pva );
permute_r( n, pva, n, cb );
free( pva );
}
}
void
permute_r( unsigned n, Voidp values[n], unsigned k, ArrayCB *cb ){
for( unsigned i = 0; i < k; i++ ){
voidp_exchange( values, n-k, n-k+i );
permute_r( n, values, k-1, cb );
voidp_exchange( values, n-k, n-k+i );
}
if( k == 1 ) cb->run( cb, n, values );
}
void
voidp_exchange( Voidp values[], unsigned i, unsigned j ){
if( i != j ){
Voidp pi = values[i], pj = values[j];
values[i] = pj, values[j] = pi;
}
}