如何在嵌套的C结构中使用灵活的数组成员?

时间:2016-06-12 05:31:49

标签: c arrays struct c-strings

相关:flexible array member in a nested struct

我正在尝试将一些数据解析为结构。数据包含如下组织的信息:

struct unit {

    struct unit_A {
        // 28 bytes each

        // dependency r6scA 1
        char dr6scA1_tagclass[4];
        uint32_t dr6scA1_tagnamepointer;
        uint32_t dr6scA1_tagnamestringlength;
        uint32_t dr6scA1_tagid;

        // 12 bytes of 0x00

    }A;

    // A strings

    struct unit_B {
        // 48 bytes each

        // dependency r6scB 1
        char dr6scB1_tagclass[4];
        uint32_t dr6scB1_tagnamepointer;
        uint32_t dr6scB1_tagnamestringlength;
        uint32_t dr6scB1_tagid;

        // 32 bytes of 0x00

    }B;

    // B strings

    // unit strings

}unit_container;

你可以忽略这种奇怪的命名法。

我的评论// A strings// B strings// unit strings每个都包含以空字符结尾的C字符串,其数量与许多unit_Aunit_B重合,以及数据中的unit结构条目。因此,如果A中有unit_container的5个条目,那么在// A strings所在的位置会有5个C字符串。

由于我不能在这些位置使用灵活的数组成员,我应该如何解释数据中这些位置基本上未知数量的可变长度C字符串

例如,这些位置的数据可能是:

"第一个条目在这里。\ 0第二个条目\ 0另一个!\ 0第四个。\ 0这第五个条目是最合适的条目evah以任何合理的标准。\ 0"

...我希望我应该解释为:

char unit_A_strings[]

......但这是不可能的。我有什么选择?

感谢您的考虑。

编辑:

我认为到目前为止最吸引人的选择是:

char** unit_A_strings;指向一个char字符串数组。

如果我这样做: char unit_A_strings[1];定义一个固定大小为1 char的char数组,然后我必须放弃sizeof(unit)等,或者对内存分配大小很麻烦,即使它对于存在的数据类型最准确。如果我char * unit_A_strings[1];,则会出现同样的情况。

另一个问题:使用char *unit_A_strings;char** unit_A_strings;之间有什么区别?

结论:

主要问题是结构用于固定大小的信息,我需要的是可变大小的信息存储区域。因此,我无法合法地将数据存储到结构中 - 至少不是作为结构。这意味着任何其他解释都没有问题,在我看来char**是这种结构情况的最佳选择。

2 个答案:

答案 0 :(得分:0)

我认为它可以使用char **(或者你可以编写一些结构来包装它)。 例如,您可以编写帮助函数来解码流。

char** decodeMyStream(uint_8* stream, unsigned int* numberOfCString)
{
    *numberOfCString = decodeNumberOfCString(stream);
    char** cstrings = malloc((*numberOfCString) * sizeof(char*));
    unsigned int start = 0;
    for (unsigned int i = 0; i < *numberOfCString; ++i)
    {
        usigned int len = calculateIthStringLength(stream, start)
        cstrings[i] = malloc((len) * sizeof(char));
        memcpy(cstrings[i], stream + start, len); 
        start += len
    }
    return cstrings;
}

它只是没有思考示例代码,你可以想出更好的算法。

答案 1 :(得分:0)

我认为你最接近的是提供一系列字符串:

    import java.applet.*;
import java.awt.*;

public class Breakout extends Applet implements Runnable{
    Thread thread = new Thread(this);
    boolean running = true;
    //Brick b;
    Brick2 b2;
    Paddle p;
    Ball ba;
    Image dbImage;
    Graphics dbg;
   public void init(){
        setSize(800,600);
        //b = new Brick(this);
        b2 = new Brick2(0,0);
        p = new Paddle(this);
        ba = new Ball(this);

    }
    public void start(){
        thread.start();
    }
    public void destroy(){
        running = false;
    }
    public void stop(){
        running = false;
    }
    public void run(){
        while(running){
            //b.update(this,ba);

            b2.update(ba);
            p.update(this);
            ba.update(this,p);
            repaint();
            try{
                thread.sleep(20);
            }
            catch (InterruptedException e){
                System.out.println("AN ERROR HAS OCCURED");
            }
        }
    }
    public void update(Graphics g, Brick2 b){
        dbImage = createImage(getWidth(),getHeight());
        dbg = dbImage.getGraphics();
        paint(dbg);
        g.drawImage(dbImage,0,0,this);

                }
    public void paint(Graphics g){
        g.fillRect(0,0,800,600);
        //b.paint(g,this);
        b2.paint(g);
        p.paint(g,this);
        ba.paint(g,this);

    }   
}

注意两件事:

  1. char *AStrings[] = { "The first entry is here.", "Second entry", "Another!", "Fourth.", "This 5th entry is the bestest entry evah by any reasonable standards.", NULL }; 是一个指向字符串的指针数组 - 它将是6个(见下面的2.)指向实际字符串的连续指针,而不是&#39;复合&#39;您在示例中使用的字符串。
  2. 我用AStrings指针结束AStrings,以解决&#34;我何时完成?&#34;问题。
  3. 所以你可以&#34;掉线&#34; NULL并开始将位置视为指针 - 但要小心!编译器可以在一个变量和下一个变量之间放入各种填充,弄清楚它们在内存中相对于彼此的位置 - 包括重新排序它们!

    修改 哦!我只是想了一下。另一个可能有用的数据表示基本上就是你所做的。我已经'漂亮了'&#39;它有点:

    A
    • C编译器会自动连接两个相邻的&#39;字符串好像它们是一个字符串 - 它们之间有没有 char AString[] = "The first entry is here.\0" "Second entry\0" "Another!\0" "Fourth.\0" "This 5th entry is the bestest entry evah by any reasonable standards.\0"; 字符。我把它们专门放在上面。
    • C编译器会自动将NUL放在任何字符串的末尾 - 在上例中的分号('\0')处。这意味着字符串实际上以两个NUL字符结尾,而不是一个。

    您可以使用该事实来跟踪解析字符串&#39;数组的位置。 - 假设每个所需的值都有一个超过零长度的(子)字符串!一旦遇到零长度(子)字符串,您就知道您已经到达字符串&#39;数组的末尾。

    我将这些字符串称为ASCIIZZ字符串(ASCIIZ字符串,并在所有字符串的末尾添加第二个NUL)。