Question Details

No question body available.

Tags

c matrix set combinations powerset

Answers (3)

Accepted Answer Available
Accepted Answer
August 16, 2025 Score: 5 Rep: 152,768 Quality: Expert Completeness: 100%

There are multiple problems in the posted code:

  • passing all variables by reference is confusing and inefficient.
  • scanf("%s", set) is risky as user input longer than 19 characters will cause a buffer overflow. Use scanf("%29s", set) to avoid this problem. Also test for values different than 1 instead of just equal to 0 to catch the case of end of file for which scanf() will return EOF.
  • the pointer array defined in powerset is redundant, you can pass combination and adjust the prototype of gencomb().
  • current and last should be arrays of int to simplify the code.

Here is a simplified version of the code:

#include 
#include 

int bincoef(int n, int k) { int nCk = 1; if (k > n - k) { k = n - k; } for (int i = 0; i < k; i++) { nCk = nCk * (n - i) / (1 + i); } return nCk; }

void edges(const char *set, int *current, int *last, int n, int k) { for (int i = 0; i < k; i++) { current[i] = i; } for (int i = 0; i < k; i++) { last[i] = i + n - k; } }

void successor(const char *set, int *current, int *last, int k) { int con = 0; for (int i = k; i-- > 0; ) { if (current[i] != last[i]) { con = i; break; } } int i = 0; for (; i != current[con]; i++) {} for (; con < k; con++) { current[con] = 1 + i; i++; } }

void gen
comb(const char set, int n, int k, int nCk, char combination[nCk][k+1]) { int current[k]; int last[k]; edges(set, current, last, n, k); for (int j = 0; j < nCk; j++) { for (int i = 0; i < k; i++) { combination[j][i] = set[current[i]]; } combination[j][k] = '\0'; successor(set, current, last, k); } }

void powerset(const char
set) { int n = strlen(set); int x = 1 n - k) { k = n - k; } for (int i = 0; i < k; i++) { nCk = nCk (n - i) / (1 + i); } return nCk; }

int set_subset(const char
set, int x, char dest) { int k = 0; for (int i = 0; x; i++) { if (x & 1) dest[k++] = set[i]; x >>= 1; } dest[k] = '\0'; return k; }

void powerset(const char
set) { int n = strlen(set); int x = 1
August 16, 2025 Score: 7 Rep: 234,000 Quality: Medium Completeness: 50%

The simplest way to handle this is to make all of the subarrays the same size.

Given n elements, you'll have n+1 for the outer dimension. The maximum size of the middle dimension will be nC(n/2), and the maximum size of the inner dimension is n+1.

So create your array as:

int maxnCk = nCk(n, n/2);
char combination[n+1][maxnCk][n+1];

For N=15, this will result in an array of about 1.6M elements. This might be big for the stack, so you can dynamically allocate it:

char (*combination)[maxnCk][n+1] = malloc(sizeof(char[n+1][maxnCk][n+1]);

Doing this will increase memory usage by a factor of just under 4, but simplifies how you work with it.

August 16, 2025 Score: 6 Rep: 62,256 Quality: High Completeness: 80%

The best way to do the allocation you asked about, for what you're using it for, is to not do it at all. Not even a little bit.

If you've got a finite number of items and need a powerset of them then mapping 1-bits in an element number is the most efficient way to express any element. Google will tell you how to iterate through numbers with k bits set. It's from hakmem iirc.

"Google it" and links are normally not great in an answer, but as an explanation, not an apology, hakmem is a damn gold mine in about the richest vein out there for little hacks like this, and studying it will train your mind.

It might be valuable to bring the old-school exposition there a few steps towards the modern age, where it's good to just expect optimizers to find the obvious speedups that only get in the way of exposition and comprehension, so:

C unsigned operations' results are defined to be bit-identical with signed two's complement (as God intended, a fact demonstrated most cogently by one of the hakmem entries). So:

/* Find the lowest set bit in a number: */
static unsigned lsb(unsigned c) { return c&-c; }

/* Find the next more-significant zero bit above the lsb: */ static unsigned nsb(unsigned c) { return lsb(c+lsb(c)); }

and to iterate to the next larger number with the same number of 1 bits you want to set the nsb, clear the lsb and shift any 1 bits between them to the bottom. It's easier to shift the lsb out at the end than isolate and reset it first.

static unsigned lsb(unsigned c) { return c & -c; }
static unsigned nsb(unsigned c) { return lsb(c + lsb(c)); }
static unsigned nextkbit(unsigned c,unsigned lim)  // lim mb 2n-1
{   // next larger c with the same number of 1 bits, wrapping when > lim
    if (!c) return c;
    unsigned highbits = c+nsb(c) & -nsb(c) & lim;
    unsigned lowbits = (nsb(c)-1) / lsb(c);
    return nsb(c)&lim? highbits | lowbits>>1 : lowbits;
}

Now, your C implementation is doing a lot more formatting and decoration than the python one. Duplicating your python implementation in C:

#include 

// these four get us what import itertools gets the python version: static unsigned lsb(unsigned c) { return c & -c; } static unsigned nsb(unsigned c) { return lsb(c + lsb(c)); } static unsigned nextkbit(unsigned c,unsigned lim) // lim mb 2
n-1 { // next larger c with the same number of 1 bits, wrapping when > lim if (!c) return c; unsigned highbits = c+nsb(c) & -nsb(c) & lim; unsigned lowbits = (nsb(c)-1) / lsb(c); return nsb(c)&lim? highbits | lowbits>>1 : lowbits; } static void printpowersetentry(char items, unsigned pick) { // try to duplicate python itertools set element printing exactly const char *sfx = ""; if ( pick && pick==lsb(pick) ) sfx=","; putchar('('); for ( int i=0; pick; ++i, pick>>=1 ) if (pick&1) printf("%s%s",items[i],pick>1?", ":sfx); puts(")"); }

// the main event int main(int argc, char
argv) { char items = argv+1; unsigned n=argc-1; const unsigned lim = (1u=1 ) if (pick&1) printf("%s",items[i]); }

// scaffolding+pretties implemented later static unsigned long choose(unsigned n,unsigned k); static void get
itemsordie(int argc, char argv, char items, unsigned nitems);

// the main event int main(int argc, char
argv) { char items; unsigned n; getitemsor_die(argc,argv,&items,&n); printf("%u items can be chosen in %u combinations, " "in ascending order of cardinality they are:\n", n,1u