使用 String** 指针访问 String 数组元素的问题

Problems in using String** pointer for access elemnts of String array

这是一个在MCU中使用字体的程序。我有4个文件。 'zar.h' 和 'zar.cpp' 包含一种字体的数据。 'font.h' 和 'font.cpp' 包含动态设置字体的指针和函数。指针有很多问题。当访问“XB_Zar_name”数组元素时,通过“uni_name[i]”指针,MCU dos reset's。另一个问题是计算“XB_Zar_name”字符串数组中的字符串。修复这些错误后肯定会出现其他错误。请帮助我。

zar.h

/*v*/extern const unsigned char XB_Zar_118[];
/*w*/extern const unsigned char XB_Zar_119[];
/*x*/extern const unsigned char XB_Zar_120[];
/*y*/extern const unsigned char XB_Zar_121[];
/*z*/extern const unsigned char XB_Zar_122[];
extern  char XB_Zar_width[];
extern const unsigned char* XB_Zar_addr[];
extern String XB_Zar_name[];

zar.cpp

/*v*/ const unsigned char XB_Zar_118[] PROGMEM ={255,255,254,255,63,255};
/*w*/ const unsigned char XB_Zar_119[] PROGMEM ={255,127,255,254,255,5};
/*x*/ const unsigned char XB_Zar_120[] PROGMEM ={215,215,23,254,255,127};
/*y*/ const unsigned char XB_Zar_121[] PROGMEM ={255,127,25,254,255,9};
/*z*/ const unsigned char XB_Zar_122[] PROGMEM ={255,243,239,254,215,19};
char XB_Zar_width[]= {2,2,2,2,2};
const unsigned char* XB_Zar_addr[] = {XB_Zar_118,XB_Zar_119,XB_Zar_120,XB_Zar_121,XB_Zar_122};
String XB_Zar_name[] = {"۰","۱","۲","۳","۴","۵"};

font.h

#pragma once
#include "zar.h"
extern unsigned char *char_addr;
extern unsigned int *char_width;
extern String **uni_name;
extern void setFont(byte fontNumber);
extern int getGliphData(String *uniChar, int *index, int *width);

font.cpp

#include "font.h"


unsigned char *char_addr = NULL;
unsigned int *char_width = NULL;
String **uni_name = NULL;
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
void setFont(byte fontNumber)
{
    switch (fontNumber)
    {
    case 0:
        char_addr = (unsigned char *)(XB_Zar_addr);
        *uni_name = XB_Zar_name;
        char_width = (unsigned int *)XB_Zar_width;
        break;

    default:
        char_addr = (unsigned char *)XB_Zar_addr;
        break;
    }
}
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
int getGliphData(String *uniChar, int* index, int* charWidth)
{
Serial.println("uniChar data= "+*uniChar);
Serial.println("uni_name[i]= "+*uni_name[0]);// <---this resets the mcu
int countOfUniChars = sizeof(uni_name) / sizeof(String*);
    for (int i = 0; i < countOfUniChars ; i++)
    {    
        if (*uniChar == *uni_name[i])
        {
            *index = i;
            *charWidth = char_width[i];
            return i;
        }
    }
    return -1;
}

