加载字符串除以分隔符到数组

时间:2018-01-28 17:00:03

标签: c arrays delimiter

我有一个数组需要填充来自字符串的值,如下所示:

value0;value1;value2;value3;\n

我尝试使用strtok(),但无法真正弄清楚如何在表格中正确加载2个以上的元素。

理想的输出类似于

arrayValues[0] = value0;
arrayValues[1] = value1;

3 个答案:

答案 0 :(得分:0)

您需要使用strtok()和realloc()。两者都有点难以使用

char input[] = "value0;value1;value2;value3\n";
char **arrayValues = NULL;
int N = 0;
char *token = strtok(input, ";");

while(token != 0)
{
   N++;
   arrayValues = realloc(arrayValues, N * sizeof(char *));
   if(!arrayValues)
      /* out of memory - very unlikely to happen */
   arrayValues[N-1] = strdup(token);
   token = strtok(NULL, ";");
}

/* print out to check */
for(i=0;i<N;i++)
  printf("***%s***\n", arrayValues[i]);

请注意分隔符&#39;;&#39;被覆盖,如果你按照你的指定保留它,你必须将它添加到字符串的末尾,这很繁琐,可能不是你真正想要的。

答案 1 :(得分:0)

您可以使用良好的旧strchr函数来搜索子字符串';'终结符,并使用mallocrealloc进行内存分配。

请注意输入str已修改(重复使用)。在该字符串中,';''\0'取代。

(如果您需要str而不是分配另一个缓冲区,请将str复制到它并指向p1,p2指针。)

arrayValues保存指向子字符串的指针:

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

int main ()
{
    char **arrayValues = malloc(sizeof(char *)); // allocate memory for string pointers

    char str[] = "value1;value2;value3\n"; // input

    char *p1 = str;  // init pointer helpers
    char *p2 = str;

    int n = 0; // substring counter

    // OPTIONAL if you want to get rid of ending '\n'
    //--s
    size_t len = strlen(str);
    if(len>0)
        if(str[len-1] == '\n')
            str[len-1] = 0;
    //--ee

    while(p1 != NULL)
    {
      p1 = strchr(p1,';');     // find ';'

      if(p1 != NULL)
      {
        arrayValues[n] = p2; // begining of the substring
        *p1 = 0;             // terminate the substring string; get rid of ';'

        n++;                 // count the substrings

        arrayValues = realloc( arrayValues, (n+1) * sizeof(char *)); // allocate more memory for next pointer

        p2 = p1+1; // move the ponter after the ';'
        p1 = p1+1; // we start the search for next ';'
      }
      else
      {
        arrayValues[n] = p2; // this is the last (or first) substring     
        n++;   
      }
    } // while


    // Output:
    for (int j=0; j<n; j++)
    {
        printf("%s \n", arrayValues[j]);
    }

    printf("------");

    free(arrayValues);
    return 0;
}

输出:

value1 
value2 
value3 
------

答案 2 :(得分:0)

以最简单的形式,如果您在使用单个令牌期间需要分离的字符串将保留在范围内,则无需分配。只需声明一个指针数组,其中包含足够数量的指针用于您拥有的标记,并且当您对字符串进行标记时,只需将每个标记开头的地址指定给指针数组中的指针即可。这样,数组中的指针只指向原始字符串中找到每个标记的位置。例如:

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

#define MAXS 16

int main (void) {
    char str[] = "value0;value1;value2;value3;\n",
        *array[MAXS] = {NULL},      /* array of pointers */
        *p = str,                   /* pointer to str */
        *delim = ";\n";             /* delimiters */
    int i, n = 0;                   /* loop var & index - n */

    p = strtok (p, delim);          /* get 1st token */
    while (n < MAXS && p) {         /* check bounds/validate token */
        array[n++] = p;             /* add pointer to array */
        p = strtok (NULL, delim);   /* get next token */
    }

    for (i = 0; i < n; i++)         /* output tokens */
        printf ("array[%2d] : %s\n", i, array[i]);

    return 0;
}

注意: strtok 修改原始字符串,方法是放置 nul-terminatedating 字符(例如'\0')代替分隔符。如果你需要保留原始字符串,请在调用strtok之前复制一份)

请注意,您只能使用固定数量的指针,因此在分离标记并将其分配给数组中的指针时,需要根据数组边界检查数字防止写入数组的末尾。

示例使用/输出

$ ./bin/parsestrstrtok
array[ 0] : value0
array[ 1] : value1
array[ 2] : value2
array[ 3] : value3

