문제

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-> 프로토콜이 메모리에 남아 있습니까? 나는 첫 번째 호출을 TMP 포인터로 설정하고, 문자열의 오른쪽 부분 (두 번째 호출)에 Ret-> 프로토콜을 호출 한 다음 무료 (TMP)로 호출해야한다고 생각했습니다.

Strtok을 사용하는 가장 좋은 방법은 무엇입니까?

도움이 되었습니까?

해결책

질문에 직접 답변하려면 Strtok은 입력으로 제공하는 문자열 내부의 위치에 대한 포인터를 반환합니다. 새로운 메모리를 할당하지 않으므로 포인터를 무료로 호출 할 필요가 없습니다. 대가로 돌아 왔습니다.

가치가있는 것은 문자열 내에서 단일 문자 나 시퀀스를 검색하는 비파괴적인 방법 인 "strchr"및 "strstr"를 조사 할 수 있습니다.

또한 여기에서 메모리 할당이 문제가됩니다. strdup ()를 사용하여 구문 분석 기능 내부에 새 문자열을 할당 한 다음 해당 메모리 블록의 조각을 "RET"필드에 할당합니다. 따라서 발신자는 strdup 'string을 풀어주는 책임이 있지만, Ret 내부에 암시 적으로 그 문자열을 다시 전달하기 때문에 발신자는 무료로 전달할 포인터를 마술처럼 알아야합니다. (아마도 ret-> 프로토콜이지만 입력이 어떻게 보이는지에 따라 아닐 수도 있습니다.)

다른 팁

Strtok은 지정된 문자를 NULL로 대체하여 문자열을 제자리에 수정합니다. C의 문자열은 null이 종결되었으므로 이제 원래 문자열이 여전히 존재하고 여전히 같은 양의 메모리를 차지하더라도 원래 포인터가 짧은 문자열을 가리키는 것으로 보입니다 (그러나 문자가 널로 교체 된 문자가 있습니다). 문자열의 끝에는 더블 널이 포함되어 있다고 생각합니다.

짧은 대답은 이것입니다. 문자열 버퍼의 시작 부분에 대한 포인터를 유지하고 구문 분석 할 때 문자열에 "현재"포인터 인 또 다른 포인터가 있습니다. Strtok을 사용하거나 다른 방식으로 문자열을 반복 할 때 "현재"포인터를 업데이트하지만 시작 포인터를 내버려 두십시오. 완료되면 무료 () 시작 포인터. 메모리가 새지 않았습니다.

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 내부에서 그것을 실행하고 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);
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top