Pointer als Rückgabewert eines Unterprogramms
-
Hallo :),
habe das Forum durchgesehen, aber nichts passendes gefunden, deswegen ein eigenes Thema.
Ich schreibe gerade an einem Programm, worin ich eine IBAN-Nummer(String aus 22 Zeichen) aus einer externen Datei einlesen und weiterverarbeiten muss.
Das Einlesen funktioniert,nur die Rückgabe des Pointers ans Hauptprogramm macht Schwierigkeiten:Mein Problem dabei ist, dass in Zeile 18( printf("p:%s\n",p); )
p nicht vollständig ausgegeben wird:http://s14.directupload.net/file/d/2962/2tbtleku_jpg.htm
Ich habe hier doch die Methode Call by Value mit Rückgabewert Pointer angewandt oder? Oder kann man Pointer nicht mit Return zurückgeben, sondern muss die Call by Reference-Methode anwenden?
Wäre cool, wenn mich einer erhellen würde.Danke.
/*Prototypen:*/ char *eingabe(FILE *); char *konvertierung(char *); /*Hauptprogramm:*/ int main() { char m[100]; int i; char *p=NULL,*s=NULL,*f=NULL,d,dummy; FILE *fp; fp=fopen("H:\\Eigene Dateien\\iban.dat","r"); p=eingabe(fp); printf("p:%s\n",p); s=konvertierung(p); printf("s:%s\n",s); scanf("%d"); /*damit Ausgabefenster offen bleibt*/ } /*Unterprogramm eingabe:*/ char *eingabe(FILE *fp){ char m[100]; char *p=NULL; char d; int i; p=m; /*sehr wichtig; ohne diese Zuweisung läufts nicht!*/ while(!feof(fp)){ fscanf(fp,"%c",&d); /*fp wandert autom.weiter, wenn nicht geclosed wird*/ *p=d;p++; } p--; *p='\0'; p=m; /*damit Pointer wieder auf Anfang von Array m[100];*/ printf("Pointer1 p:%s\n",p); return p; } /*Unterprogramm konvertierung:*/ char *konvertierung(char *s){ char *t=NULL; char m[100]; int i,j; i=0; for(j=0;j<=1;j++){ m[i]=(*s-87)/10+48; i++; m[i]=(*s-87)%10+48; i++;s++; } m[i]='\0'; t=m; return t; }
-
Du gibst Pointer auf lokale Variablen zurück. Die existieren aber nicht mehr, wenn die Funktion beendet ist, die Pointer zeigen somit in die Wüste, ein Zugriff darüber ergibt undefiniertes Verhalten.
BTW dein Programm ist fast unlesbar. Versuchs mal mit Einrückung.
-
Mir ist schon bewußt, dass wenn ich ein Unterprogramm verlasse, lokale Variablen nicht mehr gültig sind.Aber deswegen gibts ja die Rückgabe mit Return(=Call by Value),damit diese Inhalte ans (z.B.) Hauptprogramm übergeben werden können.
bzgl. Lesbarkeit:
Die Codes in den UPs sind mir zweitrangig,
deswegen, aber hast schon recht
-
Es ist kei Grund
t=m zu machen weil m ist konstant, da kanns du 'return m' machen,
Und m lieg im Stack also ist nach der Methodenaufruf weg, und dann hast du potenziell gefährlicher Zeiger aufm Stack-Position!!
-
Du musst den Speicherplatz mit an die Funktion übergeben.
-
blacksun schrieb:
bzgl. Lesbarkeit:
Die Codes in den UPs sind mir zweitrangig,
deswegen, [...]Super Grund um evtl. hilfswilligen Leuten hingerotzen Code zuzumuten.
Ob bzw. daß eine Funktion irgendeinen Wert zurückgibt hat weder mit Call-by-Reference noch mit Call-by-Value zu tun.
Du schreibst, dir sei bewusst, daß Variablen (m
) nach verlassen des Scopes aufhören zu existieren und du willst trotzdem über einen über den Scope "hinausgeretteten" Zeiger darauf zugreifen? Merkst was?
Was machst, wenn in der Datei mehr als 100 Bytes stehen?
Einefor
-Schleife die von0
bis0
zählt?
Dir ist klar, daß Bezeichner durchaus mehr als einen Buchstaben lang sein dürfen!?o4kareg schrieb:
Es ist kei Grund t=m zu machen weil m ist konstant,
wtf ist
m
!?o4kareg schrieb:
[...] Methodenaufruf [...]
Unterprogramme? Methoden!? wtf, daß ist C, diese netten Dinger heißen Funktionen ...
o4kareg schrieb:
[...] dann hast du potenziell gefährlicher Zeiger
"Potentiell gefährlich" ist eine Schusswaffe, ein Messer, ein Auto, ...
Einen Pointer dereferenzieren der auf etwas zeigt, das es nicht mehr gibt, ist viel, viel schlimmer: UNDEFINIERT!
-
Genau betrachtet ist das alles Schrott, was du hier anbietest.
Ich habe beim Zählen der Fehler bei 10 aufgehört.Genau betrachtet, brauchst du überhaupt keinen lokalen Speicher, eingabe kannst du mit fgets und konvertierung kannst du direkt auf *s erledigen, auch scheint mir die Schleife dort irgendwie sinnfrei.
-
Swordfish schrieb:
Eine
for
-Schleife die von0
bis0
zählt?
Dir ist klar, daß Bezeichner durchaus mehr als einen Buchstaben lang sein dürfen!?die for-Schleife läuft von 0 bis 1 und hat den Zweck aus z.B. "de"(=Deutschland)
die Zahlen 1314 zu berechnen und als String in ein extra Array zu speichern.
Schon richtig so,aber darum ging es mir hier nicht.Wutz schrieb:
Genau betrachtet ist das alles Schrott, was du hier anbietest.
Ich habe beim Zählen der Fehler bei 10 aufgehört.Tut mir Leid, dass dich mein Code so aufregt, aber nicht jeder kann soviel Erfahrung besitzen wie du.
Ich danke allen.
Ich werde mir eure Vorschläge ansehen und Bescheid geben,wenn es geklappt hat.
-
blacksun schrieb:
...
die Zahlen 1314 zu berechnen und als String in ein extra Array zu speichern.
Schon richtig so,aber darum ging es mir hier nicht.Da sieht keiner was du da berechnen willst.
Wenn du '0' meinst, schreib auch '0' hin.Wie sieht es mit Großbuchstaben aus?
m[i] = (toupper(*s) - 'A' + 10) / 10 + '0'; // toupper aus ctype.h
Vorher kann man noch mit
isalpha()
prüfen ob es überhaupt ein Buchstabe ist.
-
mit Übergabe von m (Variable von main) ans Unterprogramm eingabe hat es funktioniert.
Tatsächlich habe ich vorher versucht eine Pointer zu returnen, der auf eine lokale Variable m zeigte.Das war der Fehler, wie manche es hier richtig erkannt haben.
Danke nochmals.
@Dirk:
die Problematik mit Klein/-Großbuchstaben war mir hier nicht wichtig.
Ich eigne mir gerade C an und da war mir hier die Pointer-Handhabung wichtiger.
Aber natürlich sollte man in einem gescheiten Programm alle Möglichkeiten Abfangen.Noch ne Kleinigkeit:
Ich möchte nen 24stelligen String,der nur aus Zahlen besteht,(Pointer f zeigt auf diesen) im Unterprogramm pruefziffer in eine "normale" Zahl umwandeln, um damit was zu berechnen.double pruefziffer(char *f) double pruefzahl=0; for(f;*f;f++) pruefzahl= Pruefzahl*10+(*f-48); pruefzahl=98-fmod(pruefzahl,97); return pruefzahl; }
Ich habe das Problem, dass die Pruefzahl im folgenden Unterprogramm irgendwann(wahrs. wegen unzureichendem Wertebereich des Datentyps Double) irgendwann ungenau wird.f ist wie gesagt der Pointer auf nen 24stelligen String.
welcher Datentyp kann eigentlich eine 24 stellige Zahl annehmen/berechnen ohne zu runden?
und mit welchem Format gibt man sowas aus?
%d für int, %c für Char, %f für Float, %? für 24stellige Zahl?? ???
-
24 Stellen ist zuviel für jeden handelsüblichen Datentyp in C. Was willst du denn damit rechnen? "Prüfziffer" klingt nicht nach Rechnen.
-
OK,ich erklär mal meine ganze Aufgabe:
Überprüfen eine IBAN auf Gültigkeit:
Ich habe ne IBAN-Nummer (zb.de53360200410012345678) in der externen Datei.
Die IBAN besteht aus
- Ländercode(2 Stellen)
- Prüuefziffer(2 Stellen)
- Bankleitzahl(8 Stellen)
- Kontonummer(bis zu 10 Stellen,eventuell mit Nullen auf 10 Stellen auffüllen)1. Ich hole mir die aus der externen Datei.
2. ersetze Buchstaben durch a-z durch Ziffern 10 bis 35
Also a->10,...,d->13,e->14...
3. Umstellen:
de53360200410012345678->360200410012345678131400
Also BLZ, dann Kontonummer, dann "1314" für "de" und 2 abschließende Nullen dazu
4. 360200410012345678131400 mod 97 = 45
5. 98-45=53
6. Vergleiche berechnete Prüzziffern mit 3.und 4.Stelle der vorgegeben IBAN
falls gleich: alles OK
falls ungleich: ungültige IBANIch hoffe es ist jetzt verständlich wozu ich so ne lange Zahl brauche.
Wobei es bestimmt auch andere Wege gibt.nur welche?
-
blacksun schrieb:
Ich hoffe es ist jetzt verständlich wozu ich so ne lange Zahl brauche.
Du suchst nach Kongruenzen.
-
blacksun schrieb:
Ich habe hier doch die Methode Call by Value mit Rückgabewert Pointer angewandt oder? Oder kann man Pointer nicht mit Return zurückgeben, sondern muss die Call by Reference-Methode anwenden?
Du hast die lokale Variable m auf dem Stack liegen und der ist nach Rückkehr aus der Methode nicht mehr existent. Sowas kann einem schnell um die Ohren fliegen.
Du kannst die lokale Variable m statisch anlegen, d.h. diese existiert nur ein einziges Mal, dafür aber auch nach Ende Deiner Funktion:
static char m[100];
Ciao
MM
-
blacksun schrieb:
Ich hoffe es ist jetzt verständlich wozu ich so ne lange Zahl brauche.
Wobei es bestimmt auch andere Wege gibt.nur welche?Du beschreibst keine Zahl, sondern eine Ziffernfolge. Sieht zwar beides gleich aus (in den üblichen Darstellungen), ist aber ganz was anderes.
Faustregeln, wie man Zahlen von Ziffernfolgen unterscheiden kann: Ist die Differenz von zwei dieser Objekten eine sinnvolle Größe? Kann man führende Nullen weglassen? Kann man eine Größe im Oktalsystem darstellen, ohne den Sinn zu verkehren? Das ist hier alles eindeutig nicht der Fall. Ebenso bei Telefonnummern, Postleitzahlen und Kontonummern, die ebenfalls gerne fälschlicherweise als Zahl angesehen werden, obwohl sie Ziffernfolgen sind.
Behandle Ziffernfolgen wie Zeichenfolgen, deren Zeichen eben bloß Ziffern sein können.
-
SeppJ schrieb:
Du beschreibst keine Zahl, sondern eine Ziffernfolge. Sieht zwar beides gleich aus (in den üblichen Darstellungen), ist aber ganz was anderes.
Doch die IBAN wird in eine Zahl umgewandelt um die Prüfsumme zu berechnen. Vielleicht verwechselst du das mit der ISBN(da ist es eine Ziffernfolge).
BTT: Erstelle ersteinmal die Ziffernfolge in der richtigen Reihenfolge, so wie du es beschrieben hast. Nimm dafür einfach ein int Array der nötigen Länge(24?).
Danach musst du von hinten nach vorne die Stellen der letztendlichen Zahl berechnen. Als Datentyp probier mal long long int.//array = die Ziffernfolge mit Ziffern in der richtigen Reihenfolge int i; long long int zahl = 0; for (i = sizeof (array)-1; i >= 0; i--) { zahl += pow (10, (sizeof (array) - i)) * array[i]; }
So in etwa, ist eher Pseudo Code.
Für pow benötigst du math.h, damit berechnest du die zehner, hunderter, etc. Stelle der Zahl.
-
sacridex schrieb:
SeppJ schrieb:
Du beschreibst keine Zahl, sondern eine Ziffernfolge. Sieht zwar beides gleich aus (in den üblichen Darstellungen), ist aber ganz was anderes.
Doch die IBAN wird in eine Zahl umgewandelt um die Prüfsumme zu berechnen. Vielleicht verwechselst du das mit der ISBN(da ist es eine Ziffernfolge).
Eine Prüfsumme macht aus einer Ziffernfolge keine Zahl, sondern ist ein weiteres Argument, dass es sich nicht um eine Zahl handelt.
-
@sacridex
Für eine 24-Stellige Dezimalzahl braucht man ca. 80 Bit zu Darstellung.
long long hat meist 64 Bt. Reicht also nicht.Und statt pow und hinten am Array anzufangen, fängt man vorne an und rechnet immer mal 10. Zumal auch pow (auch für long double) für volle 24 Dezimalstellen nicht ausreicht.
-
Mit C99 liegt die min. garantierte Grenze für unsigned long long int bei 18446744073709551615 bzw. 18446744073709551615ULL, d.h. man kann max. 19 Dezimalstellen bei Integer-Berechnungen damit verwenden.
Ältere MSVC haben stattdessen (weil kein C99) dafür unsigned __int64.
-
SeppJ schrieb:
sacridex schrieb:
SeppJ schrieb:
Du beschreibst keine Zahl, sondern eine Ziffernfolge. Sieht zwar beides gleich aus (in den üblichen Darstellungen), ist aber ganz was anderes.
Doch die IBAN wird in eine Zahl umgewandelt um die Prüfsumme zu berechnen. Vielleicht verwechselst du das mit der ISBN(da ist es eine Ziffernfolge).
Eine Prüfsumme macht aus einer Ziffernfolge keine Zahl, sondern ist ein weiteres Argument, dass es sich nicht um eine Zahl handelt.
eine zahl ist eine folge von ziffern, wo ist das problem und was soll die haarspalterei?