getGliphData() 内部,uni_name 只是一个指针,因此您试图用来计算 countOfUniCharssizeof() 技巧根本行不通(那里在 Whosebug 上有很多关于那个问题的问题。

因此,要么在存储数组指针的同时将数组长度存储到另一个全局变量中,要么用哨兵值(在本例中为空字符串)终止每个数组,然后循环遍历数组直到你到达哨兵。

此外,当 String* 指针就足够时,无需使用 String** 指针,因为您仅遍历 1 个 String 数组。如果您遍历指向 String 数组的指针数组,那么 String** 会更有意义。

此外,我看到的另一个问题是 XB_Zar_width[]XB_Zar_addr[] 只有 5 个元素,但 XB_Zar_name[] 有 6 个元素,而 getGliphData() 正在尝试遍历 XB_Zar_name[] 使用其索引访问 XB_Zar_width[]XB_Zar_addr[] 的元素,这显然不适用于第 6 个元素。

话虽这么说,但试试更像这样的东西:

// zar.h

/*v*/extern const unsigned char XB_Zar_118[];
/*w*/extern const unsigned char XB_Zar_119[];
/*x*/extern const unsigned char XB_Zar_120[];
/*y*/extern const unsigned char XB_Zar_121[];
/*z*/extern const unsigned char XB_Zar_122[];
extern const unsigned int XB_Zar_width[];
extern const unsigned char* XB_Zar_addr[];
extern const String XB_Zar_name[];
extern const int XB_Zar_name_len;
//zar.cpp

/*v*/ const unsigned char XB_Zar_118[] PROGMEM ={255,255,254,255,63,255};
/*w*/ const unsigned char XB_Zar_119[] PROGMEM ={255,127,255,254,255,5};
/*x*/ const unsigned char XB_Zar_120[] PROGMEM ={215,215,23,254,255,127};
/*y*/ const unsigned char XB_Zar_121[] PROGMEM ={255,127,25,254,255,9};
/*z*/ const unsigned char XB_Zar_122[] PROGMEM ={255,243,239,254,215,19};
const unsigned int XB_Zar_width[] = {2, 2, 2, 2, 2, 0}; // TODO: fix the 6th element!
const unsigned char* XB_Zar_addr[] = {XB_Zar_118, XB_Zar_119, XB_Zar_120, XB_Zar_121, XB_Zar_122, NULL}; // TODO: fix the 6th element!
const String XB_Zar_name[] = {"۰", "۱", "۲", "۳", "۴", "۵"}; // TODO: remove the 6th element?
const int XB_Zar_name_len = sizeof(XB_Zar_name)/sizeof(XB_Zar_name[0]);
//font.h

#pragma once
#include "zar.h"
extern const unsigned char **char_addr;
extern const unsigned int *char_width;
extern const String *uni_name;
extern int uni_name_len;
extern void setFont(byte fontNumber);
extern int getGliphData(const String &uniChar, int *index, int *width);
//font.cpp

#include "font.h"


const unsigned char **char_addr = NULL;
const unsigned int *char_width = NULL;
const String *uni_name = NULL;
int uni_name_len = 0;
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
void setFont(byte fontNumber)
{
    switch (fontNumber)
    {
    case 0:
        char_addr = XB_Zar_addr;
        char_width = XB_Zar_width;
        uni_name = XB_Zar_name;
        uni_name_len = XB_Zar_name_len;
        break;

    default:
        char_addr = XB_Zar_addr;
        char_width = XB_Zar_width;
        break;
    }
}
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
int getGliphData(const String &uniChar, int* index, int* charWidth)
{
    Serial.println("uniChar data= " + uniChar);
    if (uni_name)
    {
        for (int i = 0; i < uni_name_len; ++i)
        {  
            Serial.println("uni_name[" + String(i) + "]= " + uni_name[i]);
            if (uniChar == uni_name[i])
            {
                *index = i;
                *charWidth = char_width[i];
                return i;
            }
        }
    }
    return -1;
}

Online Demo

或者:

// zar.h

/*v*/extern const unsigned char XB_Zar_118[];
/*w*/extern const unsigned char XB_Zar_119[];
/*x*/extern const unsigned char XB_Zar_120[];
/*y*/extern const unsigned char XB_Zar_121[];
/*z*/extern const unsigned char XB_Zar_122[];
extern const unsigned int XB_Zar_width[];
extern const unsigned char* XB_Zar_addr[];
extern const String XB_Zar_name[];
//zar.cpp

/*v*/ const unsigned char XB_Zar_118[] PROGMEM ={255,255,254,255,63,255};
/*w*/ const unsigned char XB_Zar_119[] PROGMEM ={255,127,255,254,255,5};
/*x*/ const unsigned char XB_Zar_120[] PROGMEM ={215,215,23,254,255,127};
/*y*/ const unsigned char XB_Zar_121[] PROGMEM ={255,127,25,254,255,9};
/*z*/ const unsigned char XB_Zar_122[] PROGMEM ={255,243,239,254,215,19};
const unsigned int XB_Zar_width[] = {2, 2, 2, 2, 2, 0}; // TODO: fix the 6th element!
const unsigned char* XB_Zar_addr[] = {XB_Zar_118, XB_Zar_119, XB_Zar_120, XB_Zar_121, XB_Zar_122, NULL}; // TODO: fix the 6th element!
const String XB_Zar_name[] = {"۰", "۱", "۲", "۳", "۴", "۵", ""}; // TODO: remove the 6th element?
//font.h

#pragma once
#include "zar.h"
extern const unsigned char **char_addr;
extern const unsigned int *char_width;
extern const String *uni_name;
extern void setFont(byte fontNumber);
extern int getGliphData(const String &uniChar, int *index, int *width);
//font.cpp

#include "font.h"


const unsigned char **char_addr = NULL;
const unsigned int *char_width = NULL;
const String *uni_name = NULL;
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
void setFont(byte fontNumber)
{
    switch (fontNumber)
    {
    case 0:
        char_addr = XB_Zar_addr;
        char_width = XB_Zar_width;
        uni_name = XB_Zar_name;
        break;

    default:
        char_addr = XB_Zar_addr;
        char_width = XB_Zar_width;
        break;
    }
}
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
int getGliphData(const String &uniChar, int* index, int* charWidth)
{
    Serial.println("uniChar data= " + uniChar);
    if (uni_name)
    {
        for (int i = 0; uni_name[i].Length() > 0; ++i)
        {  
            Serial.println("uni_name[" + String(i) + "]= " + uni_name[i]);
            if (uniChar == uni_name[i])
            {
                *index = i;
                *charWidth = char_width[i];
                return i;
            }
        }
    }
    return -1;
}

Online Demo

我已经在 ESP32 微控制器上完成了@RemyLebeau 对 运行 的出色回答。

    // zar.h

/*v*/extern const unsigned char XB_Zar_118[];
/*w*/extern const unsigned char XB_Zar_119[];
/*x*/extern const unsigned char XB_Zar_120[];
/*y*/extern const unsigned char XB_Zar_121[];
/*z*/extern const unsigned char XB_Zar_122[];
extern const unsigned int XB_Zar_width[];
extern const unsigned char* XB_Zar_addr[];
extern const String XB_Zar_name[];
extern const int XB_Zar_name_len;

zar.cpp 文件:

//zar.cpp    
/*v*/ const unsigned char XB_Zar_118[] PROGMEM ={255,255,254,255,63,255};
/*w*/ const unsigned char XB_Zar_119[] PROGMEM ={255,127,255,254,255,5};
/*x*/ const unsigned char XB_Zar_120[] PROGMEM ={215,215,23,254,255,127};
/*y*/ const unsigned char XB_Zar_121[] PROGMEM ={255,127,25,254,255,9};
/*z*/ const unsigned char XB_Zar_122[] PROGMEM ={255,243,239,254,215,19};
const unsigned int XB_Zar_width[] = {2, 2, 2, 2, 2, 0}; // TODO: fix the 6th element!
const unsigned char* XB_Zar_addr[] = {XB_Zar_118, XB_Zar_119, XB_Zar_120, XB_Zar_121, XB_Zar_122, NULL}; // TODO: fix the 6th element!
const String XB_Zar_name[] = {"۰", "۱", "۲", "۳", "۴", "۵"}; // TODO: remove the 6th element?
const int XB_Zar_name_len = sizeof(XB_Zar_name)/sizeof(XB_Zar_name[0]);

font.h 文件:

//font.h

#pragma once
#include "zar.h"
extern const unsigned char **char_addr;
extern const unsigned int *char_width;
extern const String *uni_name;
extern void setFont(byte fontNumber);
extern int getGliphData(const String &uniChar, int *index, int *width);

font.cpp 文件:

//font.cpp

#include "font.h"


const unsigned char **char_addr = NULL;
const unsigned int *char_width = NULL;
const String *uni_name = NULL;
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
void setFont(byte fontNumber)
{
    switch (fontNumber)
    {
    case 0:
        char_addr = (unsigned char *)pgm_read_ptr(XB_Zar_addr[0]); // use pgm_read_ptr() becuse there is PROGMEM space in flash memory
        char_addr = XB_Zar_addr;
        char_width = XB_Zar_width;
        uni_name = XB_Zar_name;
        break;

    default:
        char_addr = (unsigned char *)pgm_read_ptr(XB_Zar_addr[0]); // use pgm_read_ptr() becuse there is PROGMEM space in flash memory
        char_addr = XB_Zar_addr;
        char_width = XB_Zar_width;
        uni_name = XB_Zar_name;
        break;
    }
    //Now. char_addr points to flash space and no need to use pgm_read_word_near()  
    // or using pgm_read_byte_near(). Simply use "*(char_addr)" or "*(char_addr+number)"
    //Serial.println("char_addr[0]= "+String(*(char_addr))));
    //Serial.println("char_addr[1]= "+String(*(char_addr+1)));
    //Serial.println("char_addr[3]= "+String(*(char_addr+3)));   
}
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
int getGliphData(const String &uniChar, int* index, int* charWidth)
{
    Serial.println("uniChar data= " + uniChar);
    if (uni_name)
    {
        for (int i = 0; uni_name[i].Length() > 0; ++i)
        {  
            Serial.println("uni_name[" + String(i) + "]= " + uni_name[i]);
            if (uniChar == uni_name[i])
            {
                *index = i;
                /* *charWidth = char_width[i]; it works if 'i' is 
                 * a const number at compile time. 
                 * constant 'i' only works because the compiler 
                 * sets the value of char_width[i] during 
                 * compilation, char_width[i] is a constant value
                 * pointing to one specific location in progmem 
                 * that the compiler knows the value of while 
                 * compiling see:https://forum.arduino.cc/t/passing-a-pointer-to-progmem-in-function/637756/5
                */
                *charWidth = pgm_read_word_near(char_width+*index);
                return i;
            }
        }
    }
    return -1;
}