Question

J'ai écrit un analyseur simple URL à l'aide strtok (). voici le code

#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);
}

Comme vous pouvez le voir, j'utiliser strtok () beaucoup donc je peux « tranche » l'URL. Je ne ai pas besoin de soutenir urls différentes que http ou https donc la façon dont il est fait résout tous mes problèmes. Ce qui me préoccupe est (ce qui est en cours d'exécution sur un appareil embarqué) - Suis-je en train de perdre la mémoire? Quand j'écris quelque chose comme

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

Et puis appelez plus tard

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

me fait premier pointeur ret-> protocole tenue restent en mémoire? Je pensais que peut-être que je devrais mettre le premier appel à un pointeur tmp, appelez strtok pointant vers ret-> Protocole à la partie droite de la chaîne (deuxième appel) et libre (tmp).

Quelle devrait être la meilleure façon d'utiliser strtok?

Était-ce utile?

La solution

Pour répondre à votre question directement, strtok renvoie uniquement un pointeur vers un emplacement à l'intérieur de la chaîne que vous donnez comme input-- ne pas allouer une nouvelle mémoire pour vous, ne devrait donc pas besoin d'appeler gratuitement sur l'un des pointeurs il vous donne en retour.

Pour ce que ça vaut la peine, vous pouvez aussi regarder dans « strchr » et « strstr », qui sont des moyens non destructifs de la recherche de caractères simples ou des séquences dans les chaînes.

Notez également que votre allocation de mémoire est problématique ici-- que vous utilisez strdup () pour allouer une nouvelle chaîne dans votre fonction d'analyse syntaxique, puis vous attribuer des fragments de ce bloc de mémoire à des champs de « ret ». Votre interlocuteur sera donc responsable de la chaîne free'ing strdup'd, mais puisque vous êtes seulement passer cette chaîne de retour implicitement à l'intérieur RET, l'appelant a besoin de savoir ce que par magie pointeur pour passer au libre. (Probablement ret-> protocole, mais peut-être pas, selon la façon dont l'entrée a l'air.)

Autres conseils

strtok modifie la chaîne en place, en remplaçant les caractères spécifiés avec NULL. Étant donné que les chaînes en C sont NULL terminé, il apparaît maintenant que votre pointeur d'origine pointe vers une chaîne plus courte, même si la chaîne d'origine est toujours là et occupe toujours la même quantité de mémoire (mais avec des caractères remplacés par NULL). La fin de la chaîne, je pense, contient une double NULL.

La réponse courte est la suivante: Gardez un pointeur au début de votre mémoire tampon de chaîne, et un autre pointeur qui est votre pointeur « courant » dans la chaîne que vous l'analyser. Lorsque vous utilisez strtok ou itérer à travers la chaîne d'autres façons de mettre à jour le pointeur « en cours », mais laissez le pointeur en commençant seul. Lorsque vous avez terminé, free () le pointeur de début. Aucune fuite de mémoire était.

Savez-vous que vous pouvez continuer l'analyse de la chaîne en utilisant NULL comme premier paramètre de strtok?

Premier appel:

char* token = strtok(string, delimiters);

Alors:

token = strtok(NULL, other_delimiters);

Cela vous permet de simplifier votre code:

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;
}

Vous pouvez voir que j'avais une valeur de retour pour savoir si l'analyse a été effectuée avec succès.

Merci de partager votre code! Je couru à l'intérieur et fixé valgrind deux fuites de mémoire générés par des fonctions 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);
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top