【问题标题】:Store multidimensional array in struct在结构中存储多维数组
【发布时间】:2016-11-16 17:13:37
【问题描述】:

我有一个二维数组,其中第一个维度的长度是可变的,但第二个维度是固定的。现在在函数调用中,我可以执行类似char foo[][3] 的操作,但struct 中的相应定义是什么?

所以在示例代码中,我希望它打印一行中的每个字符串,但正如预期的那样,它将存储的指针视为一维数组。

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

struct payload_s {
    size_t length;
    char *text;
};

typedef struct payload_s payload;

static char some_text[4][3] = {"Ab", "Cd", "Ef", "Gh"};

payload* create_payload(char *text, size_t length)
{
    payload *p = malloc(sizeof *p);
    p->text = text;
    p->length = length;
    return p;
}

int main()
{
    payload *p = create_payload(some_text, 4);
    for (size_t i = 0; i < p->length; ++i)
        printf("%zu: %s\n", i, &p->text[i]);
}

我主要是因为一个警告才注意到这一点的:

strut.c: In function ‘main’:
strut.c:23:33: warning: passing argument 1 of ‘create_payload’ from incompatible pointer type [-Wincompatible-pointer-types]
     payload *p = create_payload(some_text, 4);
                                 ^~~~~~~~~
strut.c:13:10: note: expected ‘char *’ but argument is of type ‘char (*)[3]’
 payload* create_payload(char *text, size_t length)
          ^~~~~~~~~~~~~~

当函数实际上被定义为payload* create_payload(char text[][3], size_t length) 时,我可以摆脱这个警告,但是几行之后有一个警告并且行为没有改变:

strut.c: In function ‘create_payload’:
strut.c:16:13: warning: assignment from incompatible pointer type [-Wincompatible-pointer-types]
     p->text = text;
             ^

是否只有手动将指针增加每个值的长度的解决方案?

【问题讨论】:

  • 您有概念问题:您无法四个 char 数组(此处为{"Ab\0", "Cd\0", "Ef\0", "Gh\0"};)下存储一个char-pointer(此处为char *text;),至少不是以理智的方式。编译器警告提示了这个问题。
  • 这基本上就是我要问的:我还能如何将它们存储在结构中?
  • OT: "Ab\0" 在内部表示为 {'A', 'b', '\0', '\0'},因此您可能不想明确放置 '\0'
  • 将成员 char * text 也更改为 char (*)[3]:设为 char (*text)[3]
  • 在调用任何堆内存分配函数时:(malloc, calloc, realloc),始终检查 (!=NULL) 返回值以确保操作成功

标签: c string pointers multidimensional-array struct


【解决方案1】:

用途:

char (*text)[3];

代替:

char *

因为您需要的是指向二维数组的指针,而不是指向单个 char 的指针。在C pointer to two dimensional array 中阅读更多信息。

当然,建议对您的维度使用定义或类似的东西,而不是像我的示例中那样硬编码的 3。


最小。示例:

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

#define M 3

struct payload_s {
    size_t length;
    char (*text)[M]; // change the member!
};

typedef struct payload_s payload;

// not need for null terminators in the strings,
// it will be placed automatically
static char some_text[4][M] = {"Ab", "Cd", "Ef", "Gh"};

// change the prototype as well
payload* create_payload(char (*text)[M], size_t length)
{
    payload *p = malloc(sizeof *p);
    p->text = text;
    p->length = length;
    return p;
}

int main()
{
    payload *p = create_payload(some_text, 4);
    for (size_t i = 0; i < p->length; ++i)
        // no need to print the address now
        // also 'zu' should be used for 'size_t'
        printf("%zu: %s\n", i, p->text[i]);
}

输出:

Georgioss-MacBook-Pro:~ gsamaras$ gcc -Wall main.c 
Georgioss-MacBook-Pro:~ gsamaras$ ./a.out 
0: Ab
1: Cd
2: Ef
3: Gh

PS - 检查 malloc() 返回的内容,查看内存是否实际分配(当然是在真实代码上,而不是在最小的 egs 中)。

