函數位於glibc源碼中的../glibc-version/string/argz-ctsep.c中,其做用是將字符串以指定的字符進行分割,指定字符的位置替換成空字符串(\0),使整個字符串造成一個argz vector。數組
argz vector是存儲在連續空間的一維字符數組,彼此之間以空字符(\0)進行分隔。函數
也就是說argz_create_sep函數的目的是將一個字符串按指定字符分割成多個字符串,存入一個連續空間中,彼此之間以空字符(\0)進行分隔,造成argz vector。測試
假如待分割字符串爲「argz_create_sep」,以r做分割符,獲得的argz vector應當以下所示:spa
函數聲明以下:rest
// argz.h /* Make a '\0' separated arg vector from a SEP separated list in STRING, returning it in ARGZ, and the total length in LEN. If a memory allocation error occurs, ENOMEM is returned, otherwise 0. The result can be destroyed using free. */ extern error_t __argz_create_sep (const char *__restrict __string, int __sep, char **__restrict __argz, size_t *__restrict __len) __THROW; extern error_t argz_create_sep (const char *__restrict __string, int __sep, char **__restrict __argz, size_t *__restrict __len) __THROW; /* */
函數的實現以下:code
error_t __argz_create_sep (const char *string, int delim, char **argz, size_t *len) { size_t nlen = strlen (string) + 1; if (nlen > 1) { const char *rp; char *wp; *argz = (char *) malloc (nlen); if (*argz == NULL) return ENOMEM; rp = string; wp = *argz; do if (*rp == delim) { if (wp > *argz && wp[-1] != '\0') *wp++ = '\0'; else --nlen; } else *wp++ = *rp; while (*rp++ != '\0'); if (nlen == 0) { free (*argz); *argz = NULL; *len = 0; } *len = nlen; } else { *argz = NULL; *len = 0; } return 0; } weak_alias (__argz_create_sep, argz_create_sep) /* */
代碼相對比較簡單,逐字符進行復制,遇到與delim相同的就替換成\0,而後繼續複製。字符串
須要注意的是若是待分割的字符串中存在連續的delim,那麼造成的argz vector中該部分字符串只有一個\0,同時len也會相應的減少。完成這個操做的是下面這段代碼,它主要是針對這類特殊狀況的處理(假設以s進行分割)。源碼
一、待分割字符串string的第一個字符就是delim相同(如:string Microsoft)string
二、待分割字符串string中存在連續個delim(如:string Microsssoft,或者ssssssssss)it
if (wp > *argz && wp[-1] != '\0') *wp++ = '\0'; else --nlen; /* */
調用__argz_create_sep函數的方式爲:
const char *mystring = "string microsoft"; char delim = 's'; __argz_create_sep(mystring, delim, &argz, &len); /* */
寫個程序測試一下:
#include <stdio.h> #include <stdlib.h> #include <string.h> #define ENOMEM 12 #define MYLEN 4 #ifndef __error_t_defined typedef int error_t; #endif error_t __argz_create_sep (const char *string, int delim, char **argz, size_t *len) { size_t nlen = strlen(string) + 1; if (nlen > 1) { const char *rp; char *wp; *argz = (char *) malloc (nlen); if (*argz == NULL) return ENOMEM; rp = string; wp = *argz; do if (*rp == delim) { if (wp > *argz && wp[-1] != '\0') *wp++ = '\0'; else --nlen; } else *wp++ = *rp; while (*rp++ != '\0'); if (nlen == 0) { free (*argz); *argz = NULL; *len = 0; } *len = nlen; } else { *argz = NULL; *len = 0; } return 0; } int main(void) { int i, j; size_t len[MYLEN]; char *argz[MYLEN]; char *testString[MYLEN] = { "function converts the argz", "tfunction converts the argz", "tttttttt", "" }; /* 以t做分割符 */ for(i=0; i<MYLEN; ++i){ __argz_create_sep(testString[i], 't', &argz[i], &len[i]); } for(i=0; i<MYLEN; ++i) { printf("NO.%d, lenght: %d\n+", i, len[i]); for(j=0; j<len[i]; ++j){ putchar('-'); } printf("+\n|"); for(j=0; j<len[i]; ++j){ putchar(argz[i][j]); } printf("|\n+"); for(j=0; j<len[i]; ++j){ putchar('-'); } printf("+\n\n"); } for(i=0; i<MYLEN; ++i){ if(argz[i]){ free(argz[i]); argz[i]=NULL; } } return 0; }
程序輸出以下:
注意,輸出結果中argz vector的字符串之間的「空格」並非空格,而是\0的輸出可是這個字符無法顯示的結果。
附:我以爲那個函數寫的太蛋疼了。。果真我仍是喜歡用for啊。。。
error_t __argz_create_sep (const char *string, int delim, char **argz, size_t *len) { size_t nlen = strlen (string) + 1; const char *rp; char *wp; if(nlen <= 1) { *argz = NULL; *len = 0; return 0; } *argz = (char *) malloc (nlen); if (*argz == NULL) return ENOMEM; for(rp = string, wp = *argz; *rp; ++rp) { if(*rp == delim) { if(wp > *argz && wp[-1] != '\0'){ *wp++ = '\0'; } else{ --nlen; } } else{ *wp++ = *rp; } } if (nlen == 0) { free (*argz); *argz = NULL; } *len = nlen; return 0; }
如今是2017年4月14日,看到之前寫的這一段內容,仔細思考了一下,果真仍是源碼厲害。for並不能徹底的處理由delim組成的字符串。如string="ssss", delim='s',當處理到最後一個字符時,源碼很可靠的讓nlen=1,而且argz[0]='\0'。可是我上面那個用for寫的,則沒有處理argz[0]='\0',直接致使argz中len=1,可是卻什麼都沒有。