2017-04-12 59 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]); 
    } 
}