2016-05-15 25 views
1

我想使用NUL char作为分隔符将char数组拆分为标记。将字符数组拆分为分隔符为NUL的标记char

我有一个字符数组,我通过网络从recv命令收到,所以我知道char数组的长度。在那个char数组中,有一堆被NUL char(\0)分开的字符串。

由于分隔符是NUL字符,这意味着我不能使用strtok,因为它使用NULL用于自己的目的。

所以我想遍历从字节8开始的所有字符串(字符串前面有2个32位整数)。

我想我可以遍历虽然所有字符寻找\0字符,然后做到目前为止,我已经找到了长度的memcpy,但我想一定有比这一个更好的方法。

我还能采取哪些其他方法?

+2

如果您不需要重新使用其他缓冲区,可以将字符串保存在那里,只需使用指向它们开始的指针即可。它们已经被NUL终止。 –

+0

@ ThomasPadron-McCarthy我在一段时间内没有做太多的事情,我该如何再次移动指针的位置? –

+1

或者,如果你确实需要重新使用缓冲区,你可以找到每个字符串的第一个字符和'strcpy()'或'strdup()'它。无论哪种方式,都要确保最后一个字符串也是以null结尾的,否则将其作为特殊情况处理。 –

回答

1

下面是一些简单的代码展示了如何获取包含字符串:

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

int main(void) { 
    char recbuf[7] = {'a', 'b', 'c', '\0', 'd', 'e', '\0'}; 
    int recbuf_size = 7; 
    int j = 0; 
    char* p = recbuf; 
    while(j < recbuf_size) 
    { 
     printf("%s\n", p); // print the string found 
          // Here you could copy the string if needed, e.g. 
          // strcpy(mySavedStrings[stringCount++], p); 

     int t = strlen(p); // get the length of the string just printed 
     p += t + 1;   // move to next string - add 1 to include string termination 
     j += t + 1;   // remember how far we are 
    } 
    return 0; 
} 

输出:

abc 
de 

如果您需要跳过一些字节的缓冲区的开始,然后只是不:

int number_of_bytes_to_skip = 4; 
int j = number_of_bytes_to_skip; 
char* p = recbuf + number_of_bytes_to_skip; 

注意:

上面的代码假定接收缓冲区是总是正确地以'\0'终止。在现实世界中的代码,你应该检查在运行代码之前,并添加错误处理,例如:

if (recbuf[recbuf_size-1] != '\0') 
{ 
    // Some error handling... 
} 
+0

我重新使用recbuf进行recv的多个调用。这是否意味着我需要重置指针回到开始使用这种方法?如果我在遍历它之前简单地复制recbuf,那么原始指针应该可以? –

+0

@JoelPearson - 当你收到一个新的缓冲区时,你需要将指针'p'设置为新缓冲区的地址(并添加跳过的字节数)。如果你重用相同的接收缓冲区,那么你需要在解析缓冲区之前设置指针'p' – 4386427

+0

啊我看到char p *解决了我的问题,谢谢! –

0

NUL分离实际上使您的工作很容易。

char* DestStrings[MAX_STRINGS]; 
int j = 0; 
int length = 0; 
inr prevLength =0; 
int offset = 8; 
for(int i = 0;i<MAX_STRINGS;i++) 
{ 
    length += strlen(&srcbuffer[j+offset+length]); 
    if(length == prevLength)       
    { 
     break; 
    } 
    else 
    { 

     DestStrings[i] = malloc(length-prevLength+1); 
     strcpy(DestStrings[i],&srcbuffer[j+offset+length]); 
     prevLength = length; 
     j++; 
    } 

} 

您需要添加一些额外的检查以避免潜在的缓冲区溢出错误。 希望这段代码能让你对如何继续前进有一点点想法。

编辑1: 尽管这是由于修改索引而导致修改索引而不是整个解决方案的代码。

编辑2: 由于已知接收数据缓冲区的长度,请将NUL附加到接收到的数据以使此代码正常工作。另一方面,接收数据的长度本身可以用来与复制的长度进行比较。

0

假设该输入数据:

char input[] = { 
    0x01, 0x02, 0x0a, 0x0b, /* A 32bit integer */ 
    'h', 'e', 'l', 'l', 'o', 0x00, 
    'w', 'o', 'r', 'l', 'd', 0x00, 
    0x00 /* Necessary to make the end of the payload. */ 
}; 

在开始一个32整数给出:

const size_t header_size = sizeof (uint32_t); 

解析输入可以通过识别“串”来完成的第一字符和存储指向它的指针,然后精确地移动到找到的字符串很长(1+),然后重新开始,直到达到输入的结尾。

size_t strings_elements = 1; /* Set this to which ever start size you like. */ 
size_t delta = 1; /* 1 is conservative and slow for larger input, 
        increase as needed. */ 

