合并目录和文件路径 - C.

Nav*_*K N 8 c string refactoring

作为学习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;
}
Run Code Online (Sandbox Code Playgroud)

关于上面的代码我有以下问题.

  1. 考虑编号为1,2,3的线.所有这三行都是从字符串中获取最后一个元素.看起来我正在为这么小的东西编写更多代码.从char*字符串中获取最后一个元素的正确方法是什么.
  2. 要返回结果,我将使用分配一个新字符串malloc.我不确定这是否是正确的方法.调用者是否应该释放结果?如何指示呼叫者必须释放结果?是否有一个不太容易出错的方法?
  3. 你如何评价代码(差,平均,好)?有哪些方面可以成为非常重要的?

任何帮助都会很棒.

编辑

修复了所讨论的所有问题并实施了建议的更改.这是更新的代码.

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

在新版本中,调用者必须分配足够的缓冲区并发送给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;
}
Run Code Online (Sandbox Code Playgroud)

有任何改进的建议吗?

Jos*_*sey 5

并且存在内存泄漏:

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

编辑:您的新代码看起来更好。一些小的样式更改:

  • ;;第4行中的双分号。
  • 在第6行中,strlen(path2) == 0path2[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

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

还有另外两种主观意见:

  • 我会用它stpcpy()来避免效率低下strcat()。(如果需要,可以自己写。)
  • 有些人对不安全strcat()之类的事物有非常强烈的看法。但是,我认为您的用法非常好。