题
我使用的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);
}