NEWBIE: Kleines Problem mit Lernsourcecode

Hi,
bei untenstehendem Source das Problem, dass beim Ausführen ein „Segmentaion fault“ kommt.

  1. Aus anderen kleinen Programmen weiss ich, dass ich dann mal wieder Mist mit den Zeigern gemacht habe, aber WAS heisst das jetzt genau?

  2. Schlagt mich bitte nicht, wenn ich wieder einen banalen Fehler gemacht habe :wink:

Hier der Source:
#include
/* #include */

void upperCase(char *pS)
{
printf(„bin in uppercase \n“);
while(*pS)
{
if(islower(*pS))
{
printf(„jetzt kommt *ps = toupper(*pS); \n“);
*pS= toupper(*pS);
printf(„fertig!\n“);
}
pS++;
}
}

void fn()
{
char *pString;
printf(„Bin in fn()\n“);
pString = „Davis“;
printf(„Jetzt kommt upperCase\n“);
upperCase(pString);
}

int main()
{
fn();
return 0;
}

Ach ja: Kompiliert habe ich das Ding unter einem RedHat 7.3 mit dem gcc…

Und noch was: Kennt ihr nen kleinen Konverter mit dem ich Linux und Windows Dateien ins jeweilige andere Betriebssystemformat konvertieren kann(also, dass ich unter win die sourcen z.B. notdürftig auch mit notepad ansehen kann, ohne mich durch einen Buchstabensalat zu zwängen?

Danke im Voraus,
Leon

Hi,
du nutzt einen Zeiger *char, für den String wird aber nirgendwo Platz reserviert, das heisst die Print-Anweisung schreibt wild in den Speicherbereich. Heutzutage nutzt man das *char eigentlich nicht mehr, es gibt da wesentlich bessere Objekte, z.B. String(), dann hast du auch später mit dem Typcasten weniger Probleme.

Wenn du den WindowsCommander (Heute TotalCommander) nutzt, da kannst du sowohl über Menüpunkte konvertieren als auch im Editor die Ansicht auf Windows/Unix schalten…

Ralph

Hi,
du nutzt einen Zeiger *char, für den String wird aber
nirgendwo Platz reserviert, das heisst die Print-Anweisung
schreibt wild in den Speicherbereich. Heutzutage nutzt man das
*char eigentlich nicht mehr, es gibt da wesentlich bessere
Objekte, z.B. String(), dann hast du auch später mit dem
Typcasten weniger Probleme.

Meinst du folgende Stelle? :
[…]
char *pString;
[…]
pString = „Davis“;
[…]
hast du ein Beispiel für mich mit string() ? das klingt interessant…

Wenn du den WindowsCommander (Heute TotalCommander) nutzt, da
kannst du sowohl über Menüpunkte konvertieren als auch im
Editor die Ansicht auf Windows/Unix schalten…

danke, gibts den auch als shareware oder freeware?

danke, leon

JAIN
Hallo leon,

*pS= toupper(*pS); // hier ist das Problem !!!
[…]

[…]
char *pString;
[…]
pString = „Davis“;
[…]

„Davis“ ist eine String-Konstante welche in einem Speicher-Bereich abgelegt wird, welcher nicht verändert werden darf/sollte. Manche Compiler nehmen das nicht so genau und dein Code funktioniert Fehlerfrei, aber wenn du das Ganze in einem ROM ablegen willst !!!

Mit „*pS= toupper(*pS);“ soll nun in diesen Bereich geschrieben werden und das ist halt verboten !!

Im Klassischen Speicher-Model gibt es die Segmente „TEXT“, „DATA“ und „CONST“.
In „TEXT“ ist der eigentliche Code abgelegt.
In „DATA“ die Daten (Variablen).
Und in „CONST“ halt alle Konstanten.

Da du jetzt in „CONST“ schreiben willst, was ja nicht erlaubt ist, bekommst du den Hinweis auf das falsche Segment (zum schreiben).

Alles klar jetzt ??

MfG Peter(TOO)

Ich beginne zu ahnen/hoffen:

Ich schreibe in einen Zeiger, dem keine Variable zugewiesen wurde, dieses „Davis“. Das schon mal ist eigentlich grausam(wenn ich dich richtig verstehe und mein Verstand mir das so sagt).
Wenn ich jetzt versuche in diesen nicht initalisierten Zeiger zu schreiben, meint Linux: "Vorsicht, das könnte über den Speicher hinausgehen, den „Davis belegt“.

Oder ist „Davis“ nicht veränderbar, weil halt am Anfang zugewiesen wurde und jetzt halt das so ist?

Ginge es denn auch so?:
char string[10] = „Davis“;
char *pSring = &string[0];
toupper(*pString)

Sorry für meine Begriffstutzigkeit…bin halt wirklich nur Newbie, der sowas überhaupt nicht in seinen C-Büchern gelesen hat(ist jetzt das Buch grottenschlecht oder ich zu blöd?)

Gruß, Leon

Huhu :smile:

Das Problem in deinem Code liegt hier:

void fn()
{
 char \*pString;
 ...
 pString = "Davis";
 ...
 upperCase(pString);
}

Du weist dem char-Zeiger pString die Adresse der Zeichenkonstante „Davis“ zu. Da du Konstanten aber nicht verändern kannst, gibt es in der Funktion upperCase einen Fehler. Aktiviere am besten alle Warnungen von deinem Compiler. Der merkt nämlich, wenn du ein (const char *const) an ein (char *) zuweisen möchtest und kann dich auf den möglichen Fehler hinweisen …

Versuch’s mal so:

void fn()
{
 char pString[6]= "Davis";
 ...
 upperCase(pString);
}

Jetzt weist du den Compiler an, die String-Konstante „Davis“ in das Array pString zu kopieren. Und auf dieser Kopie kannst du dann arbeiten. Die 6 steht da nur, um zu verdeutlichen, dass das Array pString aus 6 Zeichen besteht: ‚D‘,‚a‘,‚v‘,‚i‘,‚s‘,’\0’. Wenn du die 6 weglässt, bestimmt der Compiler die Länge automatisch.

Viele Grüße

Stefan.

hi leon,

Ich schreibe in einen Zeiger, dem keine Variable zugewiesen
wurde, dieses „Davis“.

nicht ganz korrekt. du initialisierst mit
char *bla;
einen zeiger. zeiger haben die eigenschaft selber keinen speicherplatz fuer werte zu haben. das bedeutet in dem zeiger selber ist lediglich eine adresse gespeichert, und zwar eine adresse in deinem arbeitsspeicher. PROBLEM: noch ist der zeiger niicht initialisiert. d.h. er zeigt *irgendwohin* in deinem speicher. wenn du diesen zeiger benutzen moechtest musst du zunaechst mal speicher freigeben. also: den zeiger auf eine adresse richten in den du ohne problem schreiben kannst. wenn du das nicht tust, ist es nun moeglich irgeneinen schmarrn in den speicher zu schreiben der u.U. von einem anderen variablen benutzt wird. und das ist fuer die andere variable bloed, denn da wuerde ja dann nur noch scheisse drin stehen. also: speicher freigeben. mit dem good old c macht man das mittels der funktion malloc();
bla = (char *) malloc (20*sizeof char);
so jetzt hast du deinen zeiger ausgerichtet und speicher freigegeben.
und jetzt kannst du den freigegebenen speicher auch nutzen.
ich muss dich hier an dieserstelle vor der funktion malloc() ausdruecklich warnen. sie ist sehr sensibel in der handhabung.

hier ist ein sehr cooles script wenn du c lernen moechtest, und ein wenig m,ehr darueber wissen moechtest, ohne gleich imens geld auszugeben.
http://www.haw-hamburg.de/rzbt/dankert/

Wenn ich jetzt versuche in diesen nicht initalisierten Zeiger
zu schreiben, meint Linux: "Vorsicht, das könnte über den
Speicher hinausgehen, den „Davis belegt“.

nein, das koennte ueber den speicher hinausgehen, den dein zeiger zur verfuegung hat, da der zeiger nicht initialisiert wurde.

Oder ist „Davis“ nicht veränderbar, weil halt am Anfang
zugewiesen wurde und jetzt halt das so ist?

„Davis“ ist nicht das problem, dein zeiger hat einfach „keinen PLatz“ um Davis zu speichern!!
siehe oben malloc()

Ginge es denn auch so?:
char string[10] = „Davis“;
char *pSring = &string[0];
toupper(*pString)

koennte klappen, da du ja den zeiger auf diesen schon initialisierten speicher setzt. aber vorsicht:
toupper ist eine funktion anwendest.
in deinem string steht „Davis“ besser ist es wenn du das abschliessende"\0" hinten anfuegst, also: „Davis\0“

Sorry für meine Begriffstutzigkeit…bin halt wirklich nur
Newbie, der sowas überhaupt nicht in seinen C-Büchern gelesen
hat(ist jetzt das Buch grottenschlecht oder ich zu blöd?)

jeder faengt mal an. kein nerd ohne newb :wink: der ich im uebrigen auch nur bin, wenn ich mir die gigantische welt des c++ ansehe!!

gruß josh

Hallo Leon,

Ich schreibe in einen Zeiger, dem keine Variable zugewiesen
wurde, dieses „Davis“. Das schon mal ist eigentlich
grausam(wenn ich dich richtig verstehe und mein Verstand mir
das so sagt).
Wenn ich jetzt versuche in diesen nicht initalisierten Zeiger
zu schreiben, meint Linux: "Vorsicht, das könnte über den
Speicher hinausgehen, den „Davis belegt“.

Du bringst da noch einiges durcheinander, also fangen wir mal klein an:
char c1;
char c2 = ‚A‘;
static char c3;

void f(void)
{
char c4;
char c5 = ‚B‘;
static char c6;
}

c1-c3 werden im DATA-Segment abgelegt. Bein Programm-Start wird dieser Speicherbereich mit Nullen gefüllt, bzw. mit dem Initialisierungs-Wert.
Also: c1 und c3 enthalten 0x00; und c2 den Wert 0x41. „static“ bei c3 bewirkt hier nur, dass „c3“ ausserhalb des Moduls nicht sichtbar ist.

c4 und c5 werden auf dem Stack abgelegt und liegen deshalb bei jedem Aufruf von f() an einer anderen Speicheradresse. C5 wird bei jedem Aufruf mit dem Wert 0x41 „gefüllt“ wohingegen der Wert von c4 zufällig ist, je nachdem was da vorher an diese Speicherstelle geschrieben wurde.
Bei c6 bewirkt „static“, dass der Speicherplatz für diese Variable NICHT auf dem Stack angelegt wird, sondern im DATA-Segment. Dadurch bleibt der Wert von c6 auch nach dem verlassen von f() weiter erhalten.

Oder ist „Davis“ nicht veränderbar, weil halt am Anfang
zugewiesen wurde und jetzt halt das so ist?

„Davis“ (0x44, 0x61, 0x76, 0x69, 0x73, 0x00) wird im CONST-Segment abgelegt. Dieses ist schreibgeschützt.
Eine Zeigervariable (z.B. char *pstr) enthält nur die Speicher-ADRESSE unter welcher „Davis“ abgelegt wurde.
Also mit pstr = „Davis“ wird nur die Speicher-Adresse unter welcher „Davis“ abgelegt wurde in pstr abgelegt. pstr ist keineswegs uninitialisiert, aber zeigt auf einen schreibgeschüzten Speicher-Bereich.

Ginge es denn auch so?:
char string[10] = „Davis“;
char *pS t ring = &string[0];
toupper(*pString)

Ja, weil jetzt „Davis“ nach string[10] KOPIERT wird.

Sorry für meine Begriffstutzigkeit…bin halt wirklich nur
Newbie, der sowas überhaupt nicht in seinen C-Büchern gelesen
hat(ist jetzt das Buch grottenschlecht oder ich zu blöd?)

Auch ich habe mal angefangen und hatte damals so meine Probleme…

MfG Peter(TOO)

fehlerkorrektur
muss lauten:

bla = (char *) malloc (20*sizeof (char) );

Hallo josh,

nicht ganz korrekt. du initialisierst mit
char *bla;
einen zeiger. zeiger haben die eigenschaft selber keinen
speicherplatz fuer werte zu haben. das bedeutet in dem zeiger
selber ist lediglich eine adresse gespeichert, und zwar eine
adresse in deinem arbeitsspeicher. PROBLEM: noch ist der
zeiger niicht initialisiert. d.h. er zeigt *irgendwohin* in
deinem speicher. wenn du diesen zeiger benutzen moechtest
musst du zunaechst mal speicher freigeben. also: den zeiger
auf eine adresse richten in den du ohne problem schreiben
kannst. wenn du das nicht tust, ist es nun moeglich irgeneinen
schmarrn in den speicher zu schreiben der u.U. von einem
anderen variablen benutzt wird. und das ist fuer die andere
variable bloed, denn da wuerde ja dann nur noch scheisse drin
stehen. also: speicher freigeben. mit dem good old c macht man
das mittels der funktion malloc();
bla = (char *) malloc (20*sizeof char);
so jetzt hast du deinen zeiger ausgerichtet und speicher
freigegeben.
und jetzt kannst du den freigegebenen speicher auch nutzen.
ich muss dich hier an dieserstelle vor der funktion malloc()
ausdruecklich warnen. sie ist sehr sensibel in der handhabung.

„Speicher freigeben“ ist kompletter UNSINN. Was du meinst ist Speicher ALLOZIEREN (belegen), deswegen heisst die Funktion auch alloc() und nicht free(), mit welcher man den allozierten Speicher wieder frei gibt.

in deinem string steht „Davis“ besser ist es wenn du das
abschliessende"\0" hinten anfuegst, also: „Davis\0“

Alles was in " gestellt wird ist ein String und das ‚\0‘ wird AUTOMATISCH vom Compiler angehängt !!!

MfG Peter(TOO)

Hallo josh,

bla = (char *) malloc (20*sizeof char);
so jetzt hast du deinen zeiger ausgerichtet und speicher
freigegeben.
und jetzt kannst du den freigegebenen speicher auch nutzen.
ich muss dich hier an dieserstelle vor der funktion malloc()
ausdruecklich warnen. sie ist sehr sensibel in der handhabung.

„Speicher freigeben“ ist kompletter UNSINN. Was du meinst ist
Speicher ALLOZIEREN (belegen), deswegen heisst die Funktion
auch alloc() und nicht free(), mit welcher man den
allozierten Speicher wieder frei gibt.

hmm, naja ich dachte bei speicher freeigeben nicht an free tatsache ein versprecher…aber allokieren hoert sich fuer einen anfaenger meist nach fachchinesisch an…daher habe ich mich fuer freigeben entschieden. aber du hast recht. ich schaeme mich…

in deinem string steht „Davis“ besser ist es wenn du das
abschliessende"\0" hinten anfuegst, also: „Davis\0“

Alles was in " gestellt wird ist ein String und das ‚\0‘ wird
AUTOMATISCH vom Compiler angehängt !!!

hmm, auf welchem system arbeitest denn du. wenn ich unter unix arbeite und etwas vom typ CHAR initialisiere haengt mir niemand eine „\0“ dran. ausserdem hatte meine abschliessende „\0“ den gedanken dahinter jemanden ein wenig in die kleinen kniffe des debuggens zu fuehren. schliesslich habe ich in meinen c anfangszeiten viele lange stunden damit verbracht rauszufinden was ein segmentation fault ist, verursacht durch ein fehlendes „\0“ dahinter. und ich denke das ich hierbei wohl viele anspreche, die mit denselben problemen zu kaempfen hatten.

mit freundlichem gruß

josh

Hallo josh,

Alles was in " gestellt wird ist ein String und das ‚\0‘ wird
AUTOMATISCH vom Compiler angehängt !!!

hmm, auf welchem system arbeitest denn du. wenn ich unter unix
arbeite und etwas vom typ CHAR initialisiere haengt mir
niemand eine „\0“ dran. ausserdem hatte meine abschliessende
„\0“ den gedanken dahinter jemanden ein wenig in die kleinen
kniffe des debuggens zu fuehren. schliesslich habe ich in
meinen c anfangszeiten viele lange stunden damit verbracht
rauszufinden was ein segmentation fault ist, verursacht durch
ein fehlendes „\0“ dahinter. und ich denke das ich hierbei
wohl viele anspreche, die mit denselben problemen zu kaempfen
hatten.

Die STRING-Konstante „Davis“ wird im Speicher (ASCII-Code) als 0x44, 0x61, 0x76, 0x69, 0x73, 0x00 im Speicher abgelegt, das steht schon in den ersten Ausgaben von K&R so drin.
Und alle meine C-Compiler halten sich, seit 20 Jahren, daran.

MfG Peter(TOO)
P.S. Wie lange schreibst du schon C ??

Danke erstmal
So, den Thread muss ich jetzt erst mal verdauen. So beim überfliegen schien mirs klarer geworden sein…
Ich drucke mir den Thread gerade aus und nehme mir den mal als Lektüre vor. Wenn ichs dann immer noch nicht verstehe ist mir wahrscheinlich nicht mehr zu helfen, aber ich frage dann trotzdem noch mal :wink:

Also, vielen Dank bis jetzt,

Leon

hi peter,

Alles was in " gestellt wird ist ein String und das ‚\0‘ wird
AUTOMATISCH vom Compiler angehängt !!!

jepp

P.S. Wie lange schreibst du schon C ??

seit 3 jahren, was natuerlich gegen 20 jahre nicht mithalten kann.

oje, jetzt sind wir aber ganz schoen vom eigentlichen thema abgeschwiffen, nicht?
aber sehr schoen zu wissen, das ich bei meinem naechsten prolem einen ansprechpartner habe…der sich damit auskennt…

mfg josh