argz_create_sep函數

函數位於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,可是卻什麼都沒有。

相關文章
相關標籤/搜索