C:制作,传递和访问指向const字符串的const数组

时间:2014-01-29 11:30:07

标签: c arrays string pointers

出于某种原因,这不起作用:

const char * str_reset_command = "\r\nReset";
const char * str_config_command = "\r\nConfig";

const char *commands[2] = {
    &str_reset_command,
    &str_config_command
};

这是对的吗? (其他地方的代码是否必然导致问题?)

(我在基线8位微控制器上运行它并且具有非常有限的调试功能)

澄清:

这就是我想要实现的目标:

const char * str_reset_command = "\r\nReset";
const char * str_config_command = "\r\nConfig";
const char * str_start_command = "\r\nStart";
const char * str_end_command = "\r\nEnd";

const char * const group0[1] = {
    str_reset_command
}
const char * const group1[2] = {
    str_reset_command,
    str_start_command
}
const char * const group2[3] = {
    str_reset_command,
    str_start_command,
    str_end_command
}
void doStuffToCharacter(unsigned char the_char){
    // ....
}
void doStuffToGroup(char ** group, unsigned char num_strings){
    for (unsigned char s=0; s < num_strings; s++){
        unsigned char idx = 0;
        while (group[s][idx]){
            doStuffToCharacter(group[s][idx]);
        }
    }
}
void main (void){
    doStuff(group0, 1);
    doStuff(group1, 2);
    doStuff(group2, 3);
}

除了更正之外,我们还欢迎任何更简洁的建议。

需要将命令字符串的各种组合发送到函数进行处理。所有字符串都将在ROM中,指向它们的指针组也是如此。

7 个答案:

答案 0 :(得分:4)

您创建了一个指针数组,但是您传递的是指针的地址(意思是指向指针的指针)。你应该做的是这个 -

    const char* commands[2]= {str_reset_command, str_config_command};

答案 1 :(得分:3)

不直接回答你的问题,但为什么不试试这个:

typedef enum {
    RESET_CMD,
    CONFIG_CND
} cmd_id;

const char *commands[2] = {
    "\r\nReset",
    "\r\nConfig"
};

而不是像这样使用它:

commands[RESET_CMD]

修改

我会重写您的澄清以匹配此方法:

typedef enum {
    RESET_CMD,
    CONFIG_CND,
    START_CMD,
    END_CMD
} cmd_id;

const char *commands[4] = {
    "\r\nReset",
    "\r\nConfig",
    "\r\nStart",
    "\r\nEnd"
};

const cmd_id group0[1] = {
    RESET_CMD
};

const cmd_id group1[2] = {
    RESET_CMD,
    START_CMD
};

const cmd_id group2[3] = {
    RESET_CMD,
    START_CMD,
    END_CMD
};

void doStuffToCharacter(unsigned char the_char){
    // ....
}

void doStuffToGroup(const cmd_id group[], unsigned char num_cmds){
    for (unsigned char s=0; s < num_cmds; s++) {
        unsigned char idx = 0;
        while (commands[group[s]][idx]) {
            doStuffToCharacter(commands[group[s]][idx++]);
        }
    }
}

void main (void){
    doStuff(group0, 1);
    doStuff(group1, 2);
    doStuff(group2, 3);
}

答案 2 :(得分:2)

你有一个const char指针数组,你试图在其中存储指向const char指针的指针。删除&运算符,它应该可以正常工作。

答案 3 :(得分:1)

如果在函数外部声明了变量,则初始值设定项必须是常量。在这种情况下,Const不计算在内。您将创建一个指向指针的数组,然后使用char *变量的地址。

const char * str_reset_command = "\r\nReset";
const char * str_config_command = "\r\nConfig";

const char **commands[2] = {
    &str_reset_command,
    &str_config_command
};

使用数组时不要忘记取消引用指针。

const char* string = *commands[1] ; //actually it is *(commands[1]) but the  [] operator has higher precedence anyway

答案 4 :(得分:1)

试试这个。这不是你想要的,但它完成了这项工作。

#define RESET_COMMAND             "Reset"
#define CONFIG_COMMAND            "Config"  

const char *commands[2] = {  
    RESET_COMMAND,  
    CONFIG_COMMAND,  
};  

int  
main() {  
   ...  
}

答案 5 :(得分:1)

您正在使用全局变量。你真的确定你需要这种方法吗?

按照原样遵循您的代码,您将str_reset_command定义为const char *。这意味着它是一个指向char的指针,它也具有限定符const。你不必将“const”与const混淆。 :)
编译器将每个表达式构建的“const”视为涉及文字的表达式 另一方面,const限定符意味着您正在定义一个“变量”,其值不能被修改,除非在其定义的那一刻。

表达式"\r\nReset"是一个“const”,因为它是一个字符串文字 但是const char * str_reset_command不是“const”,而是一个无法修改的变量。

不同之处在于文字是编译器的“常量”,因为它可以在编译时计算它们的值。但是,const对象作为变量保存,因为其值可以在执行时间中确定。例如,考虑const中几个函数的<string.h>参数。

您的变量group0被定义为指向char数组的指针 由于它被定义为全局变量,因此其初始化程序必须是“const”(在编译时间意义上)值。但是你提供了str_reset_command,它不是文字(或只涉及文字的表达)。因此,其值不能在编译时确定,也不能用作初始化。

