开发者

memmove leaving garbage - C

I wrote the following function to split the given full path into directory, filename and extension.

#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->dire开发者_开发问答ctory);
    printf("Filename : %s\n", p->filename);
    printf("Extension : %s\n", p->extension);
    return 0;
}

This works well for the given input on GCC. But it fails on MSVC leaving some garbage data on extension variable. I have added a comment on the place where things go wrong. I am not understanding why memmove is behaving differently on MSVC? I have used memmove in two places and strange part is that the first one works fine.

Any help would be appreciated.


Try moving strlen(extension) + 1 bytes, so that you move not just the extension characters but the trailing null character as well. For example, if the extension was “abc”, then you're moving only 3 characters forward one space. There may have been a null character after the ‘c’ character, but no null character after that, so the string becomes unterminated when you shift the characters.


Your second memmove writes over the terminating '\0' byte. You could move strlen(extension)+1 bytes to solve that problem. I suspect that on GCC you got lucky and there happened to be an additional '\0' byte in the next memory location.


Pretty sure this has nothing to do with memmove but rather the rest of your string logic, which is a mess and very inefficient. Instead of copying at the beginning, why not just identify the 3 parts of your string and their corresponding lengths, then copy them into the destination buffer at the right offsets?

Or if you just need to use the results with printf, don't even make a copy! Just identify the lengths and do something like this:

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);

The same works if you're using snprintf to format the text for display in UI elements...


You aren't including null character while memmove(). Try this:

        memmove(last_separator + 1, last_separator, strlen(last_separator)+1); 
        memmove(extension + 1, extension, strlen(extension)+1);*/

EDIT: And here is a bit better way of the same thing that you are doing. This doesn't involve memmoves. But ofcourse you would need separate memory allocation(I am using strdup()). Nulls are also taken care of in the same memory space which was allocated by strdup().

    struct path_info* splitpath1(const char *full_path)
{
    char * path = strdup(full_path);
    char * fileWithExt = strtok((char *)strrchr(path,'\\'),"\\");

    struct path_info *p = (struct path_info*) malloc(sizeof(struct path_info));  /* Extra space for padding and shifting */
    p->filename = strtok(fileWithExt, ".");
    p->extension = strtok(NULL, ".");

    strtok((char *)strchr(path,'\\'),"\\");
    p->directory = path;

    return p;
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