hi there~
hab vor ner woche mit C angefangen und bin gleich schon an meine grenzen
gestossen Oo
waere echt lieb wenn mich jmd zu der loesung meines problems fuehren
koennte.
ziel des progs ist es einen buchstaben durch einen anderen zu ersetzen.
mein problem, das programm ignoriert quasi meine zeile 23. wenn ich fuer
die funktion 'tausch' 'b' als eine konstante benutze funktioniert es
wie es soll. hier der code
1
#include<stdio.h>
2
#include<string.h>
3
4
#define MAX 80
5
6
voidtausch(char*s,charalt,charneu){
7
while(*s){
8
if(*s==alt)
9
*s=neu;
10
*s++;
11
}
12
}
13
14
main(){
15
chartext[MAX];
16
chara;
17
charb;
18
printf("\nText her : ");
19
gets(text);
20
printf("\nwelcher buchstabe soll ersetz werden ? : ");
Das Problem ist, wenn du nur ein Zeichen eingibtst und danach Enter
drückst, dass in b '\n' gespeichert wird. Gib zwei Zeichen
hintereinander ein und drück erst danach Enter. Nun sollte dein Programm
wie gewünscht funktionieren (habs nicht getestet).
Das selbe Problem hatten wir erst vor Kurzem hier. Da findest du auch
gleich eine bessere Alternative für gets:
Beitrag "Wann Tastaturpuffer mit fflush(stdin); löschen?"
danke, dass mit dem ersetzen klappt auch. habe aber in meinem code
scanf("%c",&a); ohne %1c die '1' dazwischen gehabt.
kannst du mir bitte die '1' erklären und auch noch warum dein code noch
funktioniert ? (also was '%*c' bedeutet?)
hab auch in dem anderen thread gesehen, dass eine leerstelle in der
23ten zeile vor %c funktioniert ... und weiss nich warum :o
Schau mal da:
http://www.cplusplus.com/reference/cstdio/scanf/
unter "sub-specifier":
"An optional starting asterisk indicates that the data is to be read
from the stream but ignored (i.e. it is not stored in the location
pointed by an argument)."
und das mit der 1 :
"width" "Specifies the maximum number of characters to be read in the
current reading operation (optional)."
Das mit dem Leerzeichen ist hier erklaert:
Beitrag "Re: Wann Tastaturpuffer mit fflush(stdin); löschen?"
"Das Leerzeichen bedeutet: "Überlese alle Whitespace""
Du hast zwar eine Test-Ausgabe deiner Eingabe gemacht (das vergessen
Viele), konntest aber nicht ergkennen, das da ein \n drin steckt.
Das kannst du besser sehen, wenn du die Ausgabe zwischen Sonderzeichen
einbettest. Z.B <>
1
printf("\nAlso <%c> durch <%c> in <%s>\n",a,b,text);
Wenn du dann die Ausgabe
Also <a> durch <
> in <Hallo>
in zwei Zeilen hast, siehst du das Problem.
Auch wenn du mal fgets statt gets nimmst, ist da das \n mit drin.
danke euch allen für die loesung/tipps.
natuerlich habe ich nun ein weiteres problem :p
hab das program ein bisschen erweitert und bekomme nun bei der eingabe
für 'text' ein richtiges ergebniss, wenn ich genau elf zeichen eingebe.
bei einem zeichen gehts auch. aber bei z.B. zehn zeichen bekomme ich ein
zeichen, dass wahrscheinlich grad im speicher war. und ich weiss nit
warum Oo
#include <stdio.h>
const int MAX = 80;
void tausche(char *eingabe, char *ausgabe, char alt, char neu){
while(*eingabe){
if (*eingabe == alt)
*ausgabe = neu;
else
*ausgabe = *eingabe;
*eingabe++;
*ausgabe++;
}
}
main(){
char text[MAX];
char text2[MAX];
char a,b ;
printf("\nGibt Text : ");
gets(text);
printf("\n\nWelcher Buchstabe soll ersetzt werden ? : ");
scanf("%c",&a);
printf("\n\nDurch welchen Buchstaben ersetzen ? : ");
scanf(" %c",&b);
printf("\n\nalso in <%s> soll <%c> durch <%c> ersetzt
werden.",text,a,b);
tausche(text,text2,a,b);
printf("\n\n\n%s",text2);
}
Peter Schol schrieb:> *eingabe++;> *ausgabe++;
ist zwar kein Fehler, aber verwirrend,
schreib bitte einfach
eingabe++;
ausgabe++;
denn du willst die Zeiger erhöhen, der Inhalt ist irrelevant
Peter Schol schrieb:> void tausche(char *eingabe, char *ausgabe, char alt, char neu){> while(*eingabe){> if (*eingabe == alt)> *ausgabe = neu;> else> *ausgabe = *eingabe;> *eingabe++;> *ausgabe++;> }> }
Hier tust du zwar korrekt die Schleife abbrechen, wenn die 'eingabe' zu
Ende ist, aber du vergisst, in der 'ausgabe' das Ende des Strings zu
markieren. Daher zeigt dein printf den Ramsch, der halt grade da im
Speicher liegt.
ja klar !
wenn ich das verstanden habe, bekommt 'eingabe' die '\o' durch die
funktion 'gets()' already mit.
aber 'ausgabe' braucht ja auch noch an der richtigen stelle am speicher
ein ende ..... hmm mal guggn wie ich das hinbekomme.
ihr hoert von mir :-)
Peter Schol schrieb:> hmm mal guggn wie ich das hinbekomme.
Überleg mal, auf welche Position der Zeiger ausgabe (am Ende der
Schleife) zeigt, wenn eingabe auf die '\0' zeigt?
Dirk B. schrieb:> Gib doch mal den Wert von pos in tausche aus.> Auch mal bei verschiedenen Längen der Eingaben.
der wert von pos ist == 0. soll ja auch so sein um der funktion printf
zu sagen, dass sie aufhoeren soll den speicher auszulesen. wenn ich das
richtig verstanden habe ... :o
tests haben das auch bestaetigt, egal wie lang die eingabe ist pos == 0.
W. M. schrieb:> fueg mal vor>> printf("\nGibt Text : ");>>> memset (text, 0, 80);> memset (text2, 0, 80);>> ein.>>> http://www.cplusplus.com/reference/cstring/memset/
auch das funktioniert. bin mir aber leider nicht sicher warum Oo. wenn
statt der 80 hinten eine variable mit dem inhalt von strlen(text)
staende koennte ich mir denken wieso memset an der richtigen stelle ein
'\0' setzt. aber so mit der 80 ....
hab da wieder ein neues problem -.- eine loesung habe ich schon im netz
gefunden, werd sie gleich mal probieren.
nun aber zu meinem loesungsweg, der kein/ein falsches ergebnis bringt.
kann mir bitte jmd erklaeren, warum ich eine leere zeile als ergebnis
bekomme ?
#include <stdio.h>
#include <string.h>
const int MAX = 80;
void reverse(char *eingabe, char *ausgabe){
char hilf[MAX];
char hilf2[MAX];
int i=0;
int x=0;
int y;
memset (hilf, 0, 80);
memset (hilf2, 0, 80);
while (*eingabe){
hilf[i] = *eingabe;
eingabe++;
i++;
}
y = strlen(hilf);
printf("\n%i",y);
for (i = strlen(hilf); i<=0; i--){
hilf2[x] = hilf[i];
x++;
}
strcpy (ausgabe,hilf2);
}
main(){
char text[MAX];
char text2[MAX];
puts("\ngib Text : \n");
memset (text, 0, 80);
memset (text2, 0, 80);
gets(text);
reverse(text,text2);
printf("\n%s",text2);
}
Merke: strlen gibt zwar die Länge vom String aus, aber Du darfst das
Ende des Strings nicht mit dem Wert von strlen indexen. Die Array fangen
immer mit dem Index 0 an. Somit greifst Du beim ersten kopieren auf ein,
in deinem Fall, NULL-Byte zu und daher ist Deine Ausgabe ein leeres
Ergebnis!
Da ein NULL-Byte das Ende eines Strings definiert.
Beispiel: Eingabe von 1234. Strlen gibt Dir eine Länge von 4. Ok.
Aber, der String beginnt bei Index 0 und geht bis Index 3.
Ich hoffe, dass dies verständlich war. Den Fehler macht jeder einmal.
Peter Schol schrieb:> der wert von pos ist == 0. soll ja auch so sein um der funktion printf> zu sagen, dass sie aufhoeren soll den speicher auszulesen. wenn ich das> richtig verstanden habe ... :o
Leider falsch verstanden. pos ist ja die Länge vom String. Also der
Abstand der '\0' vom Anfang. Und der ist bei dir immer 0, weil du
eingabe solang weitergezählt hast (durch das ++), dass er jetzt auf
die '\0' zeigt.
Da pos immer 0 ist, egal was du eingibst, kannst du auf das strlen
verzichten.
Da du ausgabe auch immer weiter gezählt hast, steht es am Ende der
Schleife da, wo die '\0' hin gehört. Daher reicht ein
Peter Schol schrieb:> der kein/ein falsches ergebnis bringt.> kann mir bitte jmd erklaeren, warum ich eine leere zeile als ergebnis> bekomme ?
Fast das gleiche Problem, aber in diesem Fall kopierst du die '\0' vom
Ende ganz an den Anfang.
Daher sieht es so aus, dass der String leer ist.
Versuch mal auf hilf und hilf2 (als Arrays) zu verzichten.
Ist nicht schwer.
erstmal vielen Dank fuer eure vorschlaege und erklaerungen. denke ich
habe einiges gelernt.
ich probiere mal die hilfs arrays weg zu lassen. bin leider vorbelastet,
weil ich im netz schon ne loesung gefunden habe ohne die hilfs arrays.
da kommt allerdings eine for schleife :
for ( c = 0 ; c < ( length - 1 ) ; c++ )
end++;
vor, die ich nicht verstehe.
ich poste mal das ganze prog. vielleicht hat ja jmd lust mir auch noch
die andere for schleife in der funktion zu erklaeren. da kapier ich das
length/2 einfach nicht-.-
#include <stdio.h>
#include <string.h>
void reverse(char*);
main()
{
char string[100];
printf("Enter a string\n");
gets(string);
reverse(string);
printf("Reverse of entered string is \"%s\".\n", string);
return 0;
}
void reverse(char *string)
{
int length, c;
char *begin, *end, temp;
length = strlen(string);
begin = string;
end = string;
for ( c = 0 ; c < ( length - 1 ) ; c++ )
end++;
for ( c = 0 ; c < length/2 ; c++ )
{
temp = *end;
*end = *begin;
*begin = temp;
begin++;
end--;
}
}
kanns in etwa nachvollziehen, aber verstehe halt nicht jeden schritt Oo
Dirk B. schrieb:> Versuch mal auf hilf und hilf2 (als Arrays) zu verzichten.> Ist nicht schwer.
habe aber absichtlich nicht den original text uebrschreiben wollen um
ggfs spaeter noch mal drauf zu greifen zu koennen.
aber ich probier mal mehr mit zeigern zu arbeiten und die hilfs arrays
weg zu lassen (darum gehts mir ja hier, die zeiger richtig zu verstehen)
und trotzdem den original text un beruehrt zu lassen :)
Die Scheife mit length-1 soll den Zeiger end solange hochzählen, bis er
vor der '\0' steht.
Das ist doof gelöst, da ein
1
end+=length-1
statt der Schleife das genauso macht.
Die Schleife ist da halt im strlen versteckt.
Man kann auch auf das strlen verzichten, dann muss man das Ende halt
selber suchen.
Tja, und mit dem length/2 tauscht du nur bis zur Mitte.
Wenn du weiter machst, tauscht du wieder zurück.
0. 01234 // Anfang Länge ist 5
1. 41230 // tausche 0 mit 4
2. 43210 // tausche 1 mit 3 -> fertig
3. 43210 // tausche 2 mit 2
4. 41230 // tausche 3 mit 1
5. 01234 // tausche 4 mit 0
Die letzte Schleife kannst du auch so machen:
Ach, vergessen: Die '\0' fehlt wieder am Ende.
Die solltest du vor der Tausch-Schleife setzen, da du da ja den Zeiger
auf das Ende schon hast (+/-1).
Deine Funktion tauscht den String in sich selbst.
Das geht nur gut, wenn der String nicht const ist.
Bei einem Array geht das, aber nicht bei einem Stringliteral (Text
zwischen "")
Wenn du
1
reverse("Hallo Welt!");
kann es funktionieren, muss aber nicht.
Das ist abhängig vom System und Compiler.
Das nächste ist die Signatur der Funktion.
Wenn du dir mal die Standardfunktionen strcpy oder strcat ansiehst,
wirst du sehen, dass das Ziel als erster Parameter angegeben wurde.
Das soll dann so wie bei Ziel = Quelle aussehen.
Zudem wird das Ziel auch noch als Rückgabewert der Funktion genutzt.
Dann kann man die Funktion gleich weiter benutzen.
1
printf("Reverse of entered string is \"%s\".\n",reverse(string));
Peter Schol schrieb:> glaub ich muss mir die for schleife nochmal genau angucken.> die kann ja viel mehr als ich bisher dachte :-)
1
for(A;B;C)D;
Naja, die kann vor der Schleife etwas ausführen (A), hat eine
Schleifenbedingung (B) und macht etwas nach dem Schleifendurchgang (D)
und vor der nächsten Prüfung (C)
Es geht auch als while. Dann hast du
1
A;
2
while(B){
3
D;
4
C;
5
}
Was bei A, B, C, D steht ist nicht festgelegt.
Du kannst A und C bei for auch weglassen (aber nicht die ; )
Meist nimmt man for für Schleifen, die eine feste Anzahl von Durchläufen
haben und while, wo die Abbruchbedingung berechnet wird oder von Aussen
(Benutzer, Datei) beeinflußt wird. Meist, muss aber nicht.
Der Unterschied zwischen while und for ist nur die Sichtbarkeit der
Variablen, die evtl. bei A definiert wird.
BattMan schrieb:> Ein kleine Idee, wie man es auch realisieren könnte.
Und welchen Vorteil hat das gegenüber dem direkten Tausch?
Da kann immerhin kein malloc fehlschlagen.
also wenn ich die original eingabe behalten will, ist mein loesungsweg
mit hilf und hilf2 gut ? also effizient ?
oder kann man da noch was besser machen... ist immerhin ne menge text
fuer so ein bisschen resultat :).
Peter Schol schrieb:> also wenn ich die original eingabe behalten will, ist mein loesungsweg> mit hilf und hilf2 gut ? also effizient ?
Nein. Weder gut (zwei Hilfsfelder und du bist auf MAX Zeichen begrenzt)
noch effizient (du gehst viermal (mit strlen und strcpy) über die
Zeichen).
Erste Schleife: Ende finden (meinetwegen auch mit strlen)
Zweite Schleife: rückwärts kopieren (Quelle->Ziel) oder tauschen (in
place)
Dann wird der Text auch kürzer. :-)
printf("\nDie Eingabe besteht aus <%i> Zeichen.",y);
15
16
while(*eingabe){
17
hilf[x]=*eingabe;
18
eingabe++;
19
x++;
20
}
21
22
for(y--;y>=0;y--){
23
*ausgabe=hilf[y];
24
ausgabe++;
25
}
26
ausgabe[y+1]='\0';
27
}
28
main(){
29
chartext[MAX];
30
chartext2[MAX];
31
printf("\nText her fuer rueckwaerts : ");
32
gets(text);
33
tausche(text,text2);
34
printf("\n\n%s",text2);
35
}
so MAX ist gewaehlt als const int damit fuer mehr variable der wert an
einer stelle festgelegt werden kann. (nur fuer den fall...)
gibts denn da eine bessere(effizientere) loesung ?
hilf2 bin ich losgeworden da eh unsinn. hast recht :p
was waere denn eine alternative fuer strlen ?
was ich /*noch*/ nicht verstehe ist, wenn ich in der for schleife 'y >=0
'eingebe gehts .... bei 'y=0' bekomme ich allderding gruetze.
und 'y>0' gibt mir halt einen zu wenig aus ... ok feld geht ja ab '0'
los. aber bei = 0 ist mist aber bei >= 0 ist richtig ? weiss nich warum.
Du kopierst ja noch immer in einen Hilfsarray. Machst du das, weil du
einen Array-Index verwenden musst, also hilf[y] schreiben musst? Dann
lass dir sagen, dass du das auch auf einen Pointer anwenden kannst:
eingabe[y]. Das hat genau die gleiche Bedeutung wie bei einer als Array
deklarierten Variablen: Nimm den y-ten Wert hinter dem, auf den eingabe
zeigt. Damit wird eine Progrämmchen dann noch etwas kürzer.
Peter Schol schrieb:> was ich /*noch*/ nicht verstehe ist, wenn ich in der for schleife 'y >=0> 'eingebe gehts .... bei 'y=0' bekomme ich allderding gruetze.
Kein Wunder. 'y=0' ist ja auch eine Zuweisung. 'y==0' ist ein Vergleich.
(Ob der hier richtig ist, habe ich mir aber nicht überlegt.) Eine
Zuweisung ist auch ein Ausdruck (daher erlaubt der Compiler, dass du
'for (...; y=0;...) schreibst) und hat ein Ergebnis, nämlich den
zugewiesenen Wert, was in deinem Beispiel Null ist.
Wozu brauchst du eigentlich noch hilf?
Du kopierst da ersmal nur eingabe rein um dann beim umdrehen daraus zu
lesen.
Warum liest du nicht gleich aus eingabe?
Zudem vermischt du die Array und die Pointerschreibweise.
Das macht für die Funktion nichts, da der Compiler selber ein hilf[y] in
ein *(hilf + y) umsetzt, aber es ist schwer zu lesen.
Die for-Schleife wird solange ausgeführt, solange die Bedingung wahr
ist.
y=0 ist eine Zuweisung, deren Ergebnis 0 (unwahr bzw. falsch) ist.
(Das liegt an der 0)
Der Vergleich auf Gleichheit wird in C mit == (zwei Gleichheitszeichen)
ausgedrückt.
Der Compiler sollte dir da allerdings eine Warnung geben (wenn du den
Warnlevel entsprechend gesetzt hast)
Du hattest bemerkt, dass das ja viel Text für so eine einfache Funktion
ist.
1
char*my_strrev_a(char*out,constchar*in)
2
{// string von in nach out in umgekehrter Reihenfolge kopieren
3
// Rückgabewert ist out
4
// Arrayschreibweise
5
6
size_ti,o;
7
size_tlen=strlen(in);
8
9
out[len]='\0';
10
for(i=0,o=len-1;i<len;i++,o--)
11
out[o]=in[i];
12
13
returnout;
14
}
15
16
char*my_strrev_p(char*out,constchar*in)
17
{// string von in nach out in umgekehrter Reihenfolge kopieren
18
// Rückgabewert ist out
19
// Pointerschreibweise
20
21
char*o;
22
o=out+strlen(in);
23
24
*(o--)='\0';
25
while(o>=out)
26
*(o--)=*(in++);
27
28
returnout;
29
}
30
31
char*my_strrev_p3(char*out,constchar*in)
32
{// string von in nach out in umgekehrter Reihenfolge kopieren
erstmal vielen dank fuer eure vorschlaege.
zu tictactoe :
nein ich muss nicht irgendein array benutzen.
im moment jedenfals beschaeftige ich mich mit c aus privaten gruenden.
und ich merk grad, dass ich mich schlecht ausgedrueckt habe.
klar weiss ich (auch wenn ich erst vor zwei wochen mit c angefangen
habe) das ein einfaches = daten zuweist. (hoff ich jedenfals ,dass es
daten zuweist und nicht stellen im register oder so .... saeh sonst
bloed aus zu behaupten, dass ich weiss das daten zugewiesen werden xD
wobei ja daten, wenn ichs verstanden habe auch nur einsen und nullen in
registern sind zur richtigen zeit am richtigen ort abgerufen ...also es
quasi doch nur die stellen mit den einzelnen daten preisgibt also doch
stellen in registern mit daten preisgibt was man dann gleichsetzen kann
mit daten zuweisen ? kA erschlagt mich bitte nicht fuer den text in
klammern. einfach ueberlesen... jetzt ist ja auch zu spaet das zu
schreiben ... naja egal xD ich versuchs halt.)
meinte natuerlich == was ich getestet habe.
mich aergert einfach, dass ich nicht verstehe, warum ein == nur gruetze
gibt aber ein >= das richtige ergenis.
und Dirk
sei bitte nich so streng mit mir :p
wie gesagt, ich habe nicht wirklich viel gelernt. ein buch von Helmut
Erlenkoetter habe ich zur haelfte gelesen und bearbeitet wann immer ich
ne minute zeit hatte.
deswegen ueb ich ja den zeiger kram, um zu verstehen was da wirklich
passiert im rechner. und ich bin dir sehr dankbar fuer deine
erklaerungen und loesungsvorschlaege. (ich versuch extra umlaute zu
meiden um mich dran zu gewoehnen :))
leider hab ich imo keine zeit und kein kopp dafuer mir deine letzen
vorschlaege genau an zu schaun.
evtl morgen oder so hab ich wieder zeit/luft.
also vielen dank euch allen nochmal :-)
Peter Schol schrieb:> meinte natuerlich == was ich getestet habe.> mich aergert einfach, dass ich nicht verstehe, warum ein == nur gruetze> gibt aber ein >= das richtige ergenis.
Die Schleifen in C laufen immer solange die Bedingung wahr ist.
Du fängst mit einem y ungleich 0 an.
Dann wird die Bedingung geprüft y == 0 und das ergibt unwahr.
Daher wird die Schleife nicht ausgeführt.
Und streng wollte ich nicht sein.
Als ich mit C angefangen habe, habe ich auch nichts verstanden.
Und wenn du nicht siehst wie es geht, dann kannst du es schlecht lernen.
Das Buch scheint schon ziemlich alt zu sein.
Du benutzt main() und gets.
Heutzutage schreibt man das int bei main() mit dazu (steht so im
Standard) und gets nimmt man aus Sicherheitsgründen nicht mehr, daher
solltest du es dir nicht angewöhnen.
C läßt den Entwicklern der Compiler einige Freiheiten in der Auslegung
des Standards.
Daher kann es sein, dass Dinge auf deinem Rechner/Compiler laufen, auf
anderen dann aber nicht mehr. Da kann schon eine neue Version vom
Compiler reichen.
Darum muss man bei manchen Sachen sehr genau sein - und das hört sich
dann streng an :-)
Aber das soll dir den Spaß nicht nehmen.
Dirk B. schrieb:> C läßt den Entwicklern der Compiler einige Freiheiten in der Auslegung> des Standards.> Daher kann es sein, dass Dinge auf deinem Rechner/Compiler laufen, auf> anderen dann aber nicht mehr. Da kann schon eine neue Version vom> Compiler reichen.
Aber bitte nicht bei so einfachen Sachen....
Die Grundkontrollstrukturen wie for while switch, operator precedence,
variabelen scope etc. sind fix.
Wenn sich ein Compiler nicht an den Standard hält ist er kaputt.
Und implementation defined behaviour muss dokumentiert sein.
Dirk bitte,
erklaerst du mir noch deine loesungswege ?
array schreibweise ... klar habs verstanden und mehrfach reproduziert.
:-)
aber bei beiden anderen funktionen definierst du eine variable mit der
variablen "out", wobei "out" an dieser stelle doch noch leer ist. das
verstehe ich einfach nicht.
"char *o = out + strlen(in);"
bevor out irgendwas zugewiesen wurde.
ich weiss garnicht, was in "out" steht in dem moment wo du den pointer
"o" definierst.
dann weiss ich garnicht, ob die deklaration und definition nicht die
gleiche ist in beiden beispielen.
einmal mit "*" wie im letzen beispiel und davor einfach
"o = out + strlen(in);"
wenn das jetzt den rahmen sprengt dann sorry... muss ich wohl einfach
noch mehr selber lernen/lesen...
aber wenn du so lieb waerst :-o
<edit> sorry fuer so ne spaete antwort -.- hatte echt wenig zeit die
letzen wochen
out ist leer, weil da das Ergebnis rein kommt.
Der Aufruf ist so wie bei strcpy.
out ist die Adresse vom dem Zielarray.
o ist ein Hilfszeiger, der erstmal auf das Ende vom Ziel gesetzt wird.
Dieser wird dann durch das Postdekrement (--) runtergezählt, während die
Eingabe (in) mit dem Postinkrement (++) hochgezählt wird.
Bei dem letzten Beispiel habe ich o gleich initialisiert. Spart eine
Zeile.
Und die for-Schleife ist fast aus dem gleichen Grund da. Spart zwei
Zeilen.
Ansonsten machen die beiden Pointer-Funktionen dasselbe. Der Compiler
wird auch denselben (Maschinen-)Code dafür ausgeben.