[erledigt] C/C++-String-handling

Vom einfachen Programm zum fertigen Debian-Paket, Fragen rund um Programmiersprachen, Scripting und Lizenzierung.
Antworten
Benutzeravatar
GregorS
Beiträge: 2616
Registriert: 05.06.2008 09:36:37
Wohnort: Freiburg
Kontaktdaten:

[erledigt] C/C++-String-handling

Beitrag von GregorS » 12.10.2014 01:25:34

N‘amd allerseits!

Ich suche mir gerade eine Hornhaut auf meine Brille und fürchte, dass ich mich mal wieder vollkommen dämlich anstelle. Lasst bitte Gnade walten :-)

In einem Programm habe ich folgende zwei Zeilen:

Code: Alles auswählen

char author_name[]="G. Szaktilla                            ";
ea.author_name=author_name;
ea.author_name ist im Header als Teil eines structs so deklariert:

Code: Alles auswählen

struct TGAFile_Header {
  ...
  char author_name[41];
  ...
}
Die Meldung invalid array assignment, die ich beim Compilieren erhalte, kann ich mir nicht erklären.
Was zur Hölle mache ich hier falsch?

Gruß

Gregor
Zuletzt geändert von GregorS am 12.10.2014 03:45:40, insgesamt 1-mal geändert.
Wenn man keine Probleme hat, kann man sich welche machen. ("Großes Lötauge", Medizinmann der M3-Hopi [und sog. Maker])

wanne
Moderator
Beiträge: 7463
Registriert: 24.05.2010 12:39:42

Re: C/C++-String-handling

Beitrag von wanne » 12.10.2014 02:16:28

Die []-Schreibweise ist sehr verwirrend: Sie ist nur ein equivalent für das:

Code: Alles auswählen

char* author_name="G. Szaktilla                            ";
Und da siehts du recht schön, dass das nicht geht:
char* ist ein Pointer. (Klassischerweise 2,4 oder 8Byte). Der passt nicht in den 41Byte großes char[41].
Welcher Compiler ist das im übrigen, der invalid array assignment aus gibt?
rot: Moderator wanne spricht, default: User wanne spricht.

Benutzeravatar
GregorS
Beiträge: 2616
Registriert: 05.06.2008 09:36:37
Wohnort: Freiburg
Kontaktdaten:

Re: C/C++-String-handling

Beitrag von GregorS » 12.10.2014 02:23:24

wanne hat geschrieben:Die []-Schreibweise ist sehr verwirrend: Sie ist nur ein equivalent für das:

Code: Alles auswählen

char* author_name="G. Szaktilla                            ";
Und da siehts du recht schön, dass das nicht geht:
char* ist ein Pointer. (Klassischerweise 2,4 oder 8Byte). Der passt nicht in den 41Byte großes char[41].
Welcher Compiler ist das im übrigen, der invalid array assignment aus gibt?
Eieiei ... peinlich ... sowas ...

Eigentlich sollte man meinen, dass so ein Blödsinn nur blutigen Anfängern passiert.

Compiler ist g++ 4.7.2 (das, was gerade bei Wheezy dabei ist).

Gruß

Gregor
Wenn man keine Probleme hat, kann man sich welche machen. ("Großes Lötauge", Medizinmann der M3-Hopi [und sog. Maker])

wanne
Moderator
Beiträge: 7463
Registriert: 24.05.2010 12:39:42

Re: C/C++-String-handling

Beitrag von wanne » 12.10.2014 02:48:02

Achso:
Da hat's ein schönes Beispiel: http://www.cplusplus.com/reference/cstring/memcpy/
Du willst vermutlich das:

Code: Alles auswählen

strcpy(ea.author_name,"G. Szaktilla");
Btw: NULL-Terminiert und feste Lenge mit Leerzeichen. Ist das nicht irgend wie doppelt?
Compiler ist g++ 4.7.2 (das, was gerade bei Wheezy dabei ist).
Ah der C++-Compiler denkt da ein bisschen anders.
Hier im übrigen mal ne C++ variante: (viel einfacher)

Code: Alles auswählen

#include <iostream>
#include <string>

using namespace std;
struct TGAFile_Header {
  string author_name;
};