/* Result as array of pointers to "string": */ 
char ** strings = malloc(strings_elements * sizeof *strings); 

{ 
    char * pc = input + header_size; 
    size_t strings_found = 0; 
    /* Parse input, if necessary increase result array, and populate its elements: */ 
    while ('\0' != *pc) 
    { 
    if (strings_found >= strings_elements) 
    { 
     strings_elements += delta; 
     void * pvtmp = realloc(
     strings, 
     (strings_elements + 1) * sizeof *strings /* Allocate one more to have a 
             stopper, being set to NULL as a sentinel.*/ 
    ); 

     if (NULL == pvtmp) 
     { 
     perror("realloc() failed"); 
     exit(EXIT_FAILURE); 
     } 

     strings = pvtmp; 
    } 

    strings[strings_found] = pc; 
    ++strings_found; 

    pc += strlen(pc) + 1; 
    } 

    strings[strings_found] = NULL; /* Set a stopper element. 
            NULL terminate the pointer array. */ 
} 

/* Print result: */ 
{ 
    char ** ppc = strings; 
    for(; NULL != *ppc; ++ppc) 
    { 
    printf("%zu: '%s'\n", ppc - strings + 1, *ppc) 
    } 
} 

/* Clean up: */ 
free(strings); 

如果您需要在分裂复制,通过

strings[strings_found] = strdup(pc); 

替换该行

strings[strings_found] = pc; 

和使用之后添加清理代码和ING stringsfree()前:

{ 
    char ** ppc = strings; 
    for(; NULL != *ppc; ++ppc) 
    { 
    free(*ppc); 
    } 
} 

上面的代码假定至少有1 '\0'NUL又名空字符)跟在有效负载之后。

如果后面的条件没有得到满足,您需要定义任何其他终止序列/ around或需要知道其他来源的输入大小。如果你不是你的问题是不可解决的。

上面的代码需要以下标题:

#include <inttypes.h> /* for int32_t */ 
#include <stdio.h> /* for printf(), perror() */ 
#include <string.h> /* for strlen() */ 
#include <stdlib.h> /* for realloc(), free(), exit() */ 

,以及它可能需要以下定义之一:

#define _POSIX_C_SOURCE 200809L 

#define _GNU_SOURCE 

或什么别的你的C编译器要求做出strdup()可用。

0

我使用实施做这类工作的分词结构建议。阅读和维护会更容易,因为它看起来类似于面向对象的代码。它隔离了memcpy,所以我认为它“更好”。

首先,标题我将使用:

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

标记生成器structurehas记住字符串的开头(这样我们就可以抹去的记忆不是不再需要后),实际的指数和检查我们是否已经解析了整个字符串:

struct Tokenizer { 
    char *string; 
    char *actual_index; 
    char *end_index; 
}; 

我建议使用类似工厂的函数来创建一个标记器。它在这里构建,使用memcpy复制输入字符串,因为string.h函数在第一个'\ 0'字符处停止。

struct Tokenizer getTokenizer(char string[], unsigned length) { 
    struct Tokenizer tokenizer; 
    tokenizer.string = (char *)malloc(length); 
    tokenizer.actual_index = tokenizer.string; 
    tokenizer.end_index = tokenizer.string + length; 
    memcpy(tokenizer.string, string, length); 
    return tokenizer; 
} 

现在负责获取令牌的功能。它返回新分配的字符串,它们的末尾有'\ 0'字符。它也改变了actual_index指向的地址。它采用分词作为参数的地址,所以它可以改变自己的价值观:

char * getNextToken(struct Tokenizer *tokenizer) { 
    char * token; 
    unsigned length; 
    if(tokenizer->actual_index == tokenizer->end_index) 
     return NULL; 
    length = strlen(tokenizer->actual_index); 
    token = (char *)malloc(length + 1); 
    // + 1 because the '\0' character has to fit in 
    strncpy(token, tokenizer->actual_index, length + 1); 
    for(;*tokenizer->actual_index != '\0'; tokenizer->actual_index++) 
     ; // getting the next position 
    tokenizer->actual_index++; 
    return token; 
} 

样品使用标记生成器,以显示如何处理内存分配昂如何使用它。

int main() { 
    char c[] = "Lorem\0ipsum dolor sit amet,\0consectetur" 
     " adipiscing elit. Ut\0rhoncus volutpat viverra."; 
    char *temp; 
    struct Tokenizer tokenizer = getTokenizer(c, sizeof(c)); 
    while((temp = getNextToken(&tokenizer))) { 
     puts(temp); 
     free(temp); 
    } 
    free(tokenizer.string); 
    return 0; 
} 
+0

我来自Java背景,所以这种方式对我来说读起来好多了,谢谢。 –

相关问题