Benutzung von Feldern



  • Hallo, eigentlich habe ich eine ziemlich allgemeine Frage: Wie benutze ich Felder denn richtig? Ich bringe aber besser ein Beispiel:

    Aufgabe: Schreibe ein Programm welches durch eine Funktion ( void vektor_ausspucken ( double x[], int N ) ) einen vom Benutzer zuvor eingegebenen Vektor auf der Konsole ausgibt. N soll vom Benutzer frei wählbar sein, und die Dimension des Vektors angeben.

    So, allein schon das die Funktion den Type "void" hat irritiert mich sehr. "void" heißt doch, dass nichts zurückgegeben wird. Die Funktion gibt ja aber quasi die Ausgabe zurück. Ich habe mittlerweile rausgefunden, dass es funktioniert, warum das aber so ist, ist mir nicht klar. Also entweder habe ich das mit dem "void" falsch verstanden oder ich habe es richtig verstanden, falsch programmiert aber es funktioniert trotzdem 😉

    Hier mal mein Quelltext:

    #include <stdio.h>
    
    //Deklaration/Initialisierung der Funktion, die uns den Vektor ausgeben soll
    void vektor_ausspucken ( double x[], int N);
    
    void vektor_ausspucken (double x[], int N)
    {
      int i;
        for (i=0;i<N;i++)
          {
    	printf("x[%d] = %lf\n",i,x[i]);
          }
    }
    
    //In der main, soll vom Benutzer der Vektor und die Dimension eingegeben werden
    //und über Zugriff auf die selbsterstellte Funktion der Vektor auf der Konsole 
    //ausgegeben werden
    
    main()
    {
    //Deklaration der benötigten Variablen
      int N=5, index=0, i=0;
      double x[N];
    
    //Dimensionseingabe
      printf("Bitte gebe die Dimension ein: ");
      scanf("%d",&N);
    
    //Vektoreingabe
      for(i=0;i<N;i++)
        {
          index++;
          printf("Bitte gebe den %d. Eintrag des Vektors ein: ",index,x[i]);
          scanf("%lf",&x[i]);
        }
    
    //Ausgabe
      print_field(x,N);
    
    //  return 0; (wird nicht unbedingt benötigt, macht zumindest kein Unterschied 
    //             zu meinem Problem)
    }
    

    Noch eine Frage die mir im nachhinein eingefallen ist: Muss ich immer zwingend Startwerte bei der Deklaration eingeben? Weil manchmal funktionieren meine Programme obwohl ich keinen Startwert angegeben habe, ein anderes mal wiederum nicht. Deshalb gebe ich mittlerweile immer Startwerte an, auch wenn ich sie ne Zeile später eh wieder änder.

    So nun aber zu meinem Problem: Das Programm funktioniert nach sehr langem herumdoktorn endlich! Oder... naja, es funktioniert fast! Denn sobald ich eine Dimension eingebe die 14 oder größer ist passiert folgendes. So sieht es aus, wenn ich das Programm in der Konsole starte.

    Bitte gebe die Dimension ein: 14
    Bitte gebe den 1. Eintrag des Vektors ein: 2
    Bitte gebe den 2. Eintrag des Vektors ein: 7
    .
    .
    .
    Bitte gebe den 13. Eintrag des Vektors ein: 25
    Bitte gebe den 14. Eintrag des Vektors ein: 12
    (eine leerzeile)
    C:\Verzeichnis\...\

    Also bricht das Programm sofort nach dem 14. Eintrag ab. Hierbei spielt es keine Rolle ob ich als Dimension 14, 15 oder 100 eingebe. Wenn ich als Dimension 13 eingebe funktioniert es aber wunderbar. Wäre es nun beim 2 millionsten Eintrag so könnte ich es ja noch verstehen, da dann irgendwann die Integer ausgehen, aber beim vierzehnten?? Allerdings muss ich sagen, dass erinnert mich stark an die Fakultät, da ist es auch so, dass wenn man die Fakultät von 14 mit Type Integer berechnen will er drüber hinauskommt, während 13 gerade noch geht. Aber ich habe ja nirgends was mit Fakultät gemacht, dennoch finde ich diesen Zufall sehr merkwürdig.

    Würde mich freuen wenn mir da mal jemand helfen könnte.

    Grüße av1



  • Averlance schrieb:

    So, allein schon das die Funktion den Type "void" hat irritiert mich sehr. "void" heißt doch, dass nichts zurückgegeben wird. Die Funktion gibt ja aber quasi die Ausgabe zurück.

    Nein, die Funktion gibt nichts zurück. Sie gibt allerdings was aus, das hat aber nichts mit einer Funktionsrückgabe zu tun. Die Rückgabe einer Funktion würdest du z.B. so weiterverwenden:

    int a=3,b=5;
    cout << Produkt(a,b); //das Ergebnis der Funktion, also die Rückgabe, wird per cout ausgegeben.
    


  • @matze
    Wir sind im C-Forum, gib acht bevor du wild in die Gegend coutest. 🙂

    @TE
    Das dürfte gar nicht kompilieren. Abgesehen davon, dass es "int main()" und nicht "main()" heißt, sind da x Fehler drin!

    Edit:
    Falls double x[N]; überhaupt funktioniert, wird da ein double-Array in der Größe des Werts den N in diesem Moment hat erstellt! Nur weil du N nachher änderst, ändert sich nicht die Größe des Feldes! Die ganze Aufgabe schreit eigentlich nach malloc(), hast du dir die Funktion mal angeguckt?



  • Averlance schrieb:

    #include <stdio.h>
    
    //Deklaration/Initialisierung der Funktion, die uns den Vektor ausgeben soll
    void vektor_ausspucken ( double x[], int N);
    /* was soll eine Initialisierung einer Funktion sein?
    Es ist eine Deklaration, bei Funktionen auch Prototyp genannt */
    
    void vektor_ausspucken (double x[], int N)
    {
      int i;
        for (i=0;i<N;i++)
          {
    	printf("x[%d] = %lf\n",i,x[i]);
          }
    }
    
    //In der main, soll vom Benutzer der Vektor und die Dimension eingegeben werden
    //und über Zugriff auf die selbsterstellte Funktion der Vektor auf der Konsole 
    //ausgegeben werden
    
    main()
    {
    //Deklaration der benötigten Variablen
      int N=5, index=0, i=0;
    
    /* das funktioniert nur mit C99 */
      double x[N];
    
    /* oben hast du gerade ein double Array für 5 Elemente definiert, was soll diese nachträgliche Änderung der Dimensionsgrenze bringen? */
    //Dimensionseingabe
      printf("Bitte gebe die Dimension ein: ");
      scanf("%d",&N);
    
    /* hier nur definiertes Verhalten für i 0..4 */
    //Vektoreingabe
      for(i=0;i<N;i++)
        {
          index++;
          printf("Bitte gebe den %d. Eintrag des Vektors ein: ",index,x[i]);
          scanf("%lf",&x[i]);
        }
    
    /* hier nur definiertes Verhalten für N 0..4 */
    //Ausgabe
      print_field(x,N);
      
    /* ist im Sprachstandard so festgelegt, Compiler warnen meistens auch, also benutze es */
    //  return 0; (wird nicht unbedingt benötigt, macht zumindest kein Unterschied 
    //             zu meinem Problem)
    }
    


  • cooky451 schrieb:

    @matze
    Wir sind im C-Forum, gib acht bevor du wild in die Gegend coutest. 🙂

    Upps, schon wieder passiert... 😃



  • Hallo Wutz,

    vielen Dank erstmal für deine ganzen Erläuterungen, allerdings habe ich noch ein paar fragen:

    Zu der Sache wegen Initialisierung: Ich habe es mit den Fachausdrücken von Variablen verwechselt, denn da (so haben wir die Begriffe zumindest gelernt, aber ich weiß, dass auch andere teilweise verwendet werden) wird eine Variable ja Deklariert (also dem Programm klar gemacht, dass ich z.B. Variablen vom Namen "xy" benutze). Später werden sie dann Initialisiert, also ihnen wird ein Wert zugewiesen (richtig?). Und da sich ja nicht ein wirklich großer Unterschied (zumindest vom logischen her, ich weiß nicht wie ich mich ausdrücken soll, aber ich hoffe ihr wisst was ich meine) zwischen einer Variablen und einer Funktion verbirgt habe ich doch glatt mal die Begriffe falsch benutzt. Bei einer Funktion ist es ja auch so, dass sie zuerst Deklariert werden muss, damit mein Programm weiß, dass es soetwas gibt und wie das "Gerüst" aussehen soll. Und später wird sie (und ja, jetzt der Begriff den ich meinte) definiert. Eine Funktion darf man mehrmals deklarieren aber nur einmal definieren. (spätestens jetzt sollte klar sein, was ich mit welchem Begriff meine)

    double x[N]
    

    Das funktioniert nur in C99? Ok, dann habe ich einfach Glück gehabt, das es bei mir funktioniert hat. Aber wie löse ich dann das Problem, wenn ich das N Variabel haben will? Oder kann ich es nur fest haben, und wenn jemand einen größeren/kleineren Vektor eingeben will, muss er den Quelltext aufmachen und es dort abändern?

    Das mit der Dimensionseingabe macht, zumindest dort wo es steht, keinen Sinn. Und unter Berücksichtigung, dass dieses x[N] nur mit C99 funktioniert, überhaupt keinen Sinn. Also ich bin gerade der Meinung, dass wenn ich es über der Deklaration von meinem Array hätte, es eine Auswirkung auf meinen Array hat. Sprich das Array so groß wäre, wie der Benutzer es eingibt. Ist mein Gedanke da richtig? (das war nämlich der eigentliche Gedanke, aber Angesichts dessen, dass x[N] eh nicht allgemein funktioniert, ist es halt schwachsinn.

    Bei der Vektorein- und Ausgabe ist meiner Ansicht nach ja nichts wirklich falsch. Mein Programm geht halt nur bis zu einer Dimension von 5. Da ich selbst ja erst davon ausgegangen bin, dass ich mein Array durch die Dimensionseingabe vergrößert habe, ist das also nur ein "Folgefehler". Wäre doch zumindest richtig, wenn ich das mit dem Array richtig gemacht hätte, oder?

    @Matze nicht so wild, ich habe schon erkannt was du vom Prinzip her meintest.
    @cooky, naja, da kann man sich nun drüber streiten, ob es int main() heißt oder nur main(). Zumindest haben wir es so gelernt, dass wenn man Funktionen keinen Type gibt er standardmäßig INT als type nimmt. Aber ich habe schon gehört, dass man besser int main() schreiben sollte. Da ich aber schon eine ganze Weile mich mit C beschäftigt habe und immer main() statt int main() geschrieben habe sitzt das halt noch so drin. Aber ich werde versuchen das nächste mal daran zu denken 😉

    Wegen dem x[N]: Ja, da hast du vollkommen recht, ist das selbe wie wenn ich ein Spiegelei machen will und das Ei erst aufschlage nachdem es eine halbe Stunde in der Pfanne lag ^^ (und wehe es schreibt jetzt einer, dass man dann trotzdem noch ein Spiegelei aus dem Ei machen kann!! Denn ausprobiert habe ich es nicht)

    Ich "kenne" zwar malloc, aber habe ich bewusst nicht benutzt, da wir zu diesem Zeitpunkt noch kein malloc hatten. Gut, es kam zwar ziemlich direkt danach, aber bei malloc arbeitet man doch eigentlich immer mit Zeigern oder? Und bei dieser Aufgabe sollte halt explizit mit Feldern gearbeitet werden. Deshalb habe ich mich nicht an malloc versucht, aber das kommt bei einer späteren Aufgabe noch und ich werde mich noch ausgiebig damit beschäftigen 😉

    EDIT:
    Ok, ich habe mal die Dimensionsänderung rausgenommen und habe N=15 gesetzt und als Array nicht x[N] sondern x[15] angelegt. Nun führt er auch wirklich alle 15 Einträge aus. In der Aufgabe steht auch drin, dass man im Hauptprogramm N als ein konstanten Wert setzen darf, aber ich dachte ich könnte mein Programm mit so einer variablen Dimension halt toll aussehen lassen...



  • Averlance schrieb:

    Hallo Wutz,

    vielen Dank erstmal für deine ganzen Erläuterungen, allerdings habe ich noch ein paar fragen:

    Zu der Sache wegen Initialisierung: Ich habe es mit den Fachausdrücken von Variablen verwechselt, denn da (so haben wir die Begriffe zumindest gelernt, aber ich weiß, dass auch andere teilweise verwendet werden) wird eine Variable ja Deklariert (also dem Programm klar gemacht, dass ich z.B. Variablen vom Namen "xy" benutze). Später werden sie dann Initialisiert, also ihnen wird ein Wert zugewiesen (richtig?). Und da sich ja nicht ein wirklich großer Unterschied (zumindest vom logischen her, ich weiß nicht wie ich mich ausdrücken soll, aber ich hoffe ihr wisst was ich meine) zwischen einer Variablen und einer Funktion verbirgt habe ich doch glatt mal die Begriffe falsch benutzt. Bei einer Funktion ist es ja auch so, dass sie zuerst Deklariert werden muss, damit mein Programm weiß, dass es soetwas gibt und wie das "Gerüst" aussehen soll. Und später wird sie (und ja, jetzt der Begriff den ich meinte) definiert. Eine Funktion darf man mehrmals deklarieren aber nur einmal definieren. (spätestens jetzt sollte klar sein, was ich mit welchem Begriff meine)

    Eine Deklaration gibt nur an, daß es den Namen gibt (das geht auch mit Variablen - siehe "extern"). Eine Definition erzeugt tatsächlich etwas, das Speicher benötigt. Und mit der Initialisierung legst du den Anfangswert einer Variablen fest.
    Wenn das erste, was du mit der Variable machst, eine Wertzuweisung oder Eingabe ist, dann kannst du auch mit einer nicht-initialisierten Variablen arbeiten. Wenn du aber etwas machst, was ihren Wert benötigt, solltest du ihn vorher gesetzt haben, sonst erhältst du Müll:

    int i; // der Wert in i ist nicht definiert
    i += 5; // nutzt den unbekannten Wert von i -> das Ergebnis ist genauso undefiniert
    scanf("%x",&i); // Eingabe durch den Nutzer - wenn erfolgreich, ist der Wert anschließend definiert
    
    double x[N]
    

    Das funktioniert nur in C99? Ok, dann habe ich einfach Glück gehabt, das es bei mir funktioniert hat. Aber wie löse ich dann das Problem, wenn ich das N Variabel haben will? Oder kann ich es nur fest haben, und wenn jemand einen größeren/kleineren Vektor eingeben will, muss er den Quelltext aufmachen und es dort abändern?

    Normale Arrays in C89 haben eine Größe, die bereits beim Compilen bekannt sein muß. Die Größe von VLA's kann zur Laufzeit variieren, ist allerdings nach der Definition auch unveränderbar. Wenn du etwas benötigst, dessen Größe sich zur Laufzeit an die Bedürfnisse anpassen kann, mußt du auf dynamische Speicherverwaltung (malloc()/free()) ausweichen.



  • Ok, dann habe ich glaube ich soweit alles verstanden was ich (zumindest bis jetzt) wissen wollte. Vielen Dank an alle die geholfen haben!


Log in to reply