int main()
{
        string author_name="G. Szaktilla                            ";
        struct TGAFile_Header ea;
        ea.author_name=author_name;
        std::cout << ea.author_name;
}
rot: Moderator wanne spricht, default: User wanne spricht.

Benutzeravatar
GregorS
Beiträge: 2616
Registriert: 05.06.2008 09:36:37
Wohnort: Freiburg
Kontaktdaten:

Re: C/C++-String-handling

Beitrag von GregorS » 12.10.2014 02:55:47

wanne hat geschrieben:Achso:
Da hat's ein schönes Beispiel: http://www.cplusplus.com/reference/cstring/memcpy/
Du willst vermutlich das:

Code: Alles auswählen

strcpy(ea.author_name,"G. Szaktilla");
Btw: NULL-Terminiert und feste Lenge mit Leerzeichen. Ist das nicht irgend wie doppelt?
Klasse! Bei cplusplus.com gucke ich häufig vorbei, wenn es um das schnelle Nachschlagen einer Syntax geht. Aber da ich mich fast ausschließlich mit <string>-Strings beschäftige, stehe ich bei C-Strings immer wieder saudoof vor der Wand ... strcpy hätte ich vermutlich nie gefunden.
Wg. Deinem BTW: Auf eine feste Größe blase ich das nur auf, weil ich anderswo nicht mit Offsets rechnen möchte.

Danke für die schnelle Hilfe!

Gregor
Wenn man keine Probleme hat, kann man sich welche machen. ("Großes Lötauge", Medizinmann der M3-Hopi [und sog. Maker])

Benutzeravatar
bmario
Beiträge: 1256
Registriert: 05.09.2007 12:15:47
Lizenz eigener Beiträge: MIT Lizenz
Wohnort: Dresden

Re: C/C++-String-handling

Beitrag von bmario » 12.10.2014 02:58:54

GregorS hat geschrieben:Eieiei ... peinlich ... sowas ...
Macht nichts, wanne's Erklärung ist auch nicht besser.

Es gibt in C (und auch in C++) das "array to pointer decay". Das heißt, man kann ein Array auch als einen Pointer auf das erste Element auffassen.

Code: Alles auswählen

void foo(char * bar) {
  printf("%s\n", bar);
}

char hello[] = "Hello"; // hello ist ein char-Array mit 6 Elementen
foo(hello); // ...es kann aber implizit zu char * gecastet werden (das ist der decay)
Und man kann andersrum mittels Pointerarithmetik von einem Pointer aus, auf Arrayelemente zugreifen. Dies ist aber nicht immer eine gute Idee.

Code: Alles auswählen

char c='A';
char *p = &c;
char d;
d = *c; // dies ist äquivalent zu ...
d = c[0]; // ... dem Zugriff auf das erste Array Element
char e = c[1] = *(c+1); // Ist zwar äquivalent, aber trotzdem in dem Fall "undefined behaviour"
Und was ist nun dein Problem? Du würfelst Array und Pointer wild durcheinander.

Code: Alles auswählen

char author_name[]="G. Szaktilla                            "; // Dies legt tatsächlich ein Array an.

Code: Alles auswählen

struct TGAFile_Header {
  ...
  char author_name[41]; // Allerdings legt dies auch ein Array an *
  ...
}
Und nun kommt das Problem.

Code: Alles auswählen

ea.author_name=author_name;
Du versucht hier ein Array einem anderen Array zuzuweisen. Das hat allerdings in C keine Zukunft. Hier hilft auch der "Trick" des Decay's nicht weiter, da ea.author_name ein Array ist, aber der Decay nur für Zuweisungen an Pointer funktioniert. Die Fehlermeldung des Compilers ist also durchaus nachvollziehbar. invalid array assignment

Du kannst nun entweder TGAFile_Header:: author_name als char * definieren und dann je nach dem z.B. strdup() oder den Decay nutzen und den Pointer direkt zuweisen. Oder du kopierst mit memcopy den Inhalt des Arrays.

Anmerkung: In C++ würde man wohl std::string vorziehen.

* Vergleiche mal sizeof(TGAFile_Header) einmal mit char * und einmal mit char[]
Nichts zu tun ist viel besser,
als mit viel Mühe nichts zu schaffen. - Laotse

