URL
题目
分析
源码
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
/* split string */
char ** split(const char *s , char delim , int * return_size){
int n = strlen(s);
/* 0. 申请空间,存储分割后的字符列表 */
char ** ans = (char **)malloc(sizeof(sizeof(char *))*n);
int pos = 0;
int curr = 0;
int len = 0;
/* 1. 遍历path,存储/xxxxx/之间的‘路径名’ */
while(pos < n){
/* 重复delim时,遍历并指到最后一个delim字符 */
while(pos < n && s[pos] == delim){
++pos;
}
/* 从delim开始,遍历到下一个delim,并指向下一个delim位置 */
curr = pos ;
while(pos < n && s[pos] != delim){
++pos;
}
/* 申请空间存储(delim,delim)中的‘路径名’ */
if(curr < n){
ans[len] = (char *)malloc(sizeof(char)*(pos - curr + 1)); //pos->delim , curr->delim , pos-curr == str_len , +1 for endl
strncpy(ans[len] , s + curr , pos - curr);
ans[len][pos - curr] = '\0'; // 注意结束符
++len; //‘路径名’ 元素个数
}
}
* return_size = len ;
return ans;
}
char * simplifyPath(char * path){
int names_size = 0;
int n = strlen(path);
/* 1. 按‘/’分割原始文件路径,并存储其中的每个‘路径名’ */
char ** names = split(path,'/',&names_size);
/* 2. 申请 stack */
char ** stack = (char **)malloc(sizeof(char *) * names_size);
int stack_size = 0;
/* 3. 判断分割后元素是否为.. 或者. ,判断最终文件路径 */
for(int i = 0;i < names_size ; ++i){
if(!strcmp(names[i],"..")){//当前路径为..,则实际有效文件夹个数-1
if(stack_size > 0){
--stack_size;
}
}else if (strcmp(names[i] , ".")){//当前路径不为.,则移动分割中的元素到stack中,追加到文件stack的路径中
stack[stack_size] = names[i];
++stack_size;
}
}
/* 4. 申请最终存储路径的空间 */
char * ans = (char *)malloc(sizeof(char) * (n+1));
int curr = 0 ;
/* 4.1 已经跳转到根目录 */
if (stack_size == 0){
ans[curr] = '/';
++curr;
}else{
/* 4.2 为stack中每个元素间添加'/' */
for (int i = 0; i < stack_size; ++i){
ans[curr] = '/';
++curr;
strcpy(ans + curr, stack[i]); //start_offset of ans
curr += strlen(stack[i]);// total_length of stack[xx]
}
}
/* 4.3 addin endl */
ans[curr] = '\0';
/* 5.释放二级指针空间 */
for(int i = 0;i<names_size; ++i){
free(names[i]);
}
/* free mem */
free(names);
free(stack);
return ans;
}
int main()
{
char p1[] = "/home/";
char p2[] = "/../";
char p3[] = "/home//foo/";
char p4[] = "/a/./b/../../c/";
printf("before : %s\n",p1);
printf("after : %s\n\n",simplifyPath(p1));
printf("before : %s\n",p2);
printf("after : %s\n\n",simplifyPath(p2));
printf("before : %s\n",p3);
printf("after : %s\n\n",simplifyPath(p3));
printf("before : %s\n",p4);
printf("after : %s\n\n",simplifyPath(p4));
return 0;
}
before : /home/
after : /home
before : /../
after : /
before : /home//foo/
after : /home/foo
before : /a/./b/../../c/
after : /c
源码概述
- 以‘/’为分隔符,切分原始path,并将每个元素存储到names[]字符串列表中,并记录总“文件夹”个数。
- 遍历上述列表,if为…,则总文件夹个数-1,else if为.,则将当前列表中的元素赋值给最终存储的空间中ans[]。
- 为ans的每个元素中间添加一个’/’
- done.
将原始路径按“/”划分并存储在列表中,
申请stack空间存储最终有效的文件夹名称,通过判断上述列表中每个元素的操作逻辑,如… 或者 不为. --因为情况是限定的,只能是“.”、“…”、“文件名”三种情况。–来判断当前空间的元素赋值情况,为…表示当前上一元素值无效,做自减操作,后续赋值会覆盖当前位置;不为.则表示当前列表中的元素为文件夹,存储到申请的stack元素中。
申请新空间ans,存储完整且合法的路径。为每个stack元素之间添加“/”字符,使其表达方式合法。
小结
PS:
利用入栈出栈的机制,在遍历时确保当前元素始终为最终的操作目录,最后再合法化字符串即可。
三次申请内存空间。