【讨论】:

  • 我几乎明白了,但括号放错了(使用*(text[3]))。感谢额外的 cmets,尽管这段代码只是为了提取我遇到的问题。
  • 我知道@xZise,这就是我最后一句话的原因!我必须自己查一下,这就是为什么我在写这个答案之前把我检查过的答案链接给你! :) 好问题,非常令人耳目一新!
【解决方案2】:

这一行:

static char some_text[4][3] = {"Ab\0", "Cd\0", "Ef\0", "Gh\0"};

正在尝试使用每个条目中 4 个字节的值初始化每个条目中 3 个字节的数组。

注意:“AB\0”是 4 个字节,因为声明一个 char 数组总是在数组末尾附加一个 NUL 字节。

建议:

static char some_text[4][3] = {"Ab", "Cd", "Ef", "Gh"};

printf() 的调用包含几个错误,您的编译器应该告诉您这些错误。

字段:char *text;实际上是指向一个二维数组,所以应该相应地声明。

需要对malloc()的调用进行错误检查。

这是代码的一个版本,将应用所有(合理的)更正。

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

struct payload_s 
{
    size_t length;
    char **text;
};


static char *some_text[] = {"Ab", "Cd", "Ef", "Gh"};

struct payload_s* create_payload(char **text, size_t length)
{
    payload *p = malloc(sizeof (struct payload_s));
    if( !p )
    {
        perror( "malloc for instance of payload failed" );
        exit( EXIT_FAILURE );
    }

    // implied else, malloc successful

    p->text = text;
    p->length = length;
    return p;
}

int main( void )
{
    //payload *p = create_payload(some_text, 4);
    payload *p = create_payload(some_text, sizeof(some_text) / sizeof( *some_text ) );
    for (size_t i = 0; i < p->length; ++i)
        printf("%lu: %s\n", i, p->text[i]);
}

以上代码的结果是:

0: Ab
1: Cd
2: Ef
3: Gh

【讨论】:

    【解决方案3】:

    您正在使用无法相互隐式转换的不兼容指针。

    字符数组some_text 声明为

    static char some_text[4][3] = {"Ab\0", "Cd\0", "Ef\0", "Gh\0"};
    

    当它在表达式中使用时,例如用作参数时,它被隐式转换为指向其第一个元素的指针,并且类型为char ( * )[3]。它与char * 类型的指针不同。

    看起来您需要一个具有灵活数组的结构。

    这是一个演示程序,展示了如何使用这种结构。

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define N   3
    
    struct payload_s 
    {
        size_t length;
        char text[][N];
    };
    
    struct payload_s * create_payload( char( *text )[N], size_t length )
    {
        struct payload_s *p = malloc( sizeof( struct payload_s ) + 
                                      length * sizeof( char[N] ) );
    
        p->length = length;
    
        for ( size_t i = 0; i < length; i++ ) strcpy( p->text[i], text[i] );
    
        return p;
    }
    
    void free_payload( struct payload_s *p )
    {
        free( p );
    }
    
    int main(void) 
    {
        char some_text[4][N] = {"Ab", "Cd", "Ef", "Gh"};
        char another_text[5][N] = {"Bb", "Dd", "Ff", "Hh", "Jj"};
    
        struct payload_s *p1 = create_payload( some_text, 
            sizeof( some_text ) / sizeof( *some_text ) );
    
        struct payload_s *p2 = create_payload( another_text, 
            sizeof( another_text ) / sizeof( *another_text ) );
    
        for ( size_t i = 0; i < p1->length; i++ )
        {
            printf( "%s ", p1->text[i] );
        }
        printf( "\n" );
    
        for ( size_t i = 0; i < p2->length; i++ )
        {
            printf( "%s ", p2->text[i] );
        }
        printf( "\n" );
    
        free_payload( p2 );
        free_payload( p1 );
    
        return 0;
    }
    

    它的输出是

    Ab Cd Ef Gh 
    Bb Dd Ff Hh Jj 
    

    【讨论】:

      猜你喜欢
      • 2014-12-14
      • 2012-06-02
      • 2015-08-02
      • 1970-01-01
      • 1970-01-01
      • 2011-07-04
      • 2011-06-10
      • 2019-08-08
      • 2010-10-14
      相关资源
      最近更新 更多