所以我刚开始接受c 我的最终目标是编写一个函数,用正则表达式搜索字符串并返回匹配数组。
我遇到的最大问题是将字符串保存到内存中,该内存可以作为参数传入的指针返回或引用。
我真的想要一种方法来判断有多少匹配,所以我可以做一些像c#等效的东西; if(matches.Count() > 0) { /* we have a match! */ }
然后根据我最终传入的模式获取每个匹配组的结果字符串。
我知道这是不正确的,并且在实践中可能还有其他一些错误,但是这里是我试图弄清楚读取指针,结构,字符数组等的代码。等等
typedef struct
{
char *match;
} Matches;
int main()
{
regex_t regex;
int reti;
char msgbuf[100];
int max_matches = 10;
regmatch_t m[max_matches];
char str[] = "hello world";
reti = regcomp(®ex, "(hello) (world)", REG_EXTENDED);
if( reti )
{
fprintf(stderr, "Could not compile regex\n");
exit(1);
}
reti = regexec(®ex, str, (size_t) max_matches, m, 0);
if( !reti )
{
puts("Match");
}
else if( reti == REG_NOMATCH )
{
puts("No match");
}
else
{
regerror(reti, ®ex, msgbuf, sizeof(msgbuf));
fprintf(stderr, "Regex match failed: %s\n", msgbuf);
exit(1);
}
char *p = str;
int num_of_matches = 0;
Matches *matches;
int i = 0;
for(i = 0; i < max_matches; i++)
{
if (m[i].rm_so == -1) break;
int start = m[i].rm_so + (p - str);
int finish = m[i].rm_eo + (p - str);
if (i == 0)
printf ("$& is ");
else
printf ("$%d is ", i);
char match[finish - start + 1];
memcpy(match, str + start, finish - start);
match[sizeof(match)] = 0;
matches[i].match = match; //Need to get access to this string in an array outside of the loop
printf ("'%.*s' (bytes %d:%d)\n", (finish - start), str + start, start, finish);
num_of_matches++;
}
p += m[0].rm_eo;
for(i = 0; i < num_of_matches; i++)
{
printf("'%s'\n", matches[i].match);
}
/* Free compiled regular expression if you want to use the regex_t again */
regfree(®ex);
return 0;
}
就在我认为只有匹配“世界”的时候,我注意到当我注释掉printf语句时,最后一个printf语句返回了空字符或随机字符。
答案 0 :(得分:1)
您的问题主要是与C字符串有关的内存问题。
首先,为匹配项定义一个数组:
Matches *matches;
这定义了一个指向匹配结构的指针,但是这个指针是未初始化的,并且不指向任何合理的位置。相反,您应该定义一个匹配数组:
Matches matches[max_matches];
这将为您提供10个(本地)匹配,您可以访问。
接下来,定义一个本地字符串以将匹配保存为可变长度数组(VLA):
char match[finish - start + 1];
这一次,您已经分配了足够的空间来容纳子字符串。但是这个char缓冲区是本地的,当你到达for
循环体的右括号时它将会消失。下一次循环可能会使用相同的内存。循环后访问此内存是违法的。
一种解决方案是使用malloc
分配堆上的内存:
char *match = malloc(finish - start + 1);
请注意,您必须稍后使用free
显式再次释放资源。
复制子字符串并以空字符结束。但是,当您这样做时,您无法获得空字符的位置:
match[sizeof(match)] = 0;
sizeof
是一个编译时操作数,它告诉您给定表达式的类型在内存中占用的字节数。当您使用VLA时,sizeof(match)
是在该缓冲区结束后的一个。现在我们使用指向已分配内存的指针,其中sizeof
是指针的大小。
sizeof
经常与strlen
混淆,但在这里您无法使用strlen
,因为match
尚未以strlen
为空终止}要求。但你知道你的字符串的大小:
match[finish - start] = 0;
您也不需要指针p
,只需定义:
int start = m[i].rm_so;
int finish = m[i].rm_eo;
所以:
malloc
分配长寿命内存。此类内存不会被垃圾收集,必须使用free
明确释放。sizeof
是编译时操作数。它是原始记忆功能所需的拐杖,如malloc
。 (我在这里省略了sizeof
,因为sizeof(char)
保证为1。)在C fun中不使用字符串吗?