首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >memmove离开垃圾-C

memmove离开垃圾-C
EN

Stack Overflow用户
提问于 2010-07-08 13:54:53
回答 4查看 1K关注 0票数 2

我编写了以下函数,将给定的完整路径分为目录、文件名和扩展名。

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

struct path_info {
    char *directory;
    char *filename;
    char *extension;
};

#ifdef WIN32
const char directory_separator[] = "\\";
#else
const char directory_separator[] = "/";
#endif

struct path_info* splitpath(const char *full_path)
{
    size_t length = strlen(full_path);
    struct path_info *p = (struct path_info*) malloc(sizeof(struct path_info) + length + 3);  /* Extra space for padding and shifting */
    if(p)
    {
        char *path = (char *) &p[1];    /* copy of the path */
        char *end = &path[length + 1];  
        char *extension;
        char *last_separator;

        /* copy the path */
        strcpy(path, full_path);
        *end = '\0';
        p->directory = end;
        p->extension = end;
        p->filename  = path;

        last_separator = strrchr(path, directory_separator[0]);    /* Finding the last directory separator */
        if(last_separator) {
            memmove(last_separator + 1, last_separator, strlen(last_separator));  /* inserting a directory separator where null terminator will be inserted */
            p->directory = path;
            *(++last_separator) = '\0';      /* Truncate the directory path */
            p->filename = ++last_separator;  /* Taking the remaining as file name */
        }

        /* Finding the extension starts from second character. This allows handling filenames 
           starts with '.' like '.emacs'.*/
        extension = strrchr(&p->filename[1], '.');
        if(extension) {

            /* shifting the bytes to preserve the extension */
            memmove(extension + 1, extension, strlen(extension));   /* problem happens here */
            p->extension = extension + 1;

            *extension = '\0';  /* Truncates the file name */
        }
    }
    return p;
}


int main(void)
{
    struct path_info *p = splitpath("C:\\my documents\\some.txt");
    printf("Directory : %s\n", p->directory);
    printf("Filename : %s\n", p->filename);
    printf("Extension : %s\n", p->extension);
    return 0;
}

这对于在GCC上的给定输入很有效。但它在MSVC上失败了,在extension变量上留下了一些垃圾数据。我在出错的地方添加了一条评论。我不明白为什么memmove在MSVC上表现不同?我在两个地方使用过memmove,奇怪的是第一个运行得很好。

任何帮助都将不胜感激。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2010-07-08 14:05:56

尝试移动strlen(extension) + 1字节,这样不仅可以移动扩展字符,还可以移动尾随的空字符。例如,如果扩展名是“abc”,那么您只能将3个字符向前移动一个空格。在“c”字符之后可能有一个空字符,但在这之后没有空字符,因此当您移动字符时,字符串将变为未终止。

票数 6
EN

Stack Overflow用户

发布于 2010-07-08 14:10:18

您的第二个memmove将覆盖终止的'\0‘字节。你可以移动strlen(extension)+1字节来解决这个问题。我怀疑在GCC上你很幸运,在下一个内存位置碰巧有一个额外的'\0‘字节。

票数 2
EN

Stack Overflow用户

发布于 2010-07-08 14:11:50

我很确定这与memmove无关,而是与字符串逻辑的其余部分有关,这是一个混乱且非常低效的逻辑。与其在开始时复制,为什么不直接识别字符串的3个部分及其相应的长度,然后将它们复制到目标缓冲区中的正确偏移量?

或者,如果您只需要在printf中使用结果,甚至不要复制!只需确定长度,然后执行以下操作:

代码语言:javascript
复制
printf("Directory: %.*s\n", dir_len, full_pathname);
printf("Filename: %.s*\n", name_len, full_pathname+name_start);
printf("Extension: %.*s\n", ext_len, full_pathname+ext_start);

如果您使用snprintf格式化文本以显示在UI元素中,情况也是如此……

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

https://stackoverflow.com/questions/3200980

复制
相关文章

相似问题

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