也许您可以尝试编写初始化函数:

 const char * str_reset_command = "\r\nReset";
 const char * str_config_command = "\r\nConfig";
 const char * str_start_command = "\r\nStart";
 const char * str_end_command = "\r\nEnd";

 char * group0[1];
 char * group1[2];
 char * group2[3];

 void initGroups(void) {
      group2[0] = group1[0] = group0[0] = str_reset_command;
      group2[1] = group1[1] = str_start_command;
      group2[2] = str_end_command;
 }

 int main(void) {
    initGroups();

    // Do stuff...
 }

我删除了const限定符,因为现在我们需要修改指针。

无论如何,使用全局变量会产生一些副作用 如果可能,尝试修改此方面。


修改

第二次尝试

我在你的计划中思考,我完全改变了你的方法 首先,我不明白你为什么要使用所有那些“group []”数组 由于您希望优化内存资源,因此这不是最佳选择 另一方面,你的“常量字符串”似乎只有少数 通过假设它们不超过8,给定组中涉及的字符串的信息可以保持为1个字节 我的意思是,您可以通过一个字节的位来定义“组”或“集合”,因此如果给定的成员属于该集合,则将位1(打开),以及0。

此外,由于您接受使用指向常量字符的指针数组,我认为所有字符串都可以在代码开始时保存在常量字符数组中。这可以通过const声明保存在ROM中。

您使用的名称为str_reset,str_start等 您似乎需要自己清楚地了解这些信息 这些信息可以通过编译器常量和/或枚举保存在代码中,编译器常量和/或枚举在编译程序中没有任何成本。

我设计了一个使用位屏蔽的代码 这样您最多可以使用8个字符串 由于位掩码是2的幂,因此不能用作数组索引 但是,可以用一种非常结果的方式定义一个名称与位掩码常数“并行”的枚举常量列表。
特别是,您将能够或更改枚举的顺序,但您的代码将继续工作。

为了完成图片,我使用了C99 / C11标准的功能(您似乎使用了,因为您声明for语句的方式),这允许我们初始化数组的独立成员通过写出所需的索引 由于索引现在将具有枚举给出的名称,因此您可以信任此技术,而无需关注已使用的实际索引。

我使用<stdio.h>printf()来测试该程序。你可以删除这些行。

#include <stdio.h>

#define bit0 0x01u  /* Binary 0000 0001 */
#define bit1 0x02u  /* Binary 0000 0010 */
#define bit2 0x04u  /* Binary 0000 0100 */
#define bit3 0x08u  /* Binary 0000 1000 */
#define bit4 0x10u  /* Binary 0001 0000 */
#define bit5 0x20u  /* Binary 0010 0000 */
#define bit6 0x40u  /* Binary 0100 0000 */
#define bit7 0x80u  /* Binary 1000 0000 */

enum {reset_command = 0, config_command, start_command, end_command};

#define bit_reset  (1u << reset_command)    /*  Equal to bit0 */
#define bit_config (1u << config_command)   /*  Equal to bit1 */
#define bit_start  (1u << start_command)    /*  Equal to bit2 */
#define bit_end    (1u << end_command)      /*  Equal to bit3 */

const char * const str[] = {
         [reset_command]  = "\r\nReset",
         [config_command] = "\r\nConfig",
         [start_command]  = "\r\nStart",
         [end_command]    = "\r\nEnd"
    };

const unsigned char bitgroup0 = bit_reset;
const unsigned char bitgroup1 = bit_reset | bit_start;
const unsigned char bitgroup2 = bit_reset | bit_start | bit_end;

void doStuffToCharacter(unsigned char the_char){
    printf("%c", the_char);
}

void doStuff(const char * const * str, unsigned char bitgroup){
    printf("\n\nGroup: %hu\n", bitgroup);

    for (unsigned char b=bitgroup, j=0; b; b >>= 1u, j++){
        if (b & 1u)  {
           for(unsigned char idx = 0; str[j][idx]; idx++) {
                 doStuffToCharacter(str[j][idx]);
           }
        }
    }
}
int main (void){
    doStuff(str, bitgroup0);
    doStuff(str, bitgroup1);
    doStuff(str, bitgroup2);
}

如您所见,每个“组”现在只需要1个字节。 (您的方法至少使用了1,2和3个字节) for()语句中的迭代次数不超过groupbit参数中的最大位“on”。

const char指针中保存const对象的要求也已满足。

数组的大小由编译器自动确定,以保存最大索引。

for()循环遍历一个“byte”,初始化为您作为参数传递的“group”。
最后一位针对1进行测试 如果该位为1,则执行一些操作 否则,这将被跳过进入下一次迭代 通过赋值b >>= 1u删除最后一位。

每次迭代,我们都需要离开数组j的索引str
因此,当且仅当j - 字符串被处理时,j - 位为1 接下来,重复每一次,直到b没有更多位1

如果使用位1都是连续的“组”,则程序的工作方式与您在示例中的预期方式相同。

现在您可以选择所需的操作,只需切换相应的位即可。

答案 6 :(得分:1)

您的数组声明与使用它的函数的原型不一致:

const char *commands[2] = {  // <- declared as array of 2 pointers to char
doStuffToGroup(char ** group // <- used as pointer to pointer to char

这是一个常见的C / C ++缺陷(尽管用作香草数组的重新设计的矢量在C ++中的使用率却远不如此)。

有关更详细的说明,请参阅this answer