سؤال

كتبت محلل URL بسيط باستخدام Strtok (). إليك الرمز

#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. لا أحتاج إلى دعم عناوين URL مختلفة عن HTTP أو HTTPS بحيث تكون الطريقة التي يتم بها تحل جميع مشاكلي. قلقي هو (يعمل هذا على جهاز مضمن) - هل أهزم الذاكرة؟ عندما أكتب شيئا مثل

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

ثم اتصل لاحقا

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

هل تبقى بروتوكول البروتوكول الأول للمؤشر الأول في الذاكرة؟ اعتقدت أنه ربما يجب أن أقوم بتعيين الدعوة الأولى إلى مؤشر TMP، اتصل ببروتوكول Strtok Foreing Ret-> إلى الجزء الأيمن من السلسلة (الدعوة الثانية) ثم مجانا (TMP).

ما يجب أن يكون أفضل طريقة لاستخدام strtok؟

هل كانت مفيدة؟

المحلول

للإجابة على سؤالك مباشرة، تقوم Strtok فقط بإرجاع مؤشر إلى موقع داخل السلسلة التي تمنحها كمدخلات - لا تخصص ذاكرة جديدة لك، لذلك لا ينبغي أن تحتاج إلى الاتصال مجانا على أي من المؤشرات التي يمنحكها العودة في المقابل.

فيما يتعلق الأمر، يمكنك أيضا أن ننظر في "Strchr" و "StrStrS"، والتي تعتبر طرق غير مدمرة للبحث عن أحرف أو تسلسل فردية داخل الأوتار.

لاحظ أيضا أن تخصيص الذاكرة لديك مشكلة هنا - أنت تستخدم StrDUP () لتخصيص سلسلة جديدة داخل وظيفة التحليل الخاصة بك، ثم تقوم بتعيين شظايا من كتلة الذاكرة هذه إلى حقول "Ret". وبالتالي سيكون المتصل الخاص بك هو المسؤول عن Free'ing سلسلة StrDup'd، ولكن نظرا لأنك فقط تمر هذه السلسلة مرة أخرى ضمنيا داخل RED، يحتاج المتصل إلى معرفة ما هو مؤشر سحريا لتمريره مجانا. (ربما ret-> البروتوكول، ولكن ربما لا، اعتمادا على كيفية مظهر المدخلات.)

نصائح أخرى

Strtok يعدل السلسلة المعمول بها، واستبدال الأحرف المحددة ب NULL. نظرا لأن السلاسل في C تم إنهاؤها بشكل لا يغلب، فسيظهر الآن أن مؤشرك الأصلي يشير إلى سلسلة أقصر، على الرغم من أن السلسلة الأصلية لا تزال موجودة ولا تزال تحتل نفس كمية الذاكرة (ولكن مع استبدال الأحرف باستخدام NULL). نهاية السلسلة، أعتقد أنه يحتوي على فارغة مزدوجة.

الجواب القصير هو هذا: احتفظ بمؤشر إلى بداية المخزن المؤقت سلسلة الخاص بك، ولديه مؤشر آخر هو مؤشر "الحالي" في السلسلة أثناء تحليله. عند استخدام Strtok أو تكرر عبر السلسلة بطرق أخرى، يمكنك تحديث المؤشر "الحالي" ولكن اترك مؤشر البداية وحده. عند الانتهاء، مجاني () مؤشر البداية. لا توجد ذاكرة تسربت.

هل تعرف أنه يمكنك متابعة تحليل السلسلة باستخدام 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;
}

يمكنك أن ترى أن لدي قيمة إرجاع لمعرفة ما إذا كان التحليل بنجاح تم بنجاح.

شكرا لتقاسم الرمز الخاص بك! ركضت ذلك داخل 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