Go Down

Topic: passing a char array (Read 1 time) previous topic - next topic

jeroen870

Hi!

I'm trying to do some LCD stuff, and for that I need a little routine to cut a string into pieces depending of the with of each character.
Since I can't find a lib with "text clipping" and "var width fonts", I'm trying to make something myself.

I wrote some code, and it's working fine, but I can't put it into a function. Can someone help me?

Code: [Select]

static int lengte[] = {
3, 1, 3, 5, 5, 5, 5, 2, 3, 3, 5, 5, 2, 5, 2, 5, //20,21,22,23,24,25,26,27,28,29,2a,2b,2c,2d,2e,2f
5, 3, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 4, 5, 4, 5, //30,31,32,33,34,35,36,37,38,39,3a,3b,3c,3d,3e,3f
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, //40,41,42,43,44,45,46,47,48,49,4a,4b,4c,4d,4e,4f
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 3, 5, 3, 5, 5, //50,51,52,53,54,55,56,57,58,59,5a,5b,5c,5d,5e,5f
3, 4, 4, 4, 4, 4, 4, 4, 4, 1, 3, 4, 3, 4, 4, 4, //60,61,62,63,64,65,66,67,68,69,6a,6b,6c,6d,6e,6f
4, 4, 4, 4, 4, 4, 5, 5, 5, 3, 3, 3, 1, 3, 5, 5, //70,71,72,73,74,75,76,77,78,79,7a,7b,7c,7d,7e,7f
};

char *FormatString(String Vtext) {

  #define LCDWIDTH   84
  int Vlengthtext=0;
  int Vprevlengthtext=0;
  char Vtext2[100]="";
  char *Vtexttoprint[200];
  int j=0;
  int k=0;

  for (int i=0; i<=Vtext.length();i++){
    Vtext2[k] = Vtext.charAt(i);
    k++;
    Vlengthtext = Vlengthtext + lengte[Vtext.charAt(i) - 0x20];
    if ((Vprevlengthtext <= LCDWIDTH*(1+j) && Vlengthtext > LCDWIDTH*(1+j)) || i==Vtext.length()){
      Vtexttoprint[j]=Vtext2;
      memset(Vtext2,0,sizeof(Vtext2));//for (int z=0; z<100;z++){Vtext2[z]=0;}
      k=0;
      j++;
    } else{
      Vprevlengthtext=Vlengthtext;
    }
  }
   
  return (Vtexttoprint); 
}



void setup(void){
}

void loop(void){
 
  for (int k = 0; k < 1; k++) {
    Serial.begin(9600);
    Serial.println(FormatString("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"))
    ;delay(100);
  }
    delay(10000);

}


Thanks,

Jeroen

PaulS

There are several problems with that function.

Code: [Select]
  char Vtext2[100]="";
If you are going to specify a length, why are you not specifying the same number of initializers?

Code: [Select]
  char *Vtexttoprint[200];
This is an array of pointers. It is unlikely that that is what you want.

Passing a String to this function is a waste of resources. Pass it a char array (or pointer to char) instead.

Code: [Select]
  for (int i=0; i<=Vtext.length();i++){
If there are 3 characters in the String, you are going to access characters 0, 1, 2, and 3. Hardly seems like a good idea to me.

You are trying to return an array of pointers from a function defined to return a single pointer. That pointer, or array of pointers if you change the return type appropriately go out of scope when the function ends, so the caller would get a load of garbage.

You need to pass to the function a pointer to the memory location where it is to put its results, after allocating that memory in the caller.

mkwired

I would write a function that returns how much of the string can "fit" on a line.
Code: [Select]

#define LCDWIDTH   84

static const uint8_t lengte[] = {
3, 1, 3, 5, 5, 5, 5, 2, 3, 3, 5, 5, 2, 5, 2, 5, //20,21,22,23,24,25,26,27,28,29,2a,2b,2c,2d,2e,2f
5, 3, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 4, 5, 4, 5, //30,31,32,33,34,35,36,37,38,39,3a,3b,3c,3d,3e,3f
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, //40,41,42,43,44,45,46,47,48,49,4a,4b,4c,4d,4e,4f
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 3, 5, 3, 5, 5, //50,51,52,53,54,55,56,57,58,59,5a,5b,5c,5d,5e,5f
3, 4, 4, 4, 4, 4, 4, 4, 4, 1, 3, 4, 3, 4, 4, 4, //60,61,62,63,64,65,66,67,68,69,6a,6b,6c,6d,6e,6f
4, 4, 4, 4, 4, 4, 5, 5, 5, 3, 3, 3, 1, 3, 5, 5, //70,71,72,73,74,75,76,77,78,79,7a,7b,7c,7d,7e,7f
};

char* maxline(char* p, uint8_t max_width)
{   
   for (uint8_t w = lengte[*p - 0x20]; w < max_width; p++)
      w += lengte[*p - 0x20];
   return p;
}

void setup(void){
   Serial.begin(9600);
}

void loop(void){
  char* b = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
  char* e = maxline(b, LCDWIDTH);
 
  Serial.write((const uint8_t *)b, e-b);
  Serial.println("");
  delay(10000);
}

tuxduino

I often use this macro:

Code: [Select]
#define ARY_LEN(a) (sizeof(a) / (sizeof(a[0])))

jeroen870

Thanks to you guys I've fabricated something that works (for 95%).
I can now show some text on my 3310 nokia lcd screen.
There is still a weird sign at the end of the text, and I don't know how to delete that last caracter.
If someone has an idea in what I'm doing wrong, please comment.

Greetings, Jeroen

pYro_65

Quote
If you are going to specify a length, why are you not specifying the same number of initializers?


I'm not sure of the original posters intention, but its worth pointing out, an initialiser is perfectly fine with fewer elements than allocated to the array.
Consider this:

A large array created globally, say of type int and 100 elements, the implementation specifies that global memory is zero initialised unless explicitly set. By initialising only the needed elements you can shorten the globals section which copies/creates initial values into global variables. This runs as your code starts, effectively only containing 'x' amount of copies rather than a partially redundant 100 copies.

PaulS

Quote
I'm not sure of the original posters intention, but its worth pointing out, an initialiser is perfectly fine with fewer elements than allocated to the array.

My point was that if you are going to define the size, and provide no initializers, why bother? Just define the size and forget the initialization.

mkwired

It looks like me code had a bug.  See my change below.  Also, the first call to gotoXY the parameter y equals -1 is that a bug?

Code: [Select]

char* maxline(char* p, uint8_t max_width) { //(NOT) make a string that is one line long -----------
   for (uint8_t w = lengte[*p - 0x20]; *p && w < max_width; p++)
      w += lengte[*p - 0x20]+1; // should the +1 be here?
   return p;
}

Go Up