質問
私は)(は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を使用して)たくさんので、私がすることができ、「スライス」のURL。私は、HTTPまたはHTTPSとは異なるURLをサポートする必要はありませんので、それを行うの方法は、私のすべての問題を解決します。 私の関心は、(これは、組み込みデバイス上で実行されている)である - 私はメモリを無駄にしていますか? 私は
のようなものを書くときret->protocol = (char *) strtok(tmp, "/");
そして後で呼び出し
ret->protocol = (char *) strtok(ret->protocol, ":");
開催私の最初のポインタret->プロトコルは、メモリ内に残っていますか?私は多分私はその後ret->列(第2の呼)の右側部分にプロトコルおよび遊離(TMP)を指すはstrtokを呼び出し、TMPポインタの最初の呼び出しを設定する必要があることを考えています。
はstrtokを使用するための最良の方法であるべきか?
解決
直接あなたの質問に答えるために、strtokははあなたがそれを与える文字列内の位置へのポインタを返します。それは見返りに戻ってあなたを与えます。
何が価値があるため、あなたはまた、文字列内の単一の文字やシーケンスを検索する非破壊の方法である、「strchr」と「はstrstr」に見ることができます。
また、あなたのメモリ割り当ては、あなたのparse関数内に新しい文字列を割り当てるためのstrdup()を使用している、とあなたは「RET」の欄にそのメモリブロックの断片を代入しているhere--問題があることに注意してください。あなたの呼び出し側は、このようにstrdup'd文字列をfree'ingの責任になりますが、あなただけのRETの内側に戻って、暗黙的にその文字列を渡していることから、呼び出し側は自由に渡すために何ポインタ魔法の知っている必要があります。 (入力がどのように見えるかに応じて、おそらくret->プロトコルが、そうでないかもしれない、。)
他のヒント
はstrtokはNULLと指定された文字を置き換える、代わりに文字列を変更します。 Cの文字列がNULLで終了しているので、今、あなたのオリジナルのポインタは、元の文字列がまだそこにあるとまだ同じメモリの量(ただし、NULLに置き換え文字で)を占めているにもかかわらず、短い文字列を指していると思われます。文字列の最後には、私が思うに、二重NULLが含まれています。
短い答えはこれです:あなたの文字列バッファの先頭を指すポインタを保持し、そしてあなたがそれを解析などの文字列の中にあなたの「現在」のポインタを別のポインタを持っています。あなたはstrtokはを使用したり、他の方法で文字列を反復処理するときは、「現在の」ポインタを更新するが、一人で始めてポインタを残します。設定が完了したら、free()を開始ポインタ。いいえメモリがリークしていない。
あなたはstrtokは最初のパラメータとしてNULLを使用して文字列を解析し続けることができます知っていますか?
まず呼び出します:
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;
}
あなたが、私は構文解析が正常に行われたかどうかを知るために、戻り値を持っていた見ることができます。
あなたのコードを共有してくれてありがとう!私はvalgrindの内側にそれを実行し、固定された2つのメモリリークがのstrdup関数によって生成されます。
#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);
}