wanne
Moderator
Beiträge: 7463
Registriert: 24.05.2010 12:39:42

Re: C/C++-String-handling

Beitrag von wanne » 12.10.2014 03:09:16

GregorS hat geschrieben:Wg. Deinem BTW: Auf eine feste Größe blase ich das nur auf, weil ich anderswo nicht mit Offsets rechnen möchte.
Dazu ist ja die null-Termination da. Mach die Leerzeichen weg.
bmario hat geschrieben:Macht nichts, wanne's Erklärung ist auch nicht besser.
Warum?
rot: Moderator wanne spricht, default: User wanne spricht.

Benutzeravatar
GregorS
Beiträge: 2616
Registriert: 05.06.2008 09:36:37
Wohnort: Freiburg
Kontaktdaten:

Re: C/C++-String-handling

Beitrag von GregorS » 12.10.2014 03:45:19

wanne hat geschrieben:
bmario hat geschrieben:Macht nichts, wanne's Erklärung ist auch nicht besser.
Warum?
Ich fand wannes Erklärung hilfreich. Zumindest habe ich kapiert, wo der Fehler steckt.

Kein Wunder, dass ich auf <string>-Strings stehe.

Gut‘s Nächtle

Gregor
Wenn man keine Probleme hat, kann man sich welche machen. ("Großes Lötauge", Medizinmann der M3-Hopi [und sog. Maker])

wanne
Moderator
Beiträge: 7463
Registriert: 24.05.2010 12:39:42

Re: C/C++-String-handling

Beitrag von wanne » 12.10.2014 03:59:08

GregorS hat geschrieben:Kein Wunder, dass ich auf <string>-Strings stehe.
Ja. C-Strings sind nicht die genialste Erfindung.
rot: Moderator wanne spricht, default: User wanne spricht.

owl102

Re: C/C++-String-handling

Beitrag von owl102 » 12.10.2014 11:05:18

wanne hat geschrieben:Die []-Schreibweise ist sehr verwirrend: Sie ist nur ein equivalent für das:

Code: Alles auswählen

char* author_name="G. Szaktilla                            ";
Nicht ganz.

Code: Alles auswählen

char *x = "a";
legt einen char-Pointer namens "x" an und initialisiert diesen Pointer mit einem Wert, der auf das unbenannte char-Array "a" zeigt. Man kann hier den Wert von x zur Laufzeit verändern, da x eine eigenständige Variable ist, unabhängig vom char-Array:

Code: Alles auswählen

x  = "Hallo!";
Bei

Code: Alles auswählen

char x[] = "a";
wird hingegen lediglich ein char-Array angelegt und nichts weiter. Das char-Array hat den Namen "x" und ist mit "a" vorinitialisiert.

Code: Alles auswählen

x  = "Hallo!";
funktioniert hier logischerweise nicht.

Das Equivalent zu

Code: Alles auswählen

char* author_name="G. Szaktilla                            ";
wäre also

Code: Alles auswählen

char _author_name[]="G. Szaktilla                            ";
char *author_name=_author_name;
C-Strings sind nicht die genialste Erfindung.
Wie hättest du es denn anders gemacht?

Benutzeravatar
GregorS
Beiträge: 2616
Registriert: 05.06.2008 09:36:37
Wohnort: Freiburg
Kontaktdaten:

Re: C/C++-String-handling

Beitrag von GregorS » 12.10.2014 18:21:21

owl102 hat geschrieben:
C-Strings sind nicht die genialste Erfindung.
Wie hättest du es denn anders gemacht?
Meine (sehr oberflächlichen) Erfahrungen mit C-Strings sind verherend. Ich habe mir deshalb ziemlich schnell den Einsatz von <string> angewöhnt. Ich finde das Handling dieser Zeichenketten deutlich intuitiver. C-Strings liegen einem wohl eher, wenn man beim Programmieren ein „Speicherabbild“ im Kopf hat. Ein Freund , den ich wegen dieses Problems angerufen habe, sagte, dass er mit den C-Strings immer wieder Probleme hatte und deshalb sprintf benutzt. Ich finde diesen hier und da angestaubten C-Kram zum Davonlaufen. Aber ich habe die Coderei auch mit einem Buch für C++ gelernt, in dem AFAIR kein einziges Mal ein printf o.ä. vorkommt.

