减少正则表达式代码中所需的指针变量数量

时间:2015-10-12 01:38:27

标签: c regex pointers struct memory-address

我终于设法使我的正则表达式函数工作,但我想知道我是否可以将main函数中的指针声明数减少为1。例如,我想转换:

int main(){
    regex* r=calloc(1,300000);
    regex* rr=r;
    if (regexmatch("T/2/b","([A-Z]+)/([0-9]+)/([a-z]+)",10,&rr)==0){
    printres(r);
    }
    free(r);
    return 0;
}

类似于:

int main(){
    regex* r=calloc(1,300000);
    if (regexmatch("T/2/b","([A-Z]+)/([0-9]+)/([a-z]+)",10,&r)==0){
    printres(r);
    }
    free(r);
    return 0;
}

但是就目前而言,这不会起作用,因为regexmatch函数似乎改变了导致程序在free(r);

崩溃的变量的地址

我甚至尝试在函数中的最后一个return语句之前添加reg=rp;,希望我将struct变量地址重置为首次调用函数时的状态,但这并不起作用。

我该怎么做才能解决这个问题?或者是我在主函数中使用两个指针的唯一选择?

这是我的代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <regex.h>

typedef struct{
    char str[1000];
} regex;

long regexmatch(const char* str,const char* regexs,const size_t nummatch,regex** rp){
    regex** reg=rp;
    regex_t r;regmatch_t match[nummatch];
    if (regcomp(&r,regexs,REG_EXTENDED) != 0){return -1;}
    if (regexec(&r,str,nummatch,match,0)!=0){regfree(&r);return -1;}
    regfree(&r);size_t i=0;
    for (i=0;i<nummatch;i++){
        if (match[i].rm_so > -1){
            unsigned long sz=match[i].rm_eo-match[i].rm_so;
            if (sz > 0 && sz < 1000){
            memcpy((**reg).str,(char*)(str+match[i].rm_so),sz);
            (*reg)++;
            }
        }
    }
    (**reg).str[0]='\0';
    return 0;
}

void printres(regex* r){
    printf("Matches\n");
    while (r->str[0] != '\0'){
    printf("%s\n",r->str);
    r++;
    }
}

int main(){
    regex* r=calloc(1,300000);
    regex* rr=r;
    if (regexmatch("T/2/b","([A-Z]+)/([0-9]+)/([a-z]+)",10,&rr)==0){
    printres(r);
    }
    free(r);
    return 0;
}

2 个答案:

答案 0 :(得分:1)

regexmatch添加:regex* rp2=*rp;regex** reg=&rp2;

在您的代码中(*reg)++;正在修改rp的值。它等同于代码rp++,因为regex** reg=rp; rp&r调用中regexmatch设置的calloc的指针地址。 你不想改变这个指针。所以我们使用另一个名为rp2的指针。

enter image description here

答案 1 :(得分:1)

为什么通过引用传递rp?你显然不希望调用程序中的值发生变化,因此直接传递它会更简单。

事实上,你真正想要的参数是regex个对象的数组([注1])。所以不要使用原型

long regexmatch(const char* str,
                const char* regexs,
                const size_t nummatch, /* This const is pointless */
                regex** rp);

使用它会更有意义:

long regexmatch(const char* str,
                const char* regexs,
                size_t nummatch,
                regex rp[nummatch]);

(实际上,这与使用regex* rp作为参数相同,但将其写为rp[nummatch]则更加自我记录。因为您使用空字符串作为终结符(意味着你不能处理零长度捕获),你实际上需要nummatch至少比模式中捕获的数量大一个,所以它不是100%自我记录。

对原型进行了更改后,您需要删除函数中的一个间接级别:

long regexmatch(const char* str,
                const char* regexs,
                size_t nummatch,
                regex reg[nummatch]){
    /* Compiling the regex is the same as in your code. I removed
     * the assignment of reg from rp, since the parameter is now
     * called reg.
     */

    size_t i=0;
    for (i=0;i<nummatch;i++){
        if (match[i].rm_so > -1){
            unsigned long sz=match[i].rm_eo-match[i].rm_so;
            if (sz > 0 && sz < 1000){
                memcpy(reg->str, (char*)(str+match[i].rm_so), sz);
                /* The above memcpy doesn't nul-terminate the string,
                 * so I added an explicit nul-termination.
                 */
                reg->str[sz] = 0;
                /* I think this should be outside the if statement. Personally,
                 * I'd put it in the increment clause of the for loop.
                 * See Note 2.
                 */
                reg++;  
            }
        }
    }
    reg->str[0] = 0;
    return 0;
}

(见live on ideone。)

注释

  1. 我发现调用regex这基本上是一个表示正则表达式捕获的固定长度字符串是令人困惑的。另外,除非您打算分配类型struct的值,否则我不会在regex中看到固定长度字符分配的包装。但所有这些都与你的基本问题无关。

  2. 当您将捕获复制到正则表达式数组中时,您只需忽略空,未设置或过长的捕获。这意味着您无法通过查看数组中的i th 元素来访问捕获i。如果之前的捕获碰巧是空的,那么捕获将位于i - 1位置(或更早,如果多个捕获为空),并且空捕获根本不可访问。我不确定你的目标是什么,但这似乎很难使用。但是,由于使用空字符串表示捕获列表的结尾,因此无法在列表中插入空捕获。所以你真的可能想重新考虑API。

    更清晰的方法是使用指向字符串的指针数组(如argv。)