从路径中提取名称的函数;
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;
}
试试
大家好,我有一个问题:我想编写一个函数,它采用 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;
}
试试