Zeichenketten kürzen? strXXX

Hallo, gibt es eine Möglichkeit, eine Zeichenkette auf n-Elemente zu beschränken?
Habe noch nicht die passende str-Funktion gefunden. Möchte maximal 4 Zeichen erlauben, da es ansonsten zu einer Überschreitung kommt. Hab schon ein bisschen herumprobiert. -> // HIER

if (strlen(id) >= 5) strncpy(id, id, 4);

Funktiert nicht.

	if (strlen(id) >= 5) {
		char* oldId;
		strncpy(oldId, id, 4);
		strncpy(id, oldId,4);
	}
char* strndel(char* a, byte size) {
	char* b;
	strncpy(b, a, size - 1);
	b = '\0';
	return b;
}

id = strndel(id, 3);

Leider auch erfolglos!

Funktioniert ebenfalls nicht, und es kommt scheinbar zu einem Speicherübergreifenden Fehler. Bekomme den Text garnicht mehr angezeigt und zeitgleich werden andere Zeichnung stark in mitleidenschafft gezogen.

void menuItem(byte x, byte y, char* id) {
	const byte adjX = 39;			// Laenge Elements
	const byte adjY = 14;			// Hoehe Elements
	const byte sizeCorner = 3;		// Groeße Ecke
	const byte xChar = 8;			// Hoehe Zeichen
	const byte yChar = 12;			// Breite Zeichen
	const int colBorder = 0xFF00;	// Farbe Umrandung
	const int colId = 0x0000;		// Farbe Text

	// HIER

	glcd.setColor(colBorder);	
	glcd.drawLine(x + sizeCorner, y, x + adjX, y);				// oben
	glcd.drawLine(x + adjX, y, x + adjX, y + adjY);				// rechts
	glcd.drawLine(x, y + adjY, x + adjX, y + adjY);				// unten
	glcd.drawLine(x, y + sizeCorner, x, y + adjY);				// links
	glcd.drawLine(x, y + sizeCorner, x + sizeCorner, y + 0);	// schrage

	glcd.setColor(colId);
	glcd.print(id, x + (adjX - (strlen(id) * xChar)) / 2, y + ((adjY - yChar) / 2));
}

wie wäre es mit snprintf(id,4,"%s",id);

Hallo adubu,

bringt mir leider nicht viel. Die UTFT Lib unterstützt keine Ausgabe von formatierten Print-Befehlen.
Das weitere Problem wäre, dass ich somit auch die Berechnung unten über den Haufen werfen kann, bzw. diese auch fix legen muss für den Fall, dass mehr als 4 Zeichen angegeben werden.

Meinst du sowas ?

// begrenzt input auf maxSize Zeichen
// Achtung : input wird verändert
char* truncate ( char* input, unsigned int maxSize)
{
   if (strlen(input) > maxsize)
         input[maxsize] = 0;
   return input;
}

example usage:

void setup() {
  lcd.begin(16,2);
  static char TestString[] = "Dieser Text ist zu lang";
  lcd.print(truncate(TestString,3));   // schreibt "Die"
  // ... und verändert TestString
}

Wenn TestString nicht verändert werden darf, braucht man natürlich eine extra Variable. Das sähe geringfügig komplizierter aus.

Oder du verwendest einfach

lcd.write(TestString,3);  // schreibt die ersten 3 Buchstaben von TestString

Oder geht's um was ganz anderes ?

Hallo Michael,

es geht eher um etwas anders. Falls es nicht deutlich am Sketchausschnitt wird, es geht hier um die Ausgabe auf einem GLC Display mit Hilfe der UTFT Libary. Somit funktionieren lcd.write oder sprintf nicht.

So, konnte deine Lösung bei mir einsetzen.

// Subfunction

char* cutId(char* id, byte size) 
{
	if (strlen(id) > size) id[size] = '\0';
	return id;
}

//Function

