Let's say I have a box and there is a bunch of balls in that box. I can label each ball with a character while making sure no two balls get the same character as labels. I get a string this way. Let's say I had 5 balls in the box and I label them alphabetically, then the string I will get is abcde
. Now let's say I want to pick 3
balls randomly from the box, which can be done in 10
different ways and I will get 10
different strings of length 3
, arranged alphabetically these will be -
abc
abd
abe
acd
ace
ade
bcd
bce
bde
cde
I want to write a computer programme that will be doing the same thing. It will -
n
.k
less than or equal to the length of the string.nCK
.nCK X k+1
matrix comb
.nCK
pointers ptr
.ptr
to be equal to the corresponding addresses of the rows of comb
.gen_comb ()
and store the values in comb
.prnt_comb
and repeat.I wrote the following -
#include <stdio.h>
void length (char * string, int * n)
{
*n = 0;
for (int i = 0; string[i] != '\0'; i++)
{
*n = *n + 1;
}
}
void bin_cof (int * n, int * k, int * nCk)
{
int _k; *nCk = 1;
if (*k > *n - *k)
{
_k = *n - *k;
} else {
_k = *k;
}
for (int i = 0; i < _k; i++)
{
*nCk = *nCk * (*n - i) / (1 + i);
}
}
void first_n_last (char * string, char ** current, char ** last, int * n, int * k)
{
for (int i = 0; i < *k; i++)
{
current[i] = string + i;
}
current[*k] = string + *n;
for (int i = 0; i < *k; i++)
{
last[i] = string + i + *n - *k;
}
last[*k] = string + *n;
}
void prnt_comb (char ** ptr, int * nCk, int * k)
{
printf ("\nHere is the set of %d possible combination of length %d :\n\n{%s", *nCk, *k, ptr[0]);
for (int i = 1; i < *nCk; i++)
{
printf (", %s", ptr[i]);
}
printf ("}\n\n\n");
}
void successor (char * string, char ** current, char ** last, int k)
{
int con;
for (int i = k-1; i >= 0; i--)
{
if (current[i] != last[i])
{
con = i; break;
}
}
char * i = string;
for (;i != current[con]; i++) {}
int poi = (int) (i-string);
for (; con < k; con++)
{
current[con] = string+1+poi; poi++;
}
}
void gen_comb (char * string, int *n, int * k, int * nCk, char ** ptr)
{
char * current[*k+1], * last[*k+1];
first_n_last (string, current, last, n, k);
for (int j = 0; j < *nCk; j++)
{
for (int i = 0; i < *k+1; i++) {ptr[j][i] = *(current[i]);}
successor (string, current, last, *k);
}
}
int main ()
{
for (;;)
{
printf ("Give me a string : ");
char string [100];
if (scanf("%s", string) == 0)
{
printf ("Error!!");
break;
}
int n;
length (string, &n);
printf ("Give me a number less than or equal to %d : ", n);
int k;
if (scanf("%d", &k) == 0)
{
printf ("Error!!");
break;
}
int nCk;
bin_cof (&n, &k, &nCk);
char comb[nCk][k+1], * ptr[nCk];
for (int i = 0; i < nCk; i++)
{
ptr[i] = comb[i];
}
gen_comb (string, &n, &k, &nCk, ptr);
prnt_comb (ptr, &nCk, &k);
}
return 0;
}
It works for big n
s, but for small n
s (less than 7
or 8
let's say) when k
becomes 0
or becomes equal to n
it crashes saying "Segmentation fault, core dumped." And it does so completely randomly, sometimes when n=4 && k=4
it will crash, other times when n=2 && k=0
it will crash. Randomly. But, for big numbers, n>8
let's say, it works fine. Where is this error originating from and how can it be eliminated? I am running the programme here.
Your crash comes from out-of-bounds pointer/array access when k == 0
or k == n
.
Functions like first_n_last()
and successor()
assume k > 0
and try to index current[k-1]
or loop on invalid ranges, so they dereference garbage pointers.
So for fix:
k == 0
or k == n
, handle them directly without calling the combination-generation logic.*k-1
or array indices are only run when k > 0
.Code:
int main () {
for (;;) {
printf("Give me a string : ");
char string[100];
if (scanf("%s", string) == 0) { printf("Error!!"); break; }
int n; length(string, &n);
printf("Give me a number less than or equal to %d : ", n);
int k;
if (scanf("%d", &k) == 0) { printf("Error!!"); break; }
// Edge case
if (k < 0 || k > n) { printf("Invalid k!\n"); continue; }
if (k == 0) {
printf("\nHere is the set of 1 possible combination of length 0 :\n\n{ }\n\n\n");
continue;
}
if (k == n) {
printf("\nHere is the set of 1 possible combination of length %d :\n\n{%s}\n\n\n", k, string);
continue;
}
int nCk; bin_cof(&n, &k, &nCk);
char comb[nCk][k+1], *ptr[nCk];
for (int i = 0; i < nCk; i++) { ptr[i] = comb[i]; }
gen_comb(string, &n, &k, &nCk, ptr);
prnt_comb(ptr, &nCk, &k);
}
return 0;
}