首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >LeetCode 1108:保护IP地址

LeetCode 1108:保护IP地址
EN

Code Review用户
提问于 2020-10-24 02:22:49
回答 2查看 1.5K关注 0票数 9

我正在为LeetCode的“保护IP地址”发布两种解决方案。如果你想复习,请看。谢谢!

问题

给定有效(IPv4) IP地址,返回该IP地址的防御版本。

一个被破坏的IP地址取代了每一个句点。加上"..。“。

示例1:

代码语言:javascript
复制
Input: address = "1.1.1.1"
Output: "1[.]1[.]1[.]1"

示例2:

代码语言:javascript
复制
Input: address = "255.100.50.0"
Output: "255[.]100[.]50[.]0"

Constraints:

  • 给定的地址是一个有效的IPv4地址。

代码1

代码语言:javascript
复制
#include <stdio.h>
#include <stdlib.h>

static const char* defangIPaddr(
    char* address
) {
    char* ipv4_memory = calloc(1, sizeof("###[.]###[.]###[.]###"));
    char* defanged = ipv4_memory;

    for (char* character = address; *character; character++) {
        if (*character == '.') {
            *ipv4_memory++ = '[';
            *ipv4_memory++ = '.';
            *ipv4_memory++ = ']';

        } else {
            *ipv4_memory++ = *character;
        }
    }

    return defanged;
}


int main() {

    printf ("%s \n", defangIPaddr("1.1.1.1"));
    printf ("%s \n", defangIPaddr("255.100.50.0"));

    return 0;
}

代码2而不更改输入:

代码语言:javascript
复制
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static const char* defangIPaddr(
    const char* address
) {
    char* cloned_address = NULL;
    cloned_address = strdup(address);

    char* ipv4_memory = calloc(1, sizeof("###[.]###[.]###[.]###"));
    char* defanged = ipv4_memory;


    for (char* character = cloned_address; *character; character++) {
        if (*character == '.') {
            *ipv4_memory++ = '[';
            *ipv4_memory++ = '.';
            *ipv4_memory++ = ']';

        } else {
            *ipv4_memory++ = *character;
        }
    }

    return defanged;
}


int main() {

    printf ("%s \n", defangIPaddr("1.1.1.1"));
    printf ("%s \n", defangIPaddr("255.100.50.0"));

    return 0;
}
EN

回答 2

Code Review用户

回答已采纳

发布于 2020-10-24 03:34:56

注意内存分配和释放。在这两种情况下,defangIPaddr都会将一个const char *返回给堆分配的内存,调用者需要释放这个内存.但是它不能被释放,因为free期望一个非const void*作为它的参数。

将堆的所有权分配给调用方的函数应该(A)返回char*,而不是const char*,(B)应该有明确的文档记录。

在代码2中,不仅泄漏返回的指针,还泄漏strdup'ed原始指针,没有理由在这里调用strdup

你想要的只是

代码语言:javascript
复制
char *defangIPaddr(const char *address) {
    char *defanged = calloc(sizeof("###[.]###[.]###[.]###"), 1);
    char *q = defanged;
    for (const char *p = address; *p != '\0'; ++p) {
        if (*p == '.') {
            *q++ = '[';
            *q++ = '.';
            *q++ = ']';
        } else {
            *q++ = *p;
        }
    }
    return defanged;
}

我把你的名字characteripv4_memory缩短为pq。我的p是“指针”的意思;它根本不是一个字符,所以character是一个误导性的名字。q仅仅是继p之后出现的东西。

您将参数以错误的顺序传递给calloc。在实践中,这并不重要,但让它正确是容易的和免费的。如果你不确定一个接口,检查手册页

在您的原始代码中,您执行了以下操作:

代码语言:javascript
复制
char* cloned_address = NULL;
cloned_address = strdup(address);

这是一种冗长的写作方式

代码语言:javascript
复制
char* cloned_address = strdup(address);

始终初始化您的变量--但是将它们初始化到正确的值!不要初始化一个无稽之谈或垃圾值,然后在其上分配正确的值;只要用正确的值开始初始化即可。

sizeof("###[.]###[.]###[.]###")是计算最大可能长度的一种稍微狡猾的方法。最好只分配3*strlen(address)+1字节,这样即使调用者传入".................."作为它们的输入,也不可能发生缓冲区溢出。

或者,您可以精确地计算正确的缓冲区长度和malloc。

代码语言:javascript
复制
    int len = 0;
    for (const char *p = address; *p != '\0'; ++p) {
        len += (*p == '.') ? 3 : 1;
    }
    char *defanged = calloc(len+1, 1);
    [...]

考虑提交一个if (defanged == NULL) return NULL;,以防分配失败。

票数 12
EN

Code Review用户

发布于 2020-10-24 17:03:10

下面是我对这个问题的看法,这个函数接受任何字符串长度,并且只分配足够的内存:

代码语言:javascript
复制
//#include <malloc/_malloc.h>
#include <stdlib.h> // malloc, free
#include <assert.h> // assert
#include <stdio.h>  // printf, fprintf

/**
 * "Defangs" a string by replacing all `.` with `[.]`.
 *
 * @param str The string to defang
 * @return A pointer to a heap-allocated, defanged version of the string. The
 * pointer may be `NULL` if the allocation failed. The caller is responsible for
 * freeing the pointed-to memory (via `free()`) when they are done with it.
 */
char* defang(const char* str) {
    size_t str_len = 0; // without null terminator
    size_t new_len = 1; // with null terminator

    for (const char* c = str; *c; c++) {
        str_len++;

        if (*c == '.') {
            new_len += 3;
        } else {
            new_len++;
        }
    }

    char* new = malloc(new_len);

    if (new) {
        char* ptr = new;
        for (size_t i = 0; i < str_len; i++) {
            const char* c = &str[i];

            if (*c == '.') {
                *ptr++ = '[';
                *ptr++ = '.';
                *ptr++ = ']';
            } else {
                *ptr++ = *c;
            }
        }

        *ptr++ = 0;

        assert(ptr - new == new_len);
    }

    return new;
}

int main() {
    char* defanged1 = defang("1.1.1.1");
    if (defanged1) {
        printf("%s\n", defanged1);
        free(defanged1);
    } else {
        fprintf(stderr, "Failed to allocate memory for defanged1\n");
        return 1;
    }

    char* defanged2 = defang("255.100.50.0");
    if (defanged2) {
        printf("%s\n", defanged2);
        free(defanged2);
    } else {
        fprintf(stderr, "Failed to allocate memory for defanged2\n");
        return 1;
    }

    return 0;
}

当内存无法分配时,它会向调用方返回一个空指针,以允许它们处理这种情况,而不是试图继续并立即导致分段错误。

此外,该函数有一个文档注释,它准确地解释了它所做的事情、需要做的事情、返回的内容以及对调用方的期望。我认为,这四个要素对任何文件都是必不可少的。

然后,包含的main函数是一个示例,说明如何使用defang函数,如果内存被分配,则释放内存,如果没有释放内存,则会出现错误消息。

可以随意查看这段代码,作为如何应用其他人给出的建议的示例。

票数 2
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/251077

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档