void menuItem(byte x, byte y, char* id) {
	const byte adjX = 39;				// Laenge Elements
	const byte adjY = 14;				// Hoehe Elements
	const byte sizeCorner = 3;			// Groeße Ecke
	const byte xChar = 8;				// Hoehe Zeichen
	const byte yChar = 12;				// Breite Zeichen
	const int colBorder = 0x0000;		// Farbe Umrandung
	const int colId = 0x0000;			// Farbe Text

	id = cutId(id, maxDigId);

	glcd.setColor(colBorder);
	glcd.drawLine(x + sizeCorner, y, x + adjX, y);				// oben
	glcd.drawLine(x + adjX, y, x + adjX, y + adjY);				// rechts
	glcd.drawLine(x, y + adjY, x + adjX, y + adjY);				// unten
	glcd.drawLine(x, y + sizeCorner, x, y + adjY);				// links
	glcd.drawLine(x, y + sizeCorner, x + sizeCorner, y + 0);	// schrage

	glcd.setColor(colId);
	glcd.print(id, x + (adjX - (strlen(id) * xChar)) / 2, y + ((adjY - yChar) / 2));
}
if (strlen(id) >= 5) {
		char* oldId;
		strncpy(oldId, id, 4);
		strncpy(id, oldId,4);
	}

Hattest du da auch irgendwo mal ein Array dafür angelegt? Du kannst nicht einfach nur einen Zeiger definieren und dann Sachen dahinter kopieren. Das ist natürlich ein Speicherüberlauf.

Ich habe mir für meine ganzen String-Operationen ein größeres Array namens stringBuffer angelegt. Das kann ich dann als Zwischenspeicher verwenden um Strings aus dem Flash auszulesen, Sachen von der SD Karte zu lesen, Strings mit sprintf() zu formatieren, etc. Ab und zu brauche ich noch lokal einen zweiten Puffer aber das ist sehr selten.

Serenifly:

if (strlen(id) >= 5) {
	char* oldId;
	strncpy(oldId, id, 4);
	strncpy(id, oldId,4);
}

Gute Compiler sollten meckern, dass oldId undefiniert ist, du also irgendwo hin zwischenspeicherst.
Da es beim Arduino keine Access Violations gibt, geht das manchmal gut :wink:

Wenn es zufälligerweise gut geht, bewirkt es das gleiche wie

if (strlen(id >= 5) id[5] = 0;

Defeniert wurde doch das oldId, lediglich die max. Länge wurde nicht angegeben, hab ich aber nirgends in dem Teil machen können.

Wie kann man sowas am besten regeln?

char* cutId(char* id, byte size) 
{
	if (strlen(id) > size) id[size] = '\0';
	return id;
}
void menuItem(byte x, byte y, char* id) {
	id = cutId(id, maxDigId);
}
void loop(void) {
	menuItem(0,0, "HalloWelt");
}

Am besten du schreibst sowas gleich ins Flash, sofern das nicht unbedingt ständig im RAM stehen muss. Ich mache es so:

const int STRING_BUFFER_SIZE = 41;
char stringBuffer[STRING_BUFFER_SIZE];

void displayPrint_P(const char* str, int x, int y)
{
  strncpy_P(stringBuffer, str, STRING_BUFFER_SIZE);
  display.print(stringBuffer, x, y);
}

void func()
{
    displayPrint_P(PSTR("String"), 0, 10);
}

Da kannst du auch einen weiteren Parameter für die maximale Länge angeben und dann entsprechend den Terminator setzen

Mit stringBuffer gehen dann auch solche Sachen:

char* getTimeStr()
{
  sprintf_P(stringBuffer, PSTR("%02d:%02d:%02d"), hour(), minute(), second());
  return stringBuffer;
}

char* getDayStr(byte day)
{
  return strcpy_P(stringBuffer, (char*)pgm_read_word(&dayStrings[day]));
}

Oder für SD:

size = file.fgets(stringBuffer, STRING_BUFFER_SIZE);

Oder was auch geht:

#define P(str) strcpy_P(stringBuffer, str)

Dann kann man es ähnlich wie das F()-Makro verwenden

Ich werde gleich mal schaun, was ich davon anwenden kann. Die Funktion wird nicht dauerhaft gebraucht, nur jedesmal, wenn der Arduino resetet oder das Display aus war. Danach bleiben die Zeilen statisch stehen.

Großartig RAM/Flash sparen wird erst einmal wenig bringen. Ich habe das ganze Teil zwar noch auf dem Uno, ist aber inzwischen mit der UTFT Lib bereits recht voll mit 70%. Soblad voll, werde ich den Mega dafür umbauen. Es wird noch einiges dazu kommen. Es handelt sich hier ein relativ umfangreiches Menü zum Verstellen von Parameter, Anzeigen von Werten, etc.

Lohnt sich aber auf dem Mega, auch wenn der 8kB RAM hat. Gerade bei String Literalen kommt schon einiges zusammen auch wenn es hier und da erst mal nur wenig erscheint. Da verschwendet man schnell mal ein paar hundert Bytes.