繁体   English   中英

通过 C function 返回结构的结构

[英]Returning struct of struct by a C function

我尝试创建一个简单的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;
}

但是,output 不是我的目标:

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

如评论中所述,在使用具有灵活数组成员的结构时,您必须使用动态分配。 结构体的大小不包括数组大小,调用malloc()时必须加上数组的大小。

这意味着您不能拥有TOKENS数组,因此您需要OUTPUT.a作为指针数组。 使用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 在某些情况下可能有用,但可以在此处使用旧的可靠malloc() (及其用户strdup() ,如果可用)。

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

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

或者,下面是另一种选择,其中调用者将“顶级”结构的地址传递给 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