简体   繁体   English

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

[英]Transform 1D char array to 2D char array without allocating memory

I have a string, for example: 我有一个字符串,例如:

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

The string is composed with segments split by space, the number of segments is not fixed. 该字符串由按空格分隔的段组成,段的数量不固定。

Intuitively, I can get a 2D char string by allocating memory dynamically, for example: 直观地讲,我可以通过动态分配内存来获得2D char字符串,例如:

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

But can I transform the original array to 2d char array like below to avoid memory allocation? 但是我可以像下面那样将原始数组转换为2d char数组以避免内存分配吗?

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

As pointed out in another answer, strtok can be used to split up your string in-place so that delimiters (spaces) are replaced with null terminators. 正如另一个答案中指出的那样, strtok可用于就地拆分字符串,以便用空终止符替换定界符(空格)。

To know how many strings there will be, you'll have to iterate through the string twice. 要知道会有多少个字符串,您必须迭代两次该字符串。 For the first iteration, invent some quick & simple function that doesn't alter the string, like this: 对于第一次迭代,发明一些不改变字符串的快速简单的函数,如下所示:

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

Then for the second iteration, use strtok . 然后对于第二次迭代,使用strtok Full example: 完整示例:

#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]);
  }
}

Continuing from my comment, you can tokenize your string with, eg strtok and assign the pointers to the individual words to a pointer-to-pointer-to-char . 继续我的评论,您可以使用例如strtok标记字符串,并将各个单词的指针分配给指向char的指针 For example: 例如:

#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;
}

*Example Use/Output** *示例使用/输出**

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

Note: You cannot pass a string literal to strtok as strtok modifies the string. 注意:由于strtok修改了字符串,因此无法将字符串文字传递给strtok Either use a pointer to an array or declare and initialize as a normal char[] array to begin with. 使用指向数组的指针,或者声明并初始化为普通的char[]数组。


Dynamically allocating pointer for unknown number of words 动态分配指针用于未知数量的单词

If you have no idea whether you could read twenty words or 2000 words, you can easily handle the situation by dynamically allocating blocks of pointers, and then realloc ating again if the prior max allocation is again reached. 如果你不知道你是否能阅读二十字或2000个字,你可以很容易地通过动态地分配指针的块,然后再处理这种情况realloc再次阿婷如果再次达到最大值之前分配。 It is a simple process, eg 这是一个简单的过程,例如

#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;
}

Above, always validate your allocations with, eg if (!arr) { /* handle error */ } which was omitted from the initial allocation of arr for brevity. 上面,请始终使用if (!arr) { /* handle error */ }来验证您的分配,为简洁起见,在最初的arr分配中省略了它。

Example Use/Input 示例使用/输入

$ 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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM