如何在 C 中将逗号分隔的 char* 转换为 uint32_t[] 数组

How to convert comma separated char* to uint32_t[] array in C

我想在 C 语言中将逗号分隔的 char* 转换为 uint32_array[]。有没有简单的 method/routine 来做到这一点?

我已经在 SO 上花了很多时间,并在 C++ 上找到了很多解决方案,但不是这样的 C: Parsing a comma-delimited std::string 但我认为从 char* 转换为字符串到字符串流再转换为向量并使用向量并不是一个好的解决方案。

char input[] = "1 , 2 , 34, 12, 46, 100";

uint32_t output[] = { 1 , 2 , 34, 12, 46, 100 };

如有任何帮助,我将不胜感激。非常感谢。

一种方法(很多):

int converted = 0 ;
char* tok = input ;
int i = 0 ;
do
{
    converted = sscanf( tok, "%d", &output[i] ) ;
    tok = strchr( tok, ',' ) + 1 ;
    i++ ;

} while( tok != NULL && converted != 0 ) ;

您可以使用 strtok() 代替 sscanf()strchr(),但是 修改了 input,这可能是不可取的。

如果输入是流而不是字符串,那么更简单:

int converted = 0 ;
int i = 0 ;
do
{
    converted = fscanf( fd, "%d,", &output[i] ) ;
    i++ ;

} while( !feof( fd ) && converted != 0 ) ;

我没有包含任何方法来防止 output[i] 超出范围 - 您可能也需要考虑这一点。

通读一次字符串以找出如何调整数组大小:

uint32_t n = 1;
for (uint32_t idx = 0; idx < strlen(input); idx++) {
    if (input[idx] == ',') {
        n++;
    }
}

有一种不同的方法可以做到这一点,它不需要读取整个字符串,但需要在新元素进入时调整目标数组的大小,这使得代码更加复杂。对于小字符串,读取一次字符串很容易。

创建目标数组:

uint32_t* output = NULL;
output = malloc(sizeof(*output) * n);
if (!output) {
    fprintf(stderr, "Error: Could not allocate space for output array!\n");
    exit(EXIT_FAILURE);
}

填充您的数组。在不破坏字符串的情况下执行此操作的一种方法是保留几个指向子字符串的开头和结尾的指针,该子字符串包含逗号分隔字符串中的所需数字元素,并且只循环遍历字符串中的所有字符:

#define MAX_LEN 13
char* start = &input[0];
char* end = &input[0];
char entry[MAX_LEN];
uint32_t entry_idx = 0;
int finished = 0; // false
do {
    end = strchr(start, ',');
    if (!end) {
        end = input + strlen(input);
        finished = 1;
    }
    memcpy(entry, start, end - start);
    entry[end - start] = '[=12=]';
    sscanf(entry, "%u", &output[entry_idx++]);
    start = end + 1;
} while (!finished);

MAX_LEN 是 13,因为 uint32_t 不太可能超过 13 位数字。对于 2100 年制造的计算机,您可以延长它的时间以使其面向未来。

一定要在用完后释放数组:[​​=16=]

free(output); 
output = NULL;

这是一种方法:

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

typedef struct
{
    int* values;
    int  count;
}
output_t;

output_t Read(char input[])
{
    int*  values = NULL;
    int   count  = 0;
    char* pch    = strtok(input,", ");

    while (pch != NULL)
    {
        values = realloc(values,(count+1)*sizeof(*values));
        values[count++] = atoi(pch);
        pch = strtok(NULL,", ");
    }

    return (output_t){values,count};
}

这是一个用法示例:

void Example()
{
    char input[] = "1 , 2 , 34, 12, 46, 100";
    output_t output = Read(input);
    for (int i=0; i<output.count; i++)
        printf("%d\n",output.values[i]);
    free(output.values);
}

这是一个只进行一次传递的递归算法。它在最深层次分配,并在出路时填写:

int *cvt(char *input, int *level)
{
    char *cp = strtok(input, ", ");
    if (cp == NULL) {
        /* No more separators */
        return (int *) malloc(sizeof(int) * *level);
    }

    int my_index = -1;
    int n;
    if (sscanf(cp, "%d", &n) == 1) {
        my_index = *level;
        *level += 1;
    } else {
        printf("Invalid integer token '%s'\n", cp);
    }
    int *array = cvt(NULL, level);
    if (my_index >= 0) {
        array[my_index] = n;
    }
    return array;
}

通话方式:

int main(int ac, char **av)
{
    char input[] = "1, 2, bogus, 4, 8, 22, 33, 55";
    int n_array = 0;
    int *array = cvt(input, &n_array);

    int i;
    printf("Got %d members:\n", n_array);
    for (i = 0; i < n_array; ++i)
        printf("%d ", array[i]);
    printf("\n");

    return 0;
}

我会全力以赴,完成一次数据传递。我估计所需的数组大小是最坏的情况,其中每个数据都是 "n," 形式,所以每个数字两个字节,然后调整它的大小。

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

typedef unsigned int uint32_t;

int main (void) {
    char input[] = "1 , 2 , 34, 12, 46, 100";
    uint32_t *output, *temp;
    char *tok;
    int elements = 0;
    int len = 1 + strlen(input) / 2;            // estimate max num of elements
    output = malloc(len * sizeof(*output));
    if (output == NULL)
        exit(-1);                               // memory alloc error

    tok = strtok(input, ", ");                  // parse the string
    while (tok != NULL) {
        if (elements >= len)
            exit(-2);                           // error in length assumption
        if (1 != sscanf(tok, "%u", output + elements))
            exit(-3);                           // error in string format
        elements++;
        tok = strtok(NULL, ", ");
    }

    temp = realloc(output, elements * sizeof(*output)); // resize the array
    if (temp == NULL)
        exit(-4);                               // error in reallocating memory
    output = temp;

    for (len=0; len<elements; len++)
        printf("%u ", output[len]);
    printf("\n");
    free(output);
    return 0;
}

程序输出:

1 2 34 12 46 100
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>

int getsize(char* str, char* delimiters) //give the size of the final uint32_t array[]
{
  int count = 0;
  char* st = strdup(str), *t = strtok(st, delimiters);
  while(t)
  {
    count++;
    t = strtok(NULL, delimiters);
  }
  free(st);
  return count;
}

uint32_t* Char_to_Array(char *data, char* delimiters, int *siz) //siz is a pointer to get the size of the array
{
  char* st = strdup(data), *t = NULL; //dup string, strtok mage change on the passed string
  *siz = getsize(data, delimiters);
  uint32_t* buf=(uint32_t *)malloc((*siz)*4);
  t = strtok(st, delimiters); //split string by " "
  int i = 0;
  while(t)
  {
    buf[i] = atoi(t);
    t = strtok(NULL, delimiters);
    i++;
  }
  free(st);
  return buf;
}

这里是一个主要功能的测试

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

int main()
{
  int getsize(char* str, char* delimiters), siz = 0, i = 0;
  uint32_t* Char_to_Array(char *data, char* delimiters, int *x);
  uint32_t* t = Char_to_Array("123, 156, 4658,7878", " ,", &siz);
  while(i<siz)
  {
    printf("array[%d] = %d\n", i, t[i]);
    i++;
  }
  free(t);
  return 0;
}

2 遍方法:

1)统计逗号的个数,分配一个数组

2) 解析字符串 - 查找错误。

[迟到了 uint32 逗号派对]

#include <errno.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdint.h>
#include <inttypes.h>

typedef struct {
  uint32_t *u32;
  size_t count;
  bool error;
} CSV_32_T;

CSV_32_T CSV_to_int32_list(const char *csv) {
  CSV_32_T list = { NULL, 1, false };

  // 1st pass: Quickly go through list counting commas
  const char *p = csv;
  for (p = csv; *p; p++) {
    if (*p == ',') {
      list.count++;
    }
  }
  size_t i = 0;
  list.u32 = malloc(list.count * sizeof *list.u32);
  if (list.u32) {

    // 2nd pass: scan
    p = csv;
    for (i = 0; i < list.count; i++) {
      if (i > 0 && *p++ != ',') {
        break;
      }
      int n = 0;
      if (1 != sscanf(p, "%" SCNu32 " %n", &list.u32[i], &n)) {
        break;
      }
      p += n;
    }
  }
  if (i != list.count || *p) {
    free(list.u32);
    return (CSV_32_T ) { NULL, 0, true } ;
  }
  return list;
}

void testCSV(const char *csv) {
  CSV_32_T y = CSV_to_int32_list(csv);
  printf("%d %zu \"%s\"\n", y.error, y.count, csv);
}

int main(void) {
  testCSV("1 , 2 , 34, 12, 46, 100");
  testCSV("1  2 , 34, 12, 46, 100");
  return 0;
}