verwaltung von namen mit zeigern und dynamischen variablen
-
hey,
ich habe grade erst angefangen zu Programmiern (ich bitte also um ein bisschen nachsicht).
Ich möchte das mein Unterprogramm alle Buchstaben in Klein-Buchstaben umwandelt.
Mein Testfeld sieht so aus:char *TstNamPtrArr[10] = {"hAnS","FRANZ","oTTo","lisa-marie","LISA MARIE"};
Das habe ich programmiert: Es kommt aber eine Fehlermeldung, dass ich in geschützten Specher schreibe.
void ConvertNamen (char *NamPtrArr[10], int namAnz) { //************************************************************************** // ConvertNamen - Umformung der Namen in die übliche Schreibweise //************************************************************************** for(int a=0; a<=namAnz; a++) { int len = strlen(*NamPtrArr); for(int i=0; i<len; i++) { if(*NamPtrArr[i] >= 'A' && *NamPtrArr[i] <= 'Z') { *NamPtrArr[i] += 32; } NamPtrArr++; } } }
Würde mich über Hilfe sehr freuen.
mfg pincerepa
-
int toupper(int c);
ctype.h
oder die Entsprechung für Unicode.
siehe Wutz.
An Deinen Variablenamen solltest Du arbeiten!
-
Das Ändern von Elementen aus Stringliterale ist standardgemäß UB, das möchte der Compiler dir mit der Fehlermeldung mitteilen.
Lerne den Unerschied zwischen Zeiger und Array, insbesondere für Stringliterale, und dir wird geholfen sein.
-
Wutz schrieb:
Das Ändern von Elementen aus Stringliterale ist standardgemäß UB, das möchte der Compiler dir mit der Fehlermeldung mitteilen.
Literale tauchen nur im Quellcode auf.
Es ist nämlich so:char *a = "hello"; // *a zeigt auf einen String, der read-only ist. char b[] = "world"; // b[] enthält einen String, der beschrieben werden darf
-
Z schrieb:
Literale tauchen nur im Quellcode auf.
Schwachfug. Schon mal davon gehört, dass Quellcodeteile eine Speicherklasse haben oder initialisiert werden (können)?
`A character string literal has static storage duration and type'array of char' , and is initialized with the given characters.`
Z schrieb:
Es ist nämlich so:
char *a = "hello"; // *a zeigt auf einen String, der read-only ist.
Ist es nicht. *a zeigt nicht auf einen String, sondern a.
Von read-only steht nichts im Standard, das ist Aberglaube.
Der Standard definiert nur, was ich oben geschrieben habe.
`If the program attempts to modify a string literal ..., thebehavior is undefined.`
ANSI C, Kap. 3.1.4
-
Das ist nett das ihr mir geantwortet habt, aber irgendwie bringt mich das nicht wirklich weiter.
Es kann schon sein das ich da etwas Grundlegendes nicht verstehe, aber wie könnte ich das denn anders machen?Ich glaube der Fehler ist in Zeile 10 und 12,
aber ich möchte doch das er den Inhalt ändert, also muss ich doch *NamPtrArr nehmen und nicht NamPtrArr. Wenn ich das mit tolower mache, kommt die Meldung: Konvertierung von char* in int nicht möglich.Und in Zeile 12 möchte ich die Adresse wechseln, zum nächsten Namen. Müsste doch auch richtig sein.
-
Dein Problem ist zunächst die Definition von
char *TstNamPtrArr[10] = {"hAnS","FRANZ","oTTo","lisa-marie","LISA MARIE"};
Das ist ein Array aus 10 Zeigern auf Stringliterale.
Beim beschreiben von Stringliterale ist das Verhalten undefiniert:
Bei dir liegen sie in einem Speicherbereich, in den du nicht schreiben darfst.Du solltest auch überprüfen wie weit deine erste Schleife
a<=namAnz
zählt.
-
Wutz schrieb:
Z schrieb:
Literale tauchen nur im Quellcode auf.
Schwachfug. Schon mal davon gehört, dass Quellcodeteile eine Speicherklasse haben oder initialisiert werden (können)?
`A character string literal has static storage duration and type'array of char' , and is initialized with the given characters.`
In computer science, a literal is a notation for representing a fixed value in source code.
--> http://en.wikipedia.org/wiki/Literal_(computer_programming)Und im C-Std. (6.4.5):
A character string literal is a sequence of zero or more multibyte characters enclosed in double-quotes, as in "xyz".
-
Der C- Standard sagt, dass das Verhalten beim Schreibzugriff unbestimmt ist.
Das kann bedeuten das der Schreibzugriff einfach nicht ausgeführt wird, oder
das das Programm abstürzt, oder
das der Computer abstürzt, oder
das der Schreibzugriff einfach ausgeführt wird wenn der Rechner/Compiler kein Schutz dagegen hat.Oder es stürzt irgendein Computer/CPU irgendwo in der Welt ab.
-
Z schrieb:
In computer science, a literal is a notation for representing a fixed value in source code.
--> http://en.wikipedia.org/wiki/Literal_(computer_programming)Und im C-Std. (6.4.5):
A character string literal is a sequence of zero or more multibyte characters enclosed in double-quotes, as in "xyz".Und was besagt das?
Du kannst/willst nicht lesen und/oder verstehen und kommst mit allgemeingültigen Weisheiten daher für einen speziellen Anwendungsfall, der für sich schon wohldefiniert und spezifiziert ist.
-
DirkB schrieb:
Der C- Standard sagt, dass das Verhalten beim Schreibzugriff unbestimmt ist.
Das kann bedeuten das der Schreibzugriff einfach nicht ausgeführt wird, oder
das das Programm abstürzt, oder
das der Computer abstürzt, oder
das der Schreibzugriff einfach ausgeführt wird wenn der Rechner/Compiler kein Schutz dagegen hat.
...Allenfalls könnte man IMHO noch vertreten zu sagen, dass ein Stringliteral read-only sein kann, und das nicht unbedingt in jedem Anwendungsfall im Programm oder Programmdurchlauf jeweils gleich (unbestimmt) reagiert wird.
-
pincerepa schrieb:
Es kann schon sein das ich da etwas Grundlegendes nicht verstehe,
Jawoll, so ist es.
void toupperAll(char (*a)[100],size_t n) { while( n-- ) { char *s=a++; while( *s ) *s=toupper((unsigned char)*s),++s; } } int main() { /* Array von 5 100er-char-Arrays, deren chars per Definition alle beschreibbar sind */ char TstNamPtrArr[5][100] = {"hAnS","FRANZ","oTTo","lisa-marie","LISA MARIE"}; toupperAll(TstNamPtrArr,5); return 0; }
-
Wutz schrieb:
Z schrieb:
In computer science, a literal is a notation for representing a fixed value in source code.
--> http://en.wikipedia.org/wiki/Literal_(computer_programming)Und im C-Std. (6.4.5):
A character string literal is a sequence of zero or more multibyte characters enclosed in double-quotes, as in "xyz".Und was besagt das?
Dass (String-) Literale im Quelltext stehen.
Aus welcher Ausgabe des C-Std. stammt der Satz: "A character string literal has static storage duration and type 'array of char', and is initialized with the given characters."?
-
Z schrieb:
Dass (String-) Literale im Quelltext stehen.
Lerne erstmal vernünftig die Sprache Deutsch bevor du mit der Sprache C rummachst.
Deine Worte
Z schrieb:
Literale tauchen nur im Quellcode auf.
stellen wie o.g. eine unhaltbare Verallgemeinerung hinsichtlich der Originalfragestellung und des Forumtitels dar.
Z schrieb:
Aus welcher Ausgabe des C-Std. stammt der Satz: "A character string literal has static storage duration and type 'array of char', and is initialized with the given characters."?
Wenn du lesen könntest und auch ein bisschen nachdenken würdest beim Lesen, würdest du vielleicht bemerken, dass für beide gleichformatierte Zitate die u.g. Quelle gilt.
Mein Quorum für max. 3 Antworten bei Querulanten ist erreicht, ich werde dir nicht mehr antworten.
-
Wutz schrieb:
Mein Quorum für max. 3 Antworten bei Querulanten ist erreicht, ich werde dir nicht mehr antworten.
Alter, wie bist du denn drauf?
-
Die Definition von Stringliteralen ist im Standard nicht ganz sauber. Das sieht man am besten wohl in 6.4.5 (7):
ISO/IEC 9899:1999 6.4.5: String Literals, Absatz 7 schrieb:
EXAMPLE This pair of adjacent character string literals
"\x12" "3"
produces a single character string literal containing the two characters whose values are '\x12' and '3', because escape sequences are converted into single members of the execution character set just prior to adjacent string literal concatenation.
Da wird der Begriff "character string literal" sowohl für die Einzelliterale (wie in Absatz 2 beschrieben) als auch für das Ergebnis ihrer Verbindung benutzt, was m.E. etwas unglücklich ist.
Richtig ist allerdings, dass Zeiger nicht auf String-Literale zeigen, sondern auf aus ihnen erzeugte Zeichensequenzen. In Absatz 5 heißt es:
ISO/IEC 9899:1999 6.4.5 (5) schrieb:
In translation phase 7, a byte or code of value zero is appended to each multibyte character sequence that results from a string literal or literals.65) The multibyte character sequence is then used to initialize an array of static storage duration and length just sufficient to contain the sequence. (...)
65) A character string literal need not be a string (see 7.1.1), because a null character may be embedded in it by a \0 escape sequence.
und später:
ISO/IEC 9899:1999 6.7.8 (32) schrieb:
(...) On the other hand, the declaration
char *p = "abc";
defines p with type ‘‘pointer to char’’ and initializes it to point to an object with type ‘‘array of char’’ with length 4 whose elements are initialized with a character string literal. If an attempt is made to use p to modify the contents of the array, the behavior is undefined.
...was auf unseren Fall hier direkt anwendbar ist.
Allerdings: diese Nomenklatur wird nicht überall konsequent durchgehalten. Zum Beispiel:
ISO/IEC 9899:1999 schrieb:
An array of character type may be initialized by a character string literal, optionally enclosed in braces. Successive characters of the character string literal (including the terminating null character if there is room or if the array is of unknown size) initialize the elements of the array.
Da klingt das so, als sei der in 6.4.5 (5) eingefügte Terminator Teil des Stringliterals, was sich natürlich mit der Definition von String-Literalen in 6.4.5 (7) beißt.
Insgesamt ist es wohl richtig, zu sagen, dass Literale zur Laufzeit nicht mehr existieren (sondern halt nur die aus ihnen erzeugten Objekte), aber was ein Stringliteral während der Kompilation genau ist, ist nicht trivial zu beantworten. Auch ist die Ausdrucksweise, ein Zeiger zeige auf ein String-Literal, durchaus üblich. Sie mag nicht ganz korrekt sein, aber in der Praxis ist sie ausreichend präzise, und ich habe noch keine genauere Ausdrucksweise gehört, die nicht auch ziemlich klobig ist.
@Wutz: Ich vermute, dass mein Appell auf taube Ohren stoßen wird, aber bitte: Bevor du das nächste man jemanden als lesefaulen und gedankenlosen Querulanten beschimpfst, weil er mit deiner Meinung nicht übereinstimmt, mach dir die Mühe zu prüfen, ob diese auch korrekt ist. Es ist in dieser Sache keine Schande, sich geirrt zu haben - es geht ja nur um eine Formalie - aber wenn man sich derart im Ton vergreift und dann auch noch falsch liegt, muss einem das schon ziemlich peinlich sein.
-
seldon schrieb:
Die Definition von Stringliteralen ist im Standard nicht ganz sauber.
So wie es ausschaut, ist im Sinne des ISO-Dokuments ein Stringliteral einerseits eine in "" eingeschlossene Zeichenkette, bzw. das Resultat einer Verkettung von Strings (durch aneinanderhängen, oder durch den Präprozessor) pro Übersetzungseinheit, andererseits ein konstantes Objekt im Speicher, das aus einer Folge von "chars" inklusive Nullterminator besteht. Zweifellos schlecht definiert, aber IMHO auch nicht so widersprüchlich, dass es problematisch ist.
Btw, übrigens danke für deine Unterstützung. User Wutz erkannte den Fehler in seiner Argumentation, konnte ihn aber nicht eingestehen und wertete mein Nachbohren als Angriff auf seine Kompetenz. Seine zickige Reaktion überraschte mich schon ein wenig, aber letztlich ist sowas wurscht.
-
Hey, schön das ihr euch soviele Gedanken drüber macht. Vielen Dank. Ich verstehe davon allerdings nicht soviel. Die Lösung für mein Problem sieht aber wie folgt aus:
void ConvertNamen(char * PtrNamPtrArr[], int NamAnz) { //************************************************************************** // ConvertNamen - Namen in korrekte Schreibweise umwandeln //************************************************************************** int len = 0; char * temp; for(int i=0; i <= NamAnz-1; i++) { len = strlen(PtrNamPtrArr[i]); temp = strdup(PtrNamPtrArr[i]); for(int kar=0; kar <= len; kar++) { if(kar == 0) temp[kar] = toupper(PtrNamPtrArr[i][kar]); else if(PtrNamPtrArr[i][kar-1] == *" " || PtrNamPtrArr[i][kar-1] == *"-") temp[kar] = toupper(PtrNamPtrArr[i][kar]); else temp[kar] = tolower(PtrNamPtrArr[i][kar]); } PtrNamPtrArr[i] = temp; } }//ConvertNamen
-
Ist immer noch ziemlich falsch
- unnötig C99
- umständlichfor(int i=0; i <= NamAnz-1; i++)
stattfor(int i=0; i < NamAnz; i++)
- strdup ist kein C Standard
- signed/unsigned char-Problematik bei toupper nicht erkannt
- *" " habe ich auch lange nicht gesehenfor(int kar=0; kar <= len; kar++)
läuft zu weit
- Memoryleak (wahrscheinlich), strdup ohne free
- schlechtes Design, statt Funktionalität "toupper für einen Gesamtstring" zu kapseln und für jeden String 1x aufzurufen, machst du das detailliert in der Schleife, was prompt natürlich zu unübersichtlichem Code und Fehlern führt
- ...