简体   繁体   English

通过 C function 返回结构的结构

[英]Returning struct of struct by a C function

I tried to create a simple split function to return elements as a struct, and used another struct to return the results and the number of elements.我尝试创建一个简单的split function 以将元素作为结构返回,并使用另一个结构来返回结果和元素的数量。

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

struct TOKENS
{
  int length;
  char word[];
};

struct OUTPUT
{
  struct TOKENS *a;
  int l;
};

struct OUTPUT explode(char *a, char *b)
{
  struct TOKENS tokens[10];
  int i = 0;
  char *ptr = strtok(a, b);
  while (ptr != NULL)
  {
    tokens[i].length = strlen(ptr);
    strcpy(tokens[i].word, ptr);
    ptr = strtok(NULL, b);
    i++;
  }
  struct OUTPUT r = {
      .a = &tokens[0], .l = i};
  return r;
}

int main()
{
  char str[] = "This is test for the start";
  struct OUTPUT r = explode(str, " ");
  struct TOKENS *tokens = r.a;
  printf("%d\n", r.l);
  for (int i = 0; i < r.l; i++)
  {
    printf("%d %s (%d)\n", i, tokens[i].word, tokens[i].length);
  }

  return 0;
}

However, the output is not what I aimed for:但是,output 不是我的目标:

6
0  (4)
1  (2)
2  (4)
3  (3)
4  (3)
5 start (5)

As mentioned in the comments, you have to use dynamic allocation when using a structure with a flexible array member.如评论中所述,在使用具有灵活数组成员的结构时,您必须使用动态分配。 The size of the structure doesn't include the array size, you have to add the size of the array when calling malloc() .结构体的大小不包括数组大小,调用malloc()时必须加上数组的大小。

This means you can't have an array of TOKENS , so you need OUTPUT.a to be an array of pointers.这意味着您不能拥有TOKENS数组,因此您需要OUTPUT.a作为指针数组。 Use malloc() and realloc() to allocate the memory for r.a , and use malloc() to allocate the memory for each TOKENS element.使用malloc()realloc()为 r.a 分配r.a ,并使用malloc()为每个TOKENS元素分配 memory。

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

struct TOKENS
{
    int length;
    char word[];
};

struct OUTPUT
{
    struct TOKENS **a;
    int l;
};

struct OUTPUT explode(char *a, char *b)
{
    struct OUTPUT r = {.a = NULL, .l = 0};
    int i = 0;
    char *ptr = strtok(a, b);
    while (ptr != NULL)
    {
        r.l++;
        r.a = realloc(r.a, r.l * sizeof(*r.a));
        struct TOKENS *token = malloc(sizeof(*token)  + strlen(ptr) + 1);
        token->length = strlen(ptr);
        strcpy(token->word, ptr);
        r.a[i] = token;
        ptr = strtok(NULL, b);
        i++;
    }
    return r;
}

int main()
{
    char str[] = "This is test for the start";
    struct OUTPUT r = explode(str, " ");
    struct TOKENS **tokens = r.a;
    printf("%d\n", r.l);
    for (int i = 0; i < r.l; i++)
    {
        printf("%d %s (%d)\n", i, tokens[i]->word, tokens[i]->length);
    }
    for (int i = 0; i < r.l; i++) {
        free(tokens[i]);
    }
    free(tokens);

    return 0;
}

FAM's may be useful in some instances, but the old reliable malloc() (and its user strdup() , if available) can be used here. FAM 在某些情况下可能有用,但可以在此处使用旧的可靠malloc() (及其用户strdup() ,如果可用)。

realloc() is used to start and to grow array of ptrs to individual 'token' structs realloc()用于启动和将 ptrs 数组增长为单个“令牌”结构

#include <stdio.h>
#include <stdlib.h> // for `exit()`
#include <string.h>

typedef struct TOKENS {
    int length;
    char *word; // NB: pointer, not FAM
} TOKENS_t;

typedef struct {
    TOKENS_t *a;
    int l;
} OUTPUT_t;

#define USE_SRC_STR
// or not defined in order to use dynamic allocation of "word" copies

// return ptr to struct instead of entire struct
OUTPUT_t *explode( char *a, char *b ) {
    OUTPUT_t *r = calloc( 1, sizeof *r ); // initially all bytes = 0
    // test for NULL return omitted for brevity

    // only one invocation of strtok()
    for( char *ptr = a; (ptr = strtok( ptr, b )) != NULL; ptr = NULL ) {

        // cautiously growing array of pointers
        TOKENS_t *tmp = realloc( r->a, (r->l + 1) * sizeof *tmp );
        if( tmp == NULL ) {
            fprintf( stderr, "realloc failed on %d\n", r->l + 1 );
            exit( EXIT_FAILURE );
        }
        // preserve "word"
#ifdef USE_SRC_STR
        tmp[ r->l ].word = ptr;
#else
        tmp[ r->l ].word = strdup( ptr );
#endif
        tmp[ r->l ].length = strlen( ptr ); // preserve length of "word"
        r->a = tmp; // realloc() may have relocated extended array
        r->l++; // got one more
    }

    return r;
}

int main() {
    char str[] = "This is test for the start";

    OUTPUT_t *r = explode( str, " " ); // capture returned pointer

    printf( "%d\n", r->l );
    for( int i = 0; i < r->l; i++ )
        printf( "%d: %s (%d)\n", i, r->a[i].word, r->a[i].length );

#ifndef USE_SRC_STR
    // free those buffers containing copies of "word"s
    while( (r->l)-- )
        free( r->a[ r->l ].word );
#endif

    free( r ); // free this, too!

    return 0;
}

Output Output

6
0: This (4)
1: is (2)
2: test (4)
3: for (3)
4: the (3)
5: start (5)

Or, below is another alternative where the caller passes the address of a 'top level' struct to the function (that now just does its job and returns nothing.)或者,下面是另一种选择,其中调用者将“顶级”结构的地址传递给 function (现在只是完成它的工作并且什么都不返回。)

void explode( OUTPUT_t *r, char *a, char *b ) {
    for( char *ptr = a; (ptr = strtok( ptr, b )) != NULL; ptr = NULL ) {
        TOKENS_t *tmp = (TOKENS_t *)realloc( r->a, (r->l + 1) * sizeof *tmp );
        if( tmp == NULL ) {
            fprintf( stderr, "realloc failed on %d\n", r->l + 1 );
            exit( EXIT_FAILURE );
        }
        tmp[ r->l ].word = ptr; // using original string
        tmp[ r->l ].length = strlen( ptr );
        r->a = tmp;
        r->l++;
    }
}

int main() {
    char str[] = "This is test for the start";

    OUTPUT_t r = { 0 }; // define initialised top level instance
    explode( &r, str, " " ); // pass into "helper" function

    printf( "%d\n", r.l );
    for( int i = 0; i < r.l; i++ )
        printf( "%d: %s (%d)\n", i, r.a[i].word, r.a[i].length );

    free( r.a ); // don't forget to "clean up"

    return 0;
}

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

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