作为学习C的一部分,我编写了以下代码,以将目录名与文件名结合在一起。例如:combine("/home/user", "filename")将产生/home/user/filename。预期该功能可跨平台使用(至少在所有流行的Linux发行版以及Windows 32和64位上)。

这是代码。

const char* combine(const char* path1, const char* path2)
{
    if(path1 == NULL && path2 == NULL) {
        return NULL;
    }

    if(path2 == NULL || strlen(path2) == 0) return path1;
    if(path1 == NULL || strlen(path1) == 0) return path2;

    char* directory_separator = "";
#ifdef WIN32
    directory_separator = "\\";
#else
    directory_separator = "/";
#endif

    char p1[strlen(path1)];                    // (1)
    strcpy(p1, path1);                         // (2)
    char *last_char = &p1[strlen(path1) - 1];  // (3)

    char *combined = malloc(strlen(path1) + 1 + strlen(path2));
    int append_directory_separator = 0;
    if(strcmp(last_char, directory_separator) != 0) {
        append_directory_separator = 1;
    }
    strcpy(combined, path1);
    if(append_directory_separator)
        strcat(combined, directory_separator);
    strcat(combined, path2);
    return combined;
}

关于上述代码,我有以下问题。
  • 考虑编号为1,2,3的行。所有这三行都是为了从字符串中获取最后一个元素。看起来我正在为这么小的事情编写更多的代码。从char*字符串中获取最后一个元素的正确方法是什么。
  • 要返回结果,我正在使用malloc分配一个新字符串。我不确定这是否是正确的方法。是否要求调用者释放结果?我如何指示调用者他必须释放结果?有没有更容易出错的方法?
  • 您如何评价代码(差,中等,好)?有哪些需要改进的地方?

  • 任何帮助将是巨大的。

    编辑

    修复了所有讨论的问题并实现了建议的更改。这是更新的代码。
    void combine(char* destination, const char* path1, const char* path2)
    {
        if(path1 == NULL && path2 == NULL) {
            strcpy(destination, "");;
        }
        else if(path2 == NULL || strlen(path2) == 0) {
            strcpy(destination, path1);
        }
        else if(path1 == NULL || strlen(path1) == 0) {
            strcpy(destination, path2);
        }
        else {
            char directory_separator[] = "/";
    #ifdef WIN32
            directory_separator[0] = '\\';
    #endif
            const char *last_char = path1;
            while(*last_char != '\0')
                last_char++;
            int append_directory_separator = 0;
            if(strcmp(last_char, directory_separator) != 0) {
                append_directory_separator = 1;
            }
            strcpy(destination, path1);
            if(append_directory_separator)
                strcat(destination, directory_separator);
            strcat(destination, path2);
        }
    }
    

    在新版本中,调用者必须分配足够的缓冲区并发送给combine方法。这样避免了使用mallocfree的问题。这是用法
    int main(int argc, char **argv)
    {
        const char *d = "/usr/bin";
        const char* f = "filename.txt";
        char result[strlen(d) + strlen(f) + 2];
        combine(result, d, f);
        printf("%s\n", result);
        return 0;
    }
    

    有任何进一步改进的建议吗?

    最佳答案

    并且存在内存泄漏:

    const char *one = combine("foo", "file");
    const char *two = combine("bar", "");
    //...
    free(one);   // needed
    free(two);   // disaster!
    

    编辑:您的新代码看起来更好。一些小的样式更改:
  • 第4行中的双分号;;
  • 在第6行中,将strlen(path2) == 0替换为path2[0] == '\0''或仅替换为!path2[0]
  • 在第9行中类似。
  • 删除确定last_char的循环,并使用const char last_char = path1[strlen(path1) - 1];
  • if(append_directory_separator)更改为if(last_char != directory_separator[0])。因此,您不再需要变量append_directory_separator
  • 让您的函数还返回destination,类似于strcpy(dst, src),它返回dst

  • 编辑:并且您的last_char循环存在一个错误:它始终返回path1的结尾,因此您可能在答案中以双斜杠//结束。 (但是Unix除非将它放在开始,否则将其视为一个斜杠)。无论如何,我的建议解决了这个问题-我认为这与jdmichal的答案非常相似。而且我发现您在原始代码中具有此正确性(我承认我只是看了一眼-太复杂了,以我的口味;您的新代码要好得多)。

    还有另外两个主观意见:
  • 我将使用stpcpy(),以避免strcat()的效率低下。 (如果需要,可以轻松编写自己的代码。)
  • 有些人对strcat()等不安全的观点非常强烈。但是,我认为您的用法非常好。
  • 关于合并目录和文件路径-C,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/3142365/

    10-09 02:13