如何定义任意大小的2D数组,然后在编译时确定其尺寸?

时间:2010-10-01 21:47:25

标签: c arrays multidimensional-array

执行摘要:

  1. 如何在C中定义任意大小的2D数组?
  2. 如何在编译时确定该数组的维度?
  3. 完全披露:

    我正在为嵌入式控制器编写代码。我的应用程序需要几个不同大小的查找表,这些查找表将由一个查找函数(二进制搜索)使用。以下是我到目前为止的情况:

    typedef struct
    {
        unsigned char count;        // number of rows in the table
        unsigned char width;        // number of bytes in each row
        const unsigned char * data; // pointer to table data[count][width]
    }
    LookupTable;
    
    // returns the index of a value from within a table
    unsigned char Lookup(unsigned long value, const LookupTable * table);
    

    这部分正在运作。我现在想做的是在我的源代码中定义这些表,而不必手动输入countwidth常量。这就是我现在正在做的事情:

    #define T1_count 100
    #define T1_width 3
    const unsigned char table1_data[T1_count][T1_width] = 
    {
        { 0x12, 0x34, 0x56 },
        { 0x12, 0x38, 0x12 },
        ...
    };
    
    const LookupTable table1 = { T1_count, T1_width, table1_data };
    

    以下是我喜欢能够做的事情(伪代码,因为这个数组定义实际上不会编译):

    const unsigned char table1_data[] = 
    {
        { 0x12, 0x34, 0x56 },
        { 0x12, 0x38, 0x12 },
        ...
    };
    
    const LookupTable table1 =
    {
        get_count_expr(table1_data),
        get_width_expr(table1_data),
        table1_data
    };
    

    显然,get_count_exprget_width_expr必须是某种类型的常量表达式,基于表的大小,而不是实际的函数调用。

    要明确的是,这种设计的任何部分都不是一成不变的。我只是发布了迄今为止的内容,希望我的意图很明确。任何改进的想法都将受到赞赏。

    “为什么”:

    这些表会经常更改,如果可以添加和删除条目,或者更改表的宽度而不必每次都手动调整常量,这将使维护更容易。必须手动跟踪大小可能容易出错并违反DRY。我正在寻找更好的方法。

4 个答案:

答案 0 :(得分:3)

嗯......你可以把最左边的大小留给编译器:

#define T1_WIDTH 3
const unsigned char table1_data[][T1_WIDTH] = 
{
    { 0x12, 0x34, 0x56 },
    { 0x12, 0x38, 0x12 },
    /* ... */
};
T1_count = sizeof table1_data / sizeof *table1_data;
T1_width = sizeof *table1_data;

答案 1 :(得分:2)

嗯,这很丑陋,但我认为在你列出的约束中做到这一点的唯一方法是将数据包含在字符串中,而不是让初始化代码解析字符串并生成表格。理想情况下,你会在脚本中执行此操作,而不是使用C来执行此操作,但如果必须使用C,则必须使用C ..

请注意,我绝不会声称以下内容是生产代码,但这仅仅是一个概念验证......

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

#define datatable  "\
    { 0x12, 0x34, 0x56 },\
    { 0x14, 0x36, 0x10 },\
    { 0x13, 0x37, 0x11 },\
    { 0x12, 0x38, 0x12 }"

typedef struct
{
    unsigned char count;        // number of rows in the table
    unsigned char width;        // number of bytes in each row
    unsigned char **data; // pointer to table data[count][width]
}
LookupTable;

int parsedatatable(char *data, LookupTable **table) {
    char *p, *sp, save;
    unsigned char *tabledata;
    int count = 0, width = 0;
    unsigned int tmp;
    int i,j;

    /* find count */
    p = strstr(data,"{");
    while (p) {
        p++;
        p = strstr(p, "{");
        count++;
    }
    /* find width */
    p = strstr(data, "{");
    p++;
    sp = strstr(p, "}");
    if (sp != NULL) {
        save = *sp;
        *sp = '\0';
    }
    while (p) {
        p = strstr(p, ",");
        width++;
        if (p != NULL) p++;
    }
    if (sp != NULL) {
        *sp = save;
    }

    printf("Count = %d, width = %d\n",count, width);
    tabledata = (unsigned char *)malloc(width*count*sizeof(unsigned char));
    *table = (LookupTable *)malloc(sizeof(LookupTable));
    (*table)->data = (unsigned char **)malloc(count*sizeof(unsigned char*));
    for (i=0; i<count; i++) {
        (*table)->data[i] = &(tabledata[i*width]);
    }
    (*table)->count = count;
    (*table)->width = width;

   p = data;
    for (i=0; i<count; i++) {
        p = strstr(p,"{");
        if (!p) {
            fprintf(stderr,"Fail (a) reading in data!: %s\n",data);
            free((*table)->data);
            free(tabledata);
            free(*table);
            return -1;
        }
        p++;
        for (j=0; j<width; j++) {
            printf("Scanning <%s>, ",p);
            sscanf(p,"%x",&tmp);
            printf("got %d\n",tmp);
            (*table)->data[i][j] = tmp;
            p = strstr(p,",");
            if (!p && j<width-1) {
                fprintf(stderr,"Fail (b) reading in data!: %d, %d, %s\n",i,j,data);
                free((*table)->data);
                free(tabledata);
                free(*table);
                return -1;
            }
            p++;
        }
    } 
    return 0;
}

void printtable(LookupTable *table) {
    unsigned char i,j;
    for (i=0; i<table->count; i++) {
        printf("{");
        for (j=0; j<table->width; j++) {
            printf("%x ",table->data[i][j]);
        }
        printf("}\n");
    } 
    return;
}

int main(int argc, char **argv) {
    char *data; 
    LookupTable *table;

    data = (char *)malloc(strlen(datatable)+1);
    strcpy(data,datatable);

    parsedatatable(data,&table);
    printtable(table);

    return 0;
}

答案 2 :(得分:1)

嗯,但谁用数据填充这些表?我认为生成的资源是更好的解决方案。

答案 3 :(得分:0)

在标题内定义table1_data。您可以使用脚本自动生成该标头。我为我的一些项目做了类似的事情。我有一个包含数据的CSV文件和一个从中生成标题的Ruby或Python脚本。