2017-04-12 129 views
0

我有一个字符串,例如:变换1D char数组到2D char数组而不分配存储器

char* cmd = "a bcd ef hijk lmmopq";

该字符串由通过空间分割的段,段的数目是不固定的。

直观地说,我可以通过动态地分配存储器中,例如一个二维字符的字符串:

char** argv = malloc(); 
char* argv[0] = malloc(); 
... 
char* argv[i] = malloc(); 

但我可以将原始阵列至2d类似下面字符数组,以避免存储器分配?

char* argv[] = {"a", "bcd", "ef", "hijk", "lmmopq"}; 
+1

'char ** argv'不是二维数组,而是指向指针的指针。 'char a [3] [4]'是一个2D数组。 – chux

+0

*“但是,我可以得到像下面这样的2d char数组,以避免内存分配”*您可以得到什么意思?从哪里得到?你事先知道这个数组的大小吗? –

+0

我想将原始cmd转换为2d数组。之后,我想使用它作为一个二维数组。@ AlexLop。 –

回答

0

从我的评论继续,你可以记号化你的字符串,例如strtok并将指向单个单词的指针分配给指针指向字符的指针。例如:

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

#define MAX 10 

int main (void) { 

    char *cmd = (char[]){"a bcd ef hijk lmmopq"},  /* compound literal */ 
    // char cmd[] = "a bcd ef hijk lmmopq"; /* otherwise declare as array */ 
     *arr[MAX] = {NULL}, 
     *delim = " \n"; 
    size_t n = 0; 

    for (char *p = strtok (cmd, delim); n < MAX && p; p = strtok (NULL, delim)) 
     arr[n++] = p; 

    for (int i = 0; i < (int)n; i++) 
     printf ("arr[%d]: %s\n", i, arr[i]); 

    return 0; 
} 

*示例使用/输出**

$./bin/str2ptp 
arr[0]: a 
arr[1]: bcd 
arr[2]: ef 
arr[3]: hijk 
arr[4]: lmmopq 

注:你不能传递一个字符串文字strtokstrtok修改字符串。可以使用指向数组的指针,也可以声明并初始化为一个正常的char[]数组。


动态未知数量的单词

如果你不知道你是否能阅读二十字或2000个字,你可以很容易地通过动态地分配指针块地处理这种情况的分配指针,那么如果再次达到先前的最大分配,则再次进行。这是一个简单的过程,例如

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

#define MAX 10 
#define MAXB 4096 

int main (void) { 

    char cmd[MAXB] = "", /* buffer of 4096 chars to hold each line input */ 
     **arr = calloc (MAX, sizeof *arr), 
     *delim = " \n"; 
    size_t n = 0, max = MAX; 

    while (fgets (cmd, MAXB, stdin)) { /* read each line of input on stdin */ 

     size_t len = strlen (cmd); /* get line length */ 
     if (cmd[len - 1] == '\n') /* test for trailing '\n' */ 
      cmd[--len] = 0;   /* overwrite with nul-byte */ 

     for (char *p = strtok (cmd, delim); p; p = strtok (NULL, delim)) { 
      arr[n++] = p; 

      if (n == max) { /* realloc arr by MAX if n == MAX */ 
       void *tmp = realloc (arr, (max + MAX) * sizeof *arr); 
       if (!tmp) { 
        fprintf (stderr, "error: memory exhausted.\n"); 
        break; 
       } 
       arr = tmp; /* zero new pointers (optional) */ 
       memset (arr + max, 0, MAX * sizeof *arr); 
       max += MAX; /* update current max iteration */ 
      } 
     } 
     for (int i = 0; i < (int)n; i++) 
      printf ("arr[%2d]: %s\n", i, arr[i]); 
    } 

    free (arr); /* don't forget, if you allocate it -> you free it. */ 

    return 0; 
} 

上面总是验证您的分配,例如, if (!arr) { /* handle error */ }为简洁起见,其从arr的初始分配中省略。

示例使用/输入

$ echo "A quick brown fox jumps over the lazy dog while the dog watched" | \ 
./bin/strtop2pdyn 
arr[ 0]: A 
arr[ 1]: quick 
arr[ 2]: brown 
arr[ 3]: fox 
arr[ 4]: jumps 
arr[ 5]: over 
arr[ 6]: the 
arr[ 7]: lazy 
arr[ 8]: dog 
arr[ 9]: while 
arr[10]: the 
arr[11]: dog 
arr[12]: watched 
+0

如果有20个令牌,该怎么办?或100?最后一个标记将由'X-MAX'空格分隔的子字符串组成 – Rogus

+0

您可以将'MAX'设置为足够大,或者根据需要动态分配*,您的选择。但是,在这个问题的背景下,问题定义是针对一组“5”代币。如果我正在实现这一点,那么我会动态地在'arr'中分配第一个'MAX'指针,然后根据需要调用'realloc'来处理行中有多少个单词。 –

+0

这是正确的,但OP表示令牌的数量不固定,他希望避免内存分配。大多数时候将MAX设置为足够大的值,但恕我直言,这是不好的做法。 – Rogus

1

正如另一个答案指出,strtok可以用来使分隔符(空格)与空终结取代分裂的就地字符串。

要知道会有多少个字符串,您必须遍历字符串两次。对于第一次迭代,发明一些快速&简单的函数,不改变字符串,像这样:

size_t count_spaces (const char* src) 
{ 
    size_t spaces=0; 
    for(; *src != '\0'; src++) 
    { 
    if(*src == ' ') 
    { 
     spaces++; 
    } 
    } 
    return spaces; 
} 

然后为第二次迭代,使用strtok。完整示例:

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

size_t count_spaces (const char* src) 
{ 
    size_t spaces=0; 
    for(; *src != '\0'; src++) 
    { 
    if(*src == ' ') 
    { 
     spaces++; 
    } 
    } 
    return spaces; 
} 

void tokenize (char* restrict src, 
       size_t dst_size, 
       char* restrict dst [dst_size]) 
{ 
    size_t i; 
    char* ptr = strtok(src, " "); 
    for(i=0; i<dst_size && ptr != NULL; i++) 
    { 
    dst[i] = ptr; 
    ptr = strtok(NULL, " "); 
    } 
} 

int main (void) 
{ 
    char str [] = "a bcd ef hijk lmmopq"; 
    size_t size = count_spaces(str) + 1; 
    char* ptr_arr [size]; 

    tokenize(str, size, ptr_arr); 

    for(size_t i=0; i<size; i++) 
    { 
    puts(ptr_arr[i]); 
    } 
}