将解析转到下一步,在需要数组值的时候,原始字符串可能不会保留在范围内,您只需为每个标记分配存储空间并将每个标记复制到新分配的内存中并分配每个新块的起始地址到数组中的指针。这样,即使您将指针数组和字符串传递给函数进行解析,在函数完成后数组值仍然可用,直到您free已分配的内存为止。

您仍然只能使用固定数量的指针,但您的阵列现在可以在程序中的任何位置使用。为此所需的添加量是最小的。请注意,mallocstrcpy在下方使用,可以通过对strdup的单次调用来替换。但是,由于strdup不是所有C版本的一部分,因此会使用mallocstrcpy。 (但请注意,如果您的编译器支持,strdup确实可以非常方便地替换它)

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

#define MAXS 16

int main (void) {
    char str[] = "value0;value1;value2;value3;\n",
        *array[MAXS] = {NULL},      /* array of pointers */
        *p = str,                   /* pointer to str */
        *delim = ";\n";             /* delimiters */
    int i, n = 0;                   /* loop var & index - n */

    p = strtok (p, delim);          /* get 1st token */
    while (p) {                     /* validate token */
        /* allocate/validate storage for token */
        if (!(array[n] = malloc (strlen (p) + 1))) {
            perror ("malloc failed");
            exit (EXIT_FAILURE);
        }
        strcpy (array[n++], p);     /* copy token to array */
        p = strtok (NULL, delim);   /* get next token */
    }

    for (i = 0; i < n; i++) {       /* output tokens */
        printf ("array[%2d] : %s\n", i, array[i]);
        free (array[i]);            /* free memory for tokens */
    }

    return 0;
}

(输出相同)

最后,通过动态分配指针并根据需要重新分配指针,可以消除对固定数量指针的依赖性。您可以从相同的数字开始,然后在当前电源耗尽时分配当前指针数的两倍。在开始解析之前,它只是一个额外的分配级别,当您使用了所有指针时需要realloc。例如:

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

#define MAXS 16

int main (void) {
    char str[] = "value0;value1;value2;value3;\n",
        **array = NULL,             /* pointer to pointer to char */
        *p = str,                   /* pointer to str */
        *delim = ";\n";             /* delimiters */
    int i, n = 0,                   /* loop var & index - n */
        nptrs = MAXS;               /* number allocated pointers */

    /* allocate/validate an initial number of pointers for array */
    if (!(array = malloc (nptrs * sizeof *array))) {
            perror ("malloc pointers failed");
            exit (EXIT_FAILURE);    
    }

    p = strtok (p, delim);          /* get 1st token */
    while (p) {                     /* validate token */
        /* allocate/validate storage for token */
        if (!(array[n] = malloc (strlen (p) + 1))) {
            perror ("malloc failed");
            exit (EXIT_FAILURE);
        }
        strcpy (array[n++], p);     /* copy token to array */
        if (n == nptrs) {           /* pointer limit reached */
            /* realloc 2X number of pointers/validate */
            void *tmp = realloc (array, nptrs * 2 * sizeof *array);
            if (!tmp) {
                perror ("realloc - pointers");
                goto memfull;  /* don't exit, array has original values */
            }
            array = tmp;            /* assign new block to array */
            nptrs *= 2;             /* update no. allocated pointers */
        }
        p = strtok (NULL, delim);   /* get next token */
    }
    memfull:;

    for (i = 0; i < n; i++) {       /* output tokens */
        printf ("array[%2d] : %s\n", i, array[i]);
        free (array[i]);            /* free memory for tokens */
    }
    free (array);                   /* free memory for pointers */

    return 0;
}

注意:您应该使用内存使用和错误检查程序验证您的内存使用情况,例如Linux上的valgrind。每个平台都有类似的工具。只需通过检查程序运行代码并验证没有内存错误,并且已分配的所有内存都已正确释放。

示例:

$ valgrind ./bin/parsestrstrtokdbl
==15256== Memcheck, a memory error detector
==15256== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==15256== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==15256== Command: ./bin/parsestrstrtokdbl
==15256==
array[ 0] : value0
array[ 1] : value1
array[ 2] : value2
array[ 3] : value3
==15256==
==15256== HEAP SUMMARY:
==15256==     in use at exit: 0 bytes in 0 blocks
==15256==   total heap usage: 5 allocs, 5 frees, 156 bytes allocated
==15256==
==15256== All heap blocks were freed -- no leaks are possible
==15256==
==15256== For counts of detected and suppressed errors, rerun with: -v
==15256== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

**注意上面你看到5个分配(指针为1,每个令牌为1)。所有内存都已释放,没有内存错误。

你可以采取更多的方法来减少你的字符串选择令牌,但这是如何使用strtok扩展方法的一般进展。如果您有任何其他问题,请与我们联系。