从路径中提取名称的函数;

Function for extracting a name from a path;

大家好,我有一个问题:我想编写一个函数,它采用 char* 形式的字符串,表示路径,例如:“/1/2/3/4/5”(始终以一种 /)。该函数有两个目的,提取(和 return)名字并从列表中删除该名字。

与前面的示例 /1/2/3/4/5 -> /2/3/4/5 一样,函数将 return "1";

任何人都可以给我任何想法,我该如何构造它我很新,两个 C 和字符串作为 char 指针的整个概念让我有点震惊

因为是斜线开头,所以可以从第二个位置开始:

char* extract (char *path)
{
    int i;
    char *first;
    for(i = 1; path[i] != '/'; i++); //this for is only to get to the second slash
    
    path[i] = '[=10=]'; // here you erase the second slash
   
    first = (char*) malloc(sizeof(char) * (strlen(&path[1]) + 1)); //allocate space for the string plus the '[=10=]'
    strcpy(first, &path[1]);  //copy what you wanted to extract
    strcpy(&path[1], &path[i + 1]); // copy the things that remained back to the second position.
   //The first position is still the same slash and keeps unaltered
    return first;
} 

您可以像这样测试您的功能:

int main()
{
    char c[] =  "/1/2/3/4/5";
    printf("%s %s\n", extract(c), c);
    return 0;
}

删除第一个元素可以只用指针运算来完成。

int i;
for(i = 1; path[i] != '/'; i++);
path += i;

您既要路径的第一部分,又要更改路径。在 C 中你不能 return 两个东西。相反,我们可以使用双指针来更改 path 指向的位置。

char* extract_first_directory(char **path) {
    // Find the index of the second /
    int i;
    for(i = 1; (*path)[i] != '/'; i++);

    // Allocate enough memory for the first part and a null byte.
    // The length of the first part is i - 1. We need an extra byte for the
    // null byte so i - 1 + 1 is just i.
    char *first = malloc(sizeof(char) * i);

    // Copy just the first portion.
    strncpy(first, *path + 1, i-1);

    // Add the null byte to `first` because stpncpy doesn't do that.
    first[i] = '[=11=]';

    // Move the start of path to the second /
    *path += i;

    return first;
}

需要注意的是,由于我们移动了 path 指向的位置,如果我们 free(path) 它将泄漏内存。所以我们保留原来的指针。

int main() {
    // Can't change "/1/2/3/4/5", it has to be copied to stack memory.
    char *path = strdup("/1/2/3/4/5");

    // Keep the original pointer so it can be freed.
    char *new_path = path;
    char *first = extract_first_directory(&new_path);
    printf("first: %s, new: %s, path: %s\n", first, new_path, path);

    // This will also free new_path.
    free(path);

    return 0;
}

另一种方法可能是使用 strtok 和 return 将每个路径元素包含为数组的结构一次进行所有拆分。

typedef struct {
    char *path;
    char **entries;
    size_t num_entries;
    size_t max_size;
} Path;

Path *Path_new() {
    Path *path = malloc(sizeof(Path));

    path->path = NULL;
    // Starting with some space allocated makes extending simpler.
    path->entries = malloc(sizeof(char**) * 2);
    path->max_size = 2;
    path->num_entries = 0;

    return path;
}

void Path_append_entry(Path *path, char *entry) {
    // Double the size as needed.
    if( path->max_size <= path->num_entries ) {
        path->entries = realloc(path->entries, sizeof(char**) * 2 * path->max_size);
        path->max_size *= 2;
    }
    path->entries[ path->num_entries ] = entry;
    path->num_entries++;
}

void Path_init(Path *path, const char *original) {
    // Copy the path because strtok works by replacing the / with nulls.
    path->path = strdup(original);

    for(
        char *token = strtok(path->path, "/");
        token;
        token = strtok(NULL, "/")
    ) {
        puts(token);
        Path_append_entry(path, token);
    }
}

