[英]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.