将1D char数组转换为2D char数组而不分配内存

时间:2017-04-12 04:33:29

标签: c arrays

我有一个字符串,例如:

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

字符串由按空格分割的段组成,段数不固定。

直观地说,我可以通过动态分配内存来获取2D字符串,例如:

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

但我可以将原始数组转换为2d char数组,如下所示,以避免内存分配吗?

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

2 个答案:

答案 0 :(得分: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]);
  }
}

答案 1 :(得分:0)

继续发表评论,您可以标记化您的字符串,例如strtok并将指向单个单词的指针分配给指向指针指向char 的指针。例如:

#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

注意:您无法将 字符串文字 传递给strtok,因为strtok会修改字符串。要么使用指向数组的指针,要么声明并初始化为正常的char[]数组。

动态分配未知字数的指针

如果您不知道是否可以读取20个单词或2000个单词,则可以通过动态分配指针块来轻松处理这种情况,然后再次realloc再次进行先前的最大分配。这是一个简单的过程,例如

#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