我使用的strtok写了一个简单的URL解析器()。这里的代码

#include <stdio.h>
#include <stdlib.h>

typedef struct {
    char *protocol;
    char *host;
    int port;
    char *path;
} aUrl;


void parse_url(char *url, aUrl *ret) {

    printf("Parsing %s\n", url);
    char *tmp = (char *)_strdup(url);
    //char *protocol, *host, *port, *path;
    int len = 0;

    // protocol agora eh por exemplo http: ou https:
    ret->protocol = (char *) strtok(tmp, "/");
    len = strlen(ret->protocol) + 2;

    ret->host = (char *) strtok(NULL, "/");


    len += strlen(ret->host);

    //printf("char at %d => %c", len, url[len]);

    ret->path = (char *)_strdup(&url[len]);

    ret->path = (char *) strtok(ret->path, "#");

    ret->protocol = (char *) strtok(ret->protocol, ":");

    // host agora é por exemplo address.com:8080
    //tmp = (char *)_strdup(host);
    //strtok(tmp, ":");
    ret->host = (char *) strtok(ret->host, ":");
    tmp = (char *) strtok(NULL, ":");

    if(tmp == NULL) {
        if(strcmp(ret->protocol, "http") == 0) {
            ret->port = 80;
        } else if(strcmp(ret->protocol, "https") == 0) {
            ret->port = 443;
        }
    } else {
        ret->port = atoi(tmp);
    }


    //host = (char *) strtok(NULL, "/");




}

/*
 * 
 */
int main(int argc, char** argv) {
    printf("hello moto\n");

    aUrl myUrl;
    parse_url("http://teste.com/Teste/asdf#coisa", &myUrl);


    printf("protocol is %s\nhost is %s\nport is %d\npath is %s\n", myUrl.protocol, myUrl.host, myUrl.port, myUrl.path);

    return (EXIT_SUCCESS);
}

正如你所看到的,我用的strtok()了很多,所以我可以“切片”的网址。我并不需要支持比HTTP或HTTPS,所以它做的方式解决所有我遇到的问题不同的URL。 我担心的是(这是一个嵌入式的设备上运行) - 我是不是浪费内存? 当我写类似

ret->protocol = (char *) strtok(tmp, "/");

和再后来调用

ret->protocol = (char *) strtok(ret->protocol, ":");

保持箱第一指针ret->协议是否保留在存储器?我想,也许我应该设置为TMP指针第一呼叫,呼叫的strtok指向ret->协议的字符串的右部(第二呼叫),然后自由(TMP)。

我应该是使用strtok的最佳方式是什么?

有帮助吗?

解决方案

要直接回答你的问题,strtok的只返回一个指针,你给它input--它不为你分配新的内存字符串中的位置,所以不应该需要致电在任何指针它给你回的回报。

有关它的价值,你也可以看看“和strchr”和“的strstr”,这是搜索字符串中的单个字符或序列的非破坏性的方式。

另外请注意,您的内存分配是有问题这里 - 你正在使用的strdup()分配的解析函数中一个新的字符串,然后你到“RET”的字段分配内存块的碎片。因此,你的来电者将负责free'ing的strdup'd字符串,但因为你只有通过该字符串后面隐含里面沤,呼叫者需要奇迹般地知道通过免费什么指针。 (可能ret->协议,但也许不是,根据输入的外观。)

其他提示

的strtok就地修改字符串,替换为null指定的字符。因为在C字符串是NULL终止的,现在看来,原来的指针指向一个较短的字符串,即使原始字符串仍然存在,仍然占用相同的内存量(但用NULL替换的字符)。所述字符串的末尾,我认为,含有双NULL。

在简短的回答是这样的:保持一个指向您的字符串缓冲区的开头,并有另一指针是你的“当前”指针到字符串作为你解析它。当您使用的strtok或迭代以其他方式串更新的“当前”指针,但先不谈开始指针。当您完成,free()的开始指针。没有存储器泄漏。

你知道你可以继续使用解析为NULL的strtok的第一个参数字符串?

第一次调用:

char* token = strtok(string, delimiters);

然后:

token = strtok(NULL, other_delimiters);

这使您可以简化代码:

int parse_url(char *url, aUrl *ret)
{
//get protocol
char* token = strtok(url, "/");
if( token == NULL )
   return -1;
strcpy(ret->protocol, token);
strcat(ret->protocol, "//");

// skip next '/'
token = strtok(NULL, "/");
if( token == NULL )
   return -1;

//get host
token = strtok(NULL, "/");
if( token == NULL )
   return -1;
strcpy(ret->host, token);

// get path
token = strtok(NULL, "#");
if( token == NULL )
   return -1;
strcpy(ret->path, token);

// ...

return 0;
}

您可以看到我有一个返回值知道如果解析成功完成。

感谢您分享您的代码!通过的strdup函数生成我跑它里面的valgrind并固定在两个内存泄漏。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct {
    char *protocol;
    char *host;
    int port;
    char *path;
} URL;

void parse_url(char *url, URL *ret) {
    char *tmp = (char *) strdup(url);
    int len = 0;

    ret->protocol = (char *) strtok(tmp, "/");
    len = strlen(ret->protocol) + 2;
    ret->host = (char *) strtok(NULL, "/");
    len += strlen(ret->host);
    ret->path = (char *) strdup(&url[len]);
    ret->path = (char *) strtok(ret->path, "#");
    ret->protocol = (char *) strtok(ret->protocol, ":");
    ret->host = (char *) strtok(ret->host, ":");
    tmp = (char *) strtok(NULL, ":");

    if (tmp == NULL) {
        if (strcmp(ret->protocol, "http") == 0) {
            ret->port = 80;
        } else if (strcmp(ret->protocol, "https") == 0) {
            ret->port = 443;
        }
    } else {
        ret->port = atoi(tmp);
    }

}

void free_url(URL *url) {
    free(url->path);
    free(url->protocol);
}

int main(int argc, char** argv) {
    URL url;
    parse_url("http://example.com:3000/Teste/asdf#coisa", &url);
    printf("protocol: %s\nhost: %s\nport: %d\npath: %s\n", url.protocol, url.host, url.port, url.path);
    free_url(&url);

    return (EXIT_SUCCESS);
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top