PCRE captures are in the output vector in pairs. Your full match is in the first pair, the sub-group capture is in the second. See below:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pcre.h>
static const char subject[] =
"12345678901234567890^otherstrings^and^digits12345678901234567890";
#define OVSIZE 9
int main()
{
static const char my_pattern[] = "([0-9]{20})[\\^]";
const char *errtext = NULL;
int errofs = 0;
pcre* re = pcre_compile(my_pattern, 0, &errtext, &errofs, NULL);
if (re != NULL)
{
int ov[OVSIZE];
int rc = pcre_exec(re, NULL, subject, sizeof(subject), 0, 0, ov, OVSIZE);
if (rc >= 0)
{
for (int i=0; i<rc; ++i)
printf("group %d: %.*s\n", i, ov[2*i+1]-ov[2*i], subject+ov[2*i]);
}
}
return 0;
}
Output
group 0: 12345678901234567890^
group 1: 12345678901234567890