Gruß

Gregor
Wenn man keine Probleme hat, kann man sich welche machen. ("Großes Lötauge", Medizinmann der M3-Hopi [und sog. Maker])

Benutzeravatar
bmario
Beiträge: 1256
Registriert: 05.09.2007 12:15:47
Lizenz eigener Beiträge: MIT Lizenz
Wohnort: Dresden

Re: [erledigt] C/C++-String-handling

Beitrag von bmario » 12.10.2014 21:34:24

Das liegt auch daran, das C-Strings in C genutzt werden und std::string in C++. C und C++ sind verschiedene Sprachen und wer etwas Anderes behauptet hat in meinen Augen weder von der Einen noch der anderen Sprache Ahnung. Für jede Sprache gibt es eigene Herangehensweisen und Idiome um Probleme zu lösen, nur weil man in C++ Dinge so wie in C lösen kann, heißt das noch lange nicht, dass man das auch tun sollte.
Nichts zu tun ist viel besser,
als mit viel Mühe nichts zu schaffen. - Laotse

Hans-Martin
Beiträge: 141
Registriert: 06.12.2007 18:03:03
Lizenz eigener Beiträge: MIT Lizenz
Wohnort: Kehl

Re: [erledigt] C/C++-String-handling

Beitrag von Hans-Martin » 23.10.2014 18:44:55

Es gibt in C keine Strings im eigentlichen Sinn.

C ist so etwas wie eine Untermenge von C++, wobei C++ bezüglich der Dateitypen und Initialisierungen viel mehr Genauigkeit vom Programmierer verlangt, teils allerdings auch mehr Freiheiten gibt. So etwas wie char a[12] ist kein String, sondern enthält eine Folge von bis zu 11 Zeichen vor der abschließenden Null, die wir als String lesen können. Auch wenn Funktionen wie strcpy () an das Wort string erinnern, sind es in Wirklichkeit Arrays des Typs char. Die C++-Klasse string enthält Möglichkeiten zur direkten Zuweisung mittels des Zeichens "=". In C ist diese Möglichkeit nur für numerische Werte, bei einer ersten Initialisierung oder der Zuweisung von Zeichen an einzelne char gegeben (wobei jedes alphabetische Zeichen einen numerischen Wert hat). Die einzige Ausnahme stellen Strukturen da.

struct beispiel {char vorname[16],name[16];int alter}b1,b2;
...
Man weist Werte zu:
strcpy(b1.vorname,"Peter");
strcpy(b2.name,"Müller");
b1.alter=33;
Nun kann man definieren:
b2=b1;

Damit sind alle Werte an die Instanz b2 der struct beispiel übertragen. Die Ausgabe von b2.vorname ist z.B. nach der Zuweisung "Peter".

Falls bei Arrays die Zuweisung mit strcpy() z.B. wegen des Datentyps Probleme macht, steht memcpy() zur Verfügung.

Die im obigen Beispiel verwendeten Leerzeichen nach der Zuweisung können durchaus sinnvoll sein, um die Ausgabe zu gestalten. Habe ich z.B. eine Maske und jeweils eine bestimmte Zeile für eine Ausgabe (ich denke jetzt an Anwendungen, die auf einem Terminal laufen, ideal unter Verwendung von ncurses), bleibt bei unterschiedlich langen Zeichenfolgen immer das Problem, den Zeilenrest löschen zu müssen. Steht aber in einer Zeile ein Wert, der nicht gelöscht werden soll, z.B. die Hausnr., würde dabei "Nr." gelöscht werden. Leerzeichen sind Zeichen, die ausgegeben werden, so wie die Zahl Null nicht identisch mit einer leeren Menge ist. Wenn ich bei der Anlage von Datensätzen die Länge entsprechend plane und die Arrays mit Leerzeichen auffülle, kann ich den Inhalt eines Datensatzes ganz unproblematisch mit einem anderen überschreiben, in der Praxis z.B. in einer Liste aufwärts und abwärts blättern.

Antworten