void Path_print(Path *path, int i) {
    for(; i < path->num_entries; i++ ) {
        printf("/");
        printf("%s", path->entries[i]);
    }
    puts("");
}

int main() {
    char path[] = "/1/2/3/4/5";

    Path *p = Path_new();
    Path_init(p, path);
    printf("first: %s\n", p->entries[0]);
    Path_print(p, 1);

    return 0;
}

如果您不想动态分配内存,您可以就地编辑字符串。如果您将第一个斜杠和第二个斜杠之间的东西移回一个,那么会有一个 space 作为字符串终止字符。这样你就不需要释放函数返回的指针。

char *extract(char **path)
{
    // save the start of the string
    char *first = *path;
    if (!*first) return first;
    // find the second slash or the end of the string
    char *rest = strchr(first+1,'/');
    if (!rest) rest = first+strlen(first);
    // move the stuff between the first and second slash back one
    memmove(first,first+1,rest-first);
    *(rest-1)='[=10=]';
    // set the output parameters
    *path = rest;
    return first;
}

这是一个完整的示例程序:

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

// This function asumes the first character is a slash
// that first character is overwritten so it had better be a slash...
// 'path' is a pointer to the string so that we can change where it points
char *extract(char **path)
{
    // we repoint path before we return so we need a pointer to the start
    char *first = *path;
    // if the string is empty then don't do anything
    if (!*first) return first;
    // look for a slash after that first one
    char *rest = strchr(first+1,'/');
    // if we didn't find a second slash, point to the end of the string
    if (!rest) rest = first+strlen(first);
    // move the bit between the first and second slash back one to get rid the the leading slash
    memmove(first,first+1,rest-first);
    // make sure the end of the first bit has a string terminator
    *(rest-1)='[=11=]';
    // update the path to the new starting place
    *path = rest;
    // return the first bit
    return first;
}

int main()
{

    char a0[] = ""; // somewhere writable to store the string
    char *s0=a0; // a pointer to the start of the string that can be changed
    printf("before: \"%s\"\n",s0);
    printf("return: \"%s\"\n",extract(&s0));
    printf("after:  \"%s\"\n",s0);
    puts("---");
    
    char a1[] = "/"; // somewhere writable to store the string
    char *s1=a1; // a pointer to the start of the string that can be changed
    printf("before: \"%s\"\n",s1);
    printf("return: \"%s\"\n",extract(&s1));
    printf("after:  \"%s\"\n",s1);
    puts("---");
    
    char a2[] = "//"; // somewhere writable to store the string
    char *s2=a2; // a pointer to the start of the string that can be changed
    printf("before: \"%s\"\n",s2);
    printf("return: \"%s\"\n",extract(&s2));
    printf("after:  \"%s\"\n",s2);
    puts("---");
    
    char a3[] = "/asd"; // somewhere writable to store the string
    char *s3=a3; // a pointer to the start of the string that can be changed
    printf("before: \"%s\"\n",s3);
    printf("return: \"%s\"\n",extract(&s3));
    printf("after:  \"%s\"\n",s3);
    puts("---");
    
    char a4[] = "/asd/qwe"; // somewhere writable to store the string
    char *s4=a4; // a pointer to the start of the string that can be changed
    printf("before: \"%s\"\n",s4);
    printf("return: \"%s\"\n",extract(&s4));
    printf("after:  \"%s\"\n",s4);
    puts("---");
    
    char a5[] = "/asd/qwe/zxc"; // somewhere writable to store the string
    char *s5=a5; // a pointer to the start of the string that can be changed
    printf("before:   \"%s\"\n",a5);
    printf("return 1: \"%s\"\n",extract(&s5));
    printf("after  1: \"%s\"\n",s5);
    printf("return 2: \"%s\"\n",extract(&s5));
    printf("after  2: \"%s\"\n",s5);
    printf("return 3: \"%s\"\n",extract(&s5));
    printf("after  3: \"%s\"\n",s5);
    
    return 0;
}

https://onlinegdb.com/r1JKsTpsv

试试