Probleme bei einlesen von arrays über Console
-
@Ravensouth sagte in Probleme bei einlesen von arrays über Console:
weil ich C lernen möchte, damit mir C++ später mal leichter fällt.
Damit erreichst du übrigens den gegenteiligen Effekt. Dann programmierst du hinterher C in C++, weil du es so gewöhnt bist, anstatt "richtiges" C++.
-
@Th69 Gefühlt finde ich nichts darüber, was mein Problem lösen kann.
-
@SeppJ Wenn ich es mir ausgesucht hätte, dann hätte ich C# oder C++ im Studium genommen. Leider sind die Profs aus alter Schule.
-
@Ravensouth sagte in Probleme bei einlesen von arrays über Console:
@Th69 Gefühlt finde ich nichts darüber, was mein Problem lösen kann.
Wenn du weisst wie viele Zahlen es maximal sein können, und diese Zahl relativ klein ist, dann hilft es natürlich zu erfahren wie viele Zahlen
scanf
wirklich gefunden hat.Wenn du nicht weisst wie viele Zahlen es max. werden können bzw. die Zahl sehr gross ist, dann kannst du
scanf
mehrfach aufrufen. Dabei kannst du den "conversion specifier"n
verwenden um zu erfahren wie viele Zeichenscanf
gelesen/geparsed hat. Damit kannst du dann den Zeiger für den nächsten Aufruf vonscanf
weiterschieben. Das machst du dann in einer Schleife, bis es keine weiteren Zahlen mehr gibt.
-
@Ravensouth sagte in Probleme bei einlesen von arrays über Console:
Erstes Feld: 1 4 6 3 9 //aus diesem Feld soll das Array a[n] werden.
Die Formatspecifier zum einlesen von Zahlen überlesen führende Whitespace (dazu gehören u.a Leerzeichen, Tabulatoren, Zeilenvorschub (Entertaste)) und hören beim ersten Zeichen auf, dass nicht mehr zu der Zahl passt.
Für scanf ist es egal, ob du die ZAhlen in einer Zeile schreibst oder jede in einer Zeile oder ein Mischmasch davon.Du musst also erkennen, dass nach der 9 ein '\n' von der Entertaste kommt - zwischen 9 und der Entertaste können aber noch andere Leerzeichen sein. Das macht das Ganze etwas aufwendiger.
-
EDIT: Nein, geht nicht.
Aufwendiger, ja. Aber es sollte mit%*[]
gehen. Alaint a, b, c, d, e; int const n = scanf("%d%*[ \t\v\f\r]%d%*[ \t\v\f\r]%d%*[ \t\v\f\r]%d%*[ \t\v\f\r]%d", &a, &b, &c, &d, &e); // ...
Danach steht natürlich das Newline noch im Puffer - und muss ggf. irgendwie entfernt werden wenn es beim nächsten Input nicht stören soll.
-
@hustbaer sagte in Probleme bei einlesen von arrays über Console:
Ala
Wenn du weißt, dass 5 Zahlen in der Zeile stehen, muss ja nicht dieser Aufwand gemacht werden.
Da kommt aber noch mehr dazu.
Z.B. was ist, wenn die Zeilen unterschiedlich viele Zahlen enthalten.
-
@DirkB sagte in Probleme bei einlesen von arrays über Console:
Da kommt aber noch mehr dazu.
Z.B. was ist, wenn die Zeilen unterschiedlich viele Zahlen enthalten.Dann ist der Rückgabewert von
scanf
kleiner?
(Und dass man die maximale Anzahl kennen muss, hab ich ja bereits geschrieben.)
-
@hustbaer
dein dummy-scanset ist sinnfrei, %d macht das inklusive.
-
@Wutz
Danke für die Korrektor.Also es funktioniert wenn das Newline direkt nach der letzten Zahl ist. Dann matched das dummy-scanset nicht, und scanf bricht ab. Es funktioniert aber nicht wenn nach der letzten Zahl erstmal noch ein anderes Whitespace kommt. Dann matched das dummy-scanset das andere Whitespace, scanf macht weiter, und das
%d
matched dann das folgende Newline.D.h. so kann man es nicht machen.
Gibt es überhaupt eine Möglichkeit sowas mit einem
scanf
Aufruf zu machen? Also 1...n Zahlen zu lesen bis zum nächsten Newline.
-
@hustbaer Also ich habe es mittlerweile so gelöst, nachdem ich mir meine Vorlesungsskripte durchgelesen habe.
Bei meinem Programm muss man vorher die Dimension, also die Anzahl der n's vom jeweiligen Feld eingeben. Somit kann man zwei Felder in verschiedener Länge zu einem Feld zusammenfügen und sortieren. Ich habe nmax begrenzt, was jetzt nicht notwendig gewesen wäre, aber in meinem Beispiel will ich das nicht an die Spitze treiben. Ich hatte es auch schon recht weit ohne die Angabe von der Anzahl des Feldes geschafft, sprich ohne n. Allerdings nur in Form eine Zeichenkette mit getchar. Das Problem lag dann darin, die Zeichenketten von a uns b zusammenzufügen zu Feld c. Wenn man die Zeichenekette im Integer ausgeben könnte, dann sollte es funktionieren.#include <stdio.h> int main() { int nmax = 40; int i, an, bn, nges, j, z; int ai = 0, bi = 0; int a[nmax], b[nmax], *cpr; int c[nmax]; do { printf("Maximale Anzahl im Feld: %d\n", nmax); /*Maximale Anzahl an Zahlen im Feld*/ printf("Groesse Feld a: "); /*Größe von Feld a*/ scanf("%d", &an); printf("Groesse Feld b: "); /*Größe von Feld b*/ scanf("%d", &bn); nges = an + bn; /*Größe von Feld a + Feld b*/ } while (an < 1 && bn < 1|| an > nmax && bn > nmax); /*Bedingung: Felder kleiner 1 oder größer 40 --> Wiederholung*/ for (i = 0; i < an; i++) /*Feld a und b einzeln aufgelistet, damit man die Zahlen einzeln eintippen kann*/ { printf("a[%d]= ", i); scanf("%d", &a[i]); } for (i = 0; i < bn; i++) { printf("b[%d]= ", i); scanf("%d", &b[i]); } for (i = 0; i < an; i++) /*Feld a in Feld c einfügen*/ { cpr = &a[ai]; c[i] = *cpr; ai = ai + 1; } for (i = nges-bn; i<nges; i++){ /*Unsortiert: Feld b nach Feld a in Feld c einfügen*/ cpr = &b[bi]; c[i] = *cpr; bi = bi + 1; } printf("c[] unsortiert = {"); for(i=0;i<nges;i++){ /*Unsortiert Feld c ausgeben*/ if (i == (nges-1)) { printf("%d", c[i]); /*ohne Komma, wenn letzte Zahl*/ } else{ printf("%d,", c[i]); /*mit Komma, wenn letzte Zahl noch nicht erreicht*/ }} printf("}"); printf("\nc[] sortiert = {"); for(i=0; i<nges-1; i++) /*Feld c sortieren*/ { for (j=i+1; j<nges; j++) { if (c[i]>c[j]) { z = c[i]; c[i]=c[j]; c[j] = z; } } } for (i=0; i<nges; i++) /*Feld c sortiert ausgeben*/ { if (i == nges-1){ printf("%d", c[i]); } else { printf("%d,", c[i]); } } printf("}"); return 0; }
-
...und jetzt kannst du anfangen, Funktionen zu verwenden. Ein guter Anhaltspunkt sind übrigens deine eigenen Kommentare. Immer dann, wenn du mit einem Kommentat einen Block beschreibst, sollte dieser Block wohl eine Funktion sein.
Beispiele:
-
Zeile 25 bis 34: Dein Kommentar:
/*Feld a und b einzeln aufgelistet, damit man die Zahlen einzeln eintippen kann*/
Du machst 2x das gleiche, nämlich in einer Schleife über ein Array loopen und ausgeben/einlesen. Als Funktion könntest du hier eine allgemeine Funktion zum Einlesen von n Zahlen in EIN Array erstellen udn diese dann für a und b aufrufen. -
Zeilen 36-41:
/*Feld a in Feld c einfügen*/
- also als allgemeine Funktion vielleicht "ein Feld in ein anderes einfügen"? Allgemein sollten deine Variablen nur einen kleinen Gültigkeitsbereich haben, hier z.B.ai
. Die sollte nur hier verfügbar sein, nicht global. (und wozu brauchst ducpr
?) -
Dann hast du "Feld ausgeben" in Zeile 51 bis 60 und 77 bis 86. Das ist doch 2x das gleiche, nur mit anderen Daten! Also eine Funktion machen und die dann an den beiden Stellen aufrufen.
-
Und Sortieren in Zeile 64 bis 76 ist doch auch eindeutig eine Funktion.
-
-
@wob Danke dir für deine ausführliche Hilfe. In meinen neuen Skripten steht etwas über Funktionen und bis jetzt bin ich noch nicht dahinter gestiegen. Ich habe nur gesehen, dass das etwas mit Rückgabewerten und Parametern zu tun hat wie z.B. void bezeichnung (int k) --> das wäre jetzt meines Wissens nach ein Parameter ohne Rückgabewert. Was das genau bedeutet, weiß ich leider noch nicht.
-
@Ravensouth sagte in Probleme bei einlesen von arrays über Console:
Was das genau bedeutet, weiß ich leider noch nicht.
Warum nicht? Du kennst doch sicher z.B. trigonometrishe Funktionen wie Sinus. Was machen die? Was sind Parameter, was geben sie zurück? Kannst du das abstrahieren?
-
Hallo @Ravensouth ,
Eine Funktion (siehe auch Methode) ist so etwas wie ein kleines Unterprogramm. Du vergibst einen sprechenden Namen, wie addiereGanzzahlen, und damit die Funktion weiß, welche Werte sie addieren soll übergibst Du der Funktion addiereGanzzahlen zwei Werte (wert1 und wert2) als Parameter.Sieht jetzt schon mal so aus:
addiereGanzzahlen( int wert1, int wert2);
Voila, jetzt brauchen wir nur noch das Ganzzahl-Ergebnis, das kennzeichnen wir, indem wir den Rückgabetyp davor schreiben…
int addiereGanzzahlen( int wert1, int wert2);
Jetzt noch die Ausführung definieren (ein bisschen komplexer zum Verständnis)…
int addiereGanzzahlen( int wert1, int wert2) { int retVal = wert1 + wert2; // hier wird addiert und die Summe einer Variablen zugewiesen return retVal; // hier wird der Wert zurückgeliefert };
Jetzt nutzen wir unsere kleine Funktion:
... int meinZuBerechnenderWert = addiereGanzzahlen( 123, 456 ); ...
meinZuBerechnenderWert sollte jetzt den Wert 579 haben.
Funktionen, die keinen Rückgabewert liefern sollen, werden mit dem Schlüsselwort void eingeleitet.void tuWasOhneWasZuLiefern( … );
Zum Anfang sollte das reichen, ansonsten gibt’s da noch ne Menge nachzulesen.
-
@Mechanics Sowas hatten wir im Abitur. Kommt sicherlich im Studium auch noch dran. Habe sowieso das Gefühl, als würde sich Mathe und Informatik bei uns jetzt ziemlich stark überschneiden wie sonst nie zuvor.
-
@Helmut-Jakoby Ach so. Jetzt verstehe ich wie man die Funktion in der Praxis anwendet. Ein sehr gutes Beispiel. Danke dir
-
@hustbaer
Man nutzt überhaupt niemals scanf.
Man nutzt fgets+sscanf.
Das funktioniert dann auch in stdin redirections via commandline-Pipe und auch für beliebig viele (vorher unbekannte Anzahl von - alledings gleichtypisierten) Inputs.
-
@Ravensouth sagte in Probleme bei einlesen von arrays über Console:
Ich habe nmax begrenzt,
Mache aus "int nmax=40" ein enum { NMAX=40 };
dann sind deine Arrays keine VLA, und dein Code nähert sich etwas einer professionellen Programmierung.Nutze in deinen for-Schleifen für i die initial declaration, also
for(int i=0;...;...)
-
@Wutz sagte in Probleme bei einlesen von arrays über Console:
@hustbaer
Man nutzt überhaupt niemals scanf.
Man nutzt fgets+sscanf.
Das funktioniert dann auch in stdin redirections via commandline-Pipe und auch für beliebig viele (vorher unbekannte Anzahl von - alledings gleichtypisierten) Inputs.Was soll denn da bitte der Zusammenhang sein?