【问题标题】:reduce the size of a string减小字符串的大小
【发布时间】:2022-01-21 02:38:53
【问题描述】:

(免责声明:这不是一个完整的练习,因为我必须完成它,但是这部分代码发生了错误)

我做了这个练习来练习内存分配。

创建一个函数,它接受一个 url(一个 C 字符串)并返回网站的名称(带有“www.”和扩展名)。 例如,给定维基百科的链接“http://www.wikipedia.org/”,它必须只返回另一个字符串中的“www.wikipedia.org”(在堆中动态分配)。

这是我到目前为止所做的: 做一个for循环,当“i”大于6时,开始复制另一个字符串中的每个字符,直到到达“/”。 我需要分配另一个字符串,然后重新分配它。

这是我目前的尝试:

char *read_website(const char *url) {
    char *str = malloc(sizeof(char)); 
    if (str == NULL) {
        exit(1); 
    }
    for (unsigned int i = 0; url[i] != "/" && i > 6; ++i) {
        if (i <= 6) {
            continue; 
        }
        char* s = realloc(str, sizeof(char) + 1); 
        if (s == NULL) {
            exit(1); 
        }
        *str = *s; 
    }
    return str; 
}

int main(void) {
    char s[] = "http://www.wikipedia.org/"; 
    char *str = read_website(s); 
    return 0; 
}

(1) 通过逐行调试,我注意到一旦到达 for 循环,程序就会结束。 (已解决)我意识到最好删除 if (i

(2) 另一件事:当我使用realloc 时,我选择创建另一个指针,因为我必须检查是否存在内存泄漏。这是一个好习惯吗?还是我应该做点别的?

编辑:删除 if-check 后,我看到这个 realloc(在调试期间触发了断点)。

【问题讨论】:

  • 那是因为你的 for 循环没有做任何事情。返回并确保您了解 continue 的作用。

标签: c string memory-management dynamic-memory-allocation


【解决方案1】:

该分配没有说返回的字符串必须是最小的大小,并且用于 URL 的内存量是最小的。

chqrlie 的解决方案的基础上,我首先找到域名的开头(跳过协议部分),复制字符串的其余部分,然后截断结果。大致:

char *prot[] = { "http://", "https://" };
for( int i=0; i < 2; i++ ) {
  if( 0 == strncmp(url, http, strlen(prot)) ) 
     s += strlen(prot);
     break;
  }
}
char *output = strdup(s);
if( output ) {
  size_t n = strcspn(output, "/:");
  output[n] = '\0';
}
return output; 

调用者仍然可以释放返回的指针,因此总“浪费”的空间仅限于截断 URL 的尾随部分。

【讨论】:

  • 协议部分使用通用方法的简单实现,但复制整个字符串似乎很浪费。为什么不只是 return strndup(s, strcspn(output, "/:")); ?分配没有指定返回字符串应该有最小的分配,但是 OP 的实现试图通过一次重新分配一个字节的字符串直到域名的末尾来实现这一点......
  • 除非应用程序使用的内存非常有限,以字节为单位,那么对我来说,尾随的重复字符串不如 strndup 的可移植性约束重要。我不是说你错了,只是说这是一个判断电话。
  • 有道理...那么您可能会完全远离strdup,而使用malloc(n + 1)memcpy() :)
【解决方案2】:

您的代码中存在多个问题:

  • url[i] != "/" 不正确,是类型不匹配。您应该将字符 url[i] 与字符常量 '/' 进行比较,而不是字符串文字 "/"

  • char *s = realloc(str, sizeof(char) + 1); 仅重新分配大小为 2,而不是当前长度加 1。

  • 你不增加指针,也不使用索引变量。

  • 不要使用mallocrealloc,您应该首先计算服务器名称的长度并直接分配具有正确大小的数组。

这是修改后的版本:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char *read_website(const char *url) {
    // skip the protocol part
    if (!strncmp(url, "http://", 7))
        url += 7;
    else if (!strncmp(url, "https://", 8))
        url += 8;
    // compute the length of the domain name, stop at ':' or '/'
    size_t n = strcspn(url, "/:");
    // return an allocated copy of the substring
    return strndup(url, n);
}

int main(void) {
    char s[] = "http://www.wikipedia.org/"; 
    char *str = read_website(s);
    printf("%s -> %s\n", s, str);
    free(str);
    return 0; 
}

strndup() 是许多系统上可用的 POSIX 函数,它将成为 C 标准下一版本的一部分。如果它在您的目标上不可用,这里有一个简单的实现:

char *strndup(const char *s, size_t n) {
    char *p;
    size_t i;
    for (i = 0; i < n && s[i]; i++)
        continue;
    p = malloc(i + 1);
    if (p) {
        memcpy(p, s, i);
        p[i] = '\0';
    }
    return p;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-17
    • 1970-01-01
    • 1970-01-01
    • 2010-10-03
    相关资源
    最近更新 更多