Problem mit Array als return-Wert!



  • Hi Leute!

    Ich hab mir folgendes Programm geschrieben. Dieses Programm soll zwei Funktionen schneiden und den Schnittpunkt ausgeben. Das Problem dabei ist nun, dass eine Funktion ja keine 2 return-Werte zurückgeben kann. Nun packe ich die zwei berechneten Werte, also x und y des Schnittpunkts in ein 2-Elemente-Array in der Funktion und geb einen Zeiger darauf in die main-Funktin zurück. In der main möchte ich nun das zurückgegebene Array in zwei einzelne Variablen auslesen. Mein Problem ist hier nun in der 39. Zeile. Anscheinend kann ich das zurückgegebene Array nicht in mein Array xy[2] schreiben. Wie mach ich das dann?

    #include<stdio.h>
    #include<math.h>
    #include<string.h>
    
    float* schnittpunkt(float m1, float m2, float t1, float t2, float array[])
    {
    	float x, y, array[2];
    	x = (t2 - t1) / (m1 - m2);
    	array[0] = x;
    	y = m1 * x + t1;
    	array[1] = y;
    
    	return array;
    
    }
    
    int main()
    {
    	float m1, m2, t1, t2, x, y, xy[2];
    
    	printf("Steigung m1 von Gerade 1 eingeben: \n");
    	printf("m1 = ");
    	scanf("%f", &m1);
    	printf("Achsenabschnitt t1 von Gerade 1 eingeben: \n");
    	printf("t1 = ");
    	scanf("%f", &t1);
    
    	printf("Steigung m2 von Gerade 2 eingeben: \n");
    	printf("m2 = ");
    	scanf("%f", &m2);
    	printf("Achsenabschnitt t2 von Gerade 2 eingeben: \n");
    	printf("t2 = ");
    	scanf("%f", &t2);
    
    	xy[2] = schnittpunkt(m1, m2, t1, t2, xy);
    
    	x = xy[0];
    	y = xy[1];
    
    return 0;
    }
    


  • Ich habe 2 Vorschläge, da ich dies nicht mit einem Array machen würde.

    Du könntest eine structure Coordinate machen, die einen x und y Wert enthält. Dann statt eines Array diese structure zurückgeben. Finde ich eleganter.

    Du könntest die Variablen für x und y als Pointer übergeben, so dass du sie in der Funktion abändern kannst. (Ich würde es ja mit Referenzen machen aber ich glaube die gibt es in C nicht).



  • Also, ich hab mir jetzt auch nochmal dazu Gedanken gemacht. Ich hab's jetzt mal mit Pointern gemacht:

    #include<stdio.h>
    #include<math.h>
    #include<string.h>
    
    float* schnittpunkt(float m1, float m2, float t1, float t2, float array[])
    {
    	float x, y;
    	x = (t2 - t1) / (m1 - m2);
    	array[0] = x;
    	y = m1 * x + t1;
    	array[1] = y;
    
    	return array;
    
    }
    
    int main()
    {
    	float m1, m2, t1, t2, x, y, *xy[2];
    
    	printf("Steigung m1 von Gerade 1 eingeben: \n");
    	printf("m1 = ");
    	scanf("%f", &m1);
    	printf("Achsenabschnitt t1 von Gerade 1 eingeben: \n");
    	printf("t1 = ");
    	scanf("%f", &t1);
    
    	printf("Steigung m2 von Gerade 2 eingeben: \n");
    	printf("m2 = ");
    	scanf("%f", &m2);
    	printf("Achsenabschnitt t2 von Gerade 2 eingeben: \n");
    	printf("t2 = ");
    	scanf("%f", &t2);
    
    	xy[2] = schnittpunkt(m1, m2, t1, t2, *xy);
    
    	x = *xy[0];
    	y = *xy[1];
    
    return 0;
    }
    

    Nun sind zwar diese float* zu float konvertierungsprobleme laut meinem Compiler weg, aber jetzt sagt er mir als einziges Problem, dass die Variable xy ohne initialisierung benutzt wird. Ich kann sie ja aber gar nicht initialisieren, da ich ja das ja erst in der Funktion mache! Wahrscheinlich stimmen die Pointer einfach nicht!



  • Hi, da gibts zwei Lösungen.

    1. Array in main erstellen und pointer übergeben:

    #include <stdio.h>
    #include <string.h>
    
    int foo(char *string)
    {
      strcpy(string, "Bar!");
      return 0;
    }
    
    int main()
    {
      char string[0x100];
    
      foo(string);
      printf("%s", string);
      return 0;
    }
    

    2. Statisches Array & Pointer zurückgeben:

    #include <stdio.h>
    #include <string.h>
    
    char* foo()
    {
      static char string[0x100];
    
      strcpy(string, "Bar!");
      return &string[0];
    }
    
    int main()
    {
      printf("%s", foo());
      return 0;
    }
    


  • @cooky451:

    Sorry, aber ich versteh überhaupt nicht was du da machst!

    Kannst du's mir vielleicht etwas erklären?



  • Ich würde eine der beiden Möglichkeiten wählen. Hoffe dass das kein schlechter C Stil ist:

    #include<stdio.h> 
    #include<math.h> 
    #include<string.h> 
    
    // Structure, um die Koordinaten zu speichern
    struct Schnittpunkt
    {
    	float x;
    	float y;
    };
    
    // Erste Möglichkeit mit "Call by Reference"
    void schnittpunkt1(float m1, float m2, float t1, float t2, float* x, float* y) 
    { 
        *x = (t2 - t1) / (m1 - m2); 
        *y = m1 * *x + t1; 
    } 
    
    // Zweite Möglichkeit, die eine structure Schnittpunkt zurückgibt
    Schnittpunkt schnittpunkt2(float m1, float m2, float t1, float t2, float x, float y) 
    {
    	Schnittpunkt s;
    	s.x = (t2 - t1) / (m1 - m2);
    	s.y = m1 * s.x + t1; 
    	return s;
    }
    
    int main() 
    { 
        float m1, m2, t1, t2, x, y; 
    
        printf("Steigung m1 von Gerade 1 eingeben: \n"); 
        printf("m1 = "); 
        scanf("%f", &m1); 
        printf("Achsenabschnitt t1 von Gerade 1 eingeben: \n"); 
        printf("t1 = "); 
        scanf("%f", &t1); 
    
        printf("Steigung m2 von Gerade 2 eingeben: \n"); 
        printf("m2 = "); 
        scanf("%f", &m2); 
        printf("Achsenabschnitt t2 von Gerade 2 eingeben: \n"); 
        printf("t2 = "); 
        scanf("%f", &t2); 
    
        schnittpunkt1(m1, m2, t1, t2, &x, &y); // 1. Möglichkeit
    	Schnittpunkt s = schnittpunkt2(m1, m2, t1, t2, x, y); // 2. Möglichkeit
    
    return 0; 
    }
    

    *Edit
    Habs nicht getestet, sollte aber gehen 😉



  • bandchef schrieb:

    @cooky451:

    Sorry, aber ich versteh überhaupt nicht was du da machst!

    Kannst du's mir vielleicht etwas erklären?

    #include <stdio.h>
    
    int foo(float *pointer) // funktion erhält einen pointer auf ein float
    {
      pointer[0] = 5.5; // schreibt an die stelle auf die pointer zeigt
      pointer[1] = 3.6; // schreibt an die stelle auf die pointer zeigt + sizeof(float)
      return 0;
    }
    
    int main()
    {
      float arr[2];
    
      foo(arr); // übergibt pointer auf das erste element von arr
      printf("%f, %f", arr[0], arr[1]);
      return 0;
    }
    

    Ist das etwas klarer? Ansonsten frag am besten noch mal speziell nach was Du daran nicht verstehst.



  • Wenn ich jetzt mal die Option von "call by reference" wähle, dann sieht das ja jetzt bei mir so aus:

    #include<stdio.h>
    #include<math.h>
    #include<string.h>
    
    void schnittpunkt(float m1, float m2, float t1, float t2, float* x, float* y)
    {
    	*x = (t2 - t1) / (m1 - m2);
    	*y = m1 * *x + t1;
    }
    
    int main()
    {
    	float m1, m2, t1, t2, x, y, xy[2];
    
    	printf("Steigung m1 von Gerade 1 eingeben: \n");
    	printf("m1 = ");
    	scanf("%f", &m1);
    	printf("Achsenabschnitt t1 von Gerade 1 eingeben: \n");
    	printf("t1 = ");
    	scanf("%f", &t1);
    
    	printf("Steigung m2 von Gerade 2 eingeben: \n");
    	printf("m2 = ");
    	scanf("%f", &m2);
    	printf("Achsenabschnitt t2 von Gerade 2 eingeben: \n");
    	printf("t2 = ");
    	scanf("%f", &t2);
    
    	schnittpunkt(m1, m2, t1, t2, &x, &y);
    
    	x = xy[0];
    	y = xy[1];
    
    return 0;
    }
    

    Das Problem daran ist nur, dass mein compiler immer noch den gleichen Fehler bringt, als vorher, nämlich, dass die Variable xy nicht initialisiert sei...



  • Da hat der Compiler ja auch recht 😃
    Wo weist du den Variablen xy[0] und xy[1] denn einen Wert zu? 😉



  • bandchef schrieb:

    Das Problem daran ist nur, dass mein compiler immer noch den gleichen Fehler bringt, als vorher, nämlich, dass die Variable xy nicht initialisiert sei...

    Ich habe oben in meinem Post den Code kurz editiert. Du brauchst jetzt kein Array mehr. Die Werte werden in den Variablen x und y gespeichert.

    (Sry, ich hatte vergessen im Code das Array zu löschen).



  • Danke icarus2 für deine Hilfe!

    Ich hab jetzt mein Programm dann soweit mit "call by reference" fertig. Jetzt hab ich dazu nur noch ein paar Verständnisfragen:

    In der main übergebe ich ja an die Funktion schnittpunkt die ganzen Parameter. Darunter sind die zwei Adressen der Variablen x und y. Soweit richtig, oder? Damit die Funktion schnittpunkt mit den beiden übergebenen Adresseparametern was anfangen kann, deklariert man in der Typ-Parameter-Deklarationsliste der Funktion für die zu übergebenden Adressen x und y jeweils einen Pointer auf einen float, stimmt das soweit?

    Womit ich nun aber etwas Schwierigkeiten mit dem Verständnis habe, ist der Dereferezierungsoperator in der ersten Berechnungszeile der Funktion. Kannst du mir das etwas näher bringen? Ich versuch's trotzdem mal das zu erklären: Über diese Dereferenzierung wird doch die Variable x über die Adresse geändert, oder? Das würde ja jetzt bedeuten, dass in der main nach der Ausführung der ersten Zeile der Wert dieser ersten Berechnung in der Funktion steht, soweit richtig?

    #include<stdio.h>
    #include<math.h>
    #include<string.h>
    
    void schnittpunkt(float m1, float m2, float t1, float t2, float* x, float* y)
    {
    	*x = (t2 - t1) / (m1 - m2);
    	*y = m1 * *x + t1;
    }
    
    int main()
    {
    	float m1, m2, t1, t2, x, y;
    
    	printf("Steigung m1 von Gerade 1 eingeben: \n");
    	printf("m1 = ");
    	scanf("%f", &m1);
    	printf("Achsenabschnitt t1 von Gerade 1 eingeben: \n");
    	printf("t1 = ");
    	scanf("%f", &t1);
    
    	printf("Steigung m2 von Gerade 2 eingeben: \n");
    	printf("m2 = ");
    	scanf("%f", &m2);
    	printf("Achsenabschnitt t2 von Gerade 2 eingeben: \n");
    	printf("t2 = ");
    	scanf("%f", &t2);
    
    	schnittpunkt(m1, m2, t1, t2, &x, &y);
    
    	printf("S = %f , %f\n\n", x, y);
    
    return 0;
    }
    


  • Das Prinzip des Call-by-Reference ist nicht eine Kopie eines Wertes, sondern dessen Adresse im Speicher zu übergeben. Dadurch kann die Variable x, die du in main() definierst, in der Funktion schnittpunkt(..) verändert werden.

    Du übergibst also die Adresse der in main() definierten Variable x. Die Adresse, die du übergibst, wird nun im Pointer int* x gespeichert. Wenn du jetzt in der Funktion schnittpunkt

    x = (t2 - t1) / (m1 - m2);
    

    machen würdest wäre das ein Fehler. In der Variable x ist nämlich die Adresse und nicht der Wert selber gespeichert. Über den Dereferenzierungsoperator * bekommst du den effektiven Wert, der an dieser Adresse ist und kannst damit auch den effektiven Wert ändern, also

    *x = (t2 - t1) / (m1 - m2);
    

    bandchef schrieb:

    Über diese Dereferenzierung wird doch die Variable x über die Adresse geändert, oder? Das würde ja jetzt bedeuten, dass in der main nach der Ausführung der ersten Zeile der Wert dieser ersten Berechnung in der Funktion steht, soweit richtig?

    Im bin mir jetzt nicht ganz sicher ob ich dich da richtig verstehe. Aber ich glaube du meinst es richtig.

    Ich hoffe die Erklärung oben ist verständlich.



  • Ich hab jetzt ein weiteres Programm angefangen, dass mir von einem String alle sonderzeichen entfernen soll.

    Das sieht schon mal so aus:

    #include<stdio.h>
    #include<math.h>
    #include<string.h>
    
    void zeichen_entfernen(char zeichen[])
    {
    	gets(zeichen);
    
    	int len;
    	len = strlen(zeichen);
    	for(int i=0; i<len; i=i+1);
    	{
    		if((zeichen[i] < 48) || (zeichen[i] > 57))
    		{
    
    		}
    	}
    }
    
    int main()
    {
    	char zeichen[100];
    
    	zeichen_entfernen(zeichen);
    
    return 0;
    }
    

    Wenn ich nun meinen Debugger anwerfe, dann mosert er mir in Zeile 14 rum, dass i nicht deklariert sei. komischerweise steht doch in der for-schleife drin, dass int i=0 ist! Was soll das jetzt?

    Noch eine weitere Frage. bekomm ich da nun die Sonderzeichen raus? vor allem so, dass die entstehenden leerzeichen auch gelöscht werden, will sagen, dass die nächste ziffer an die stelle vom bzw. von den sonderzeichen gerutscht wird... Ich weiß da grad echt nicht weiter...



  • for(int i=0; i<len; i=i+1); // Mach hier mal den Strichpunkt weg
        { 
            if( (zeichen[i] < 48) || (zeichen[i] > 57) ) 
            { 
    
            } 
        }
    

    Zum anderen kann ich dir leider nichts sagen, da ich mich in C nicht so gut auskenne. Probiers doch einfach mal aus wenn der Code läuft 😉

    *Edit
    Falls du C89 machst musst du du die Variable i ausserhalb der for-Schleife definieren. Nimm einfach mal den Strichpunkt raus und wens funktioniert ist gut. Wenn es noch nicht funktioniert, dann versuchs mal so:

    int i;
        for( i=0; i<len; i=i+1 )
        { 
            if( (zeichen[i] < 48) || (zeichen[i] > 57) ) 
            { 
    
            } 
        }
    


  • Ich hab jetzt mal weiter gemacht. Jetzt sieht's so aus:

    #include<stdio.h>
    #include<ctype.h>
    #include<string.h>
    
    void zeichen_entfernen(char zeichen[])
    {
    	char zeichen_ohne[100];
    	int i, j, len;
    
    	gets(zeichen);
    
    	len = strlen(zeichen);
    	j = 0;
    	for(i=0; i<len; i=i+1);
    	{
    		if(isalpha(zeichen[i]))
    		{
    			zeichen_ohne[j] = zeichen[i];
    			j = j + 1;
    		}
    	}
    	zeichen_ohne[j] = '\0';
    
    	len = strlen(zeichen_ohne);
    	for(i=0; i<len; i=i+1)
    	{
    		printf("%c", zeichen_ohne[i]);
    	}
    }
    
    int main()
    {
    	char zeichen[100];
    
    	zeichen_entfernen(zeichen);
    
    return 0;
    }
    

    Jetzt hab ich das Deklarationsproblem nicht mehr aber funktionieren tuts trotzdem nicht...



  • Ja, schau dir meinen oberen Post an. Ich hatte übersehen, dass da ein Strichpunkt am falschen Ort ist. Ich hatte den Post etwas spät editiert. So wie oben sollte es funktionieren.

    Ich kann dir auch erklären was in deinem Code genau passiert wenn du da den Strichpunkt hast wenn du willst.



  • Was der Strichpunkt da macht kannst du mir gerne erklären... Der tut doch recht effektiv NICHTS, oder? Das ist doch sowas wie ne Endlosschleife dann ,oder?

    Ich hab jetzt aus meinem Code den Strichpunkt entfernt, hat aber leider nix gebracht... Hier nochmal mein neuer Code.

    #include<stdio.h>
    #include<ctype.h>
    #include<string.h>
    
    void zeichen_entfernen(char zeichen[])
    {
    	char zeichen_ohne[100];
    	int i, j, len;
    
    	gets(zeichen);
    
    	len = strlen(zeichen);
    	j = 0;
    	for(i=0; i<len; i=i+1)
    	{
    		if(isalpha(zeichen[i]))
    		{
    			zeichen_ohne[j] = zeichen[i];
    			j = j + 1;
    		}
    	}
    	zeichen_ohne[j] = '\0';
    
    	len = strlen(zeichen_ohne);
    	for(i=0; i<len; i=i+1)
    	{
    		printf("%c", zeichen_ohne[i]);
    	}
    }
    
    int main()
    {
    	char zeichen[100];
    
    	zeichen_entfernen(zeichen);
    
    return 0;
    }
    


  • Also der Code

    for(int i=0; i<len; i=i+1);
        { 
            if( (zeichen[i] < 48) || (zeichen[i] > 57) ) 
            { 
    
            } 
        }
    

    Macht genau das gleiche wie

    for( int i = 0; i < len; i=i+1)
    	{
    	}
    
    	{
    		if( (zeichen[i] < 48) || (zeichen[i] > 57) ) 
            { 
    
            } 
    	}
    

    Der Grund dafür ist, dass eine for-Schleife keine {} braucht, man kann diese Weglassen. Wenn jetzt dort ein Komma steht, so wird das als

    for( int i = 0; i < len; i=i+1)
    		;
    

    interpretiert. Das heisst in der Schleife passiert nichts.

    Was funktioniert den am Programm nicht? Compiler felher oder tut es nicht das, was es soll? Zur Semantik kann ich leider nicht viel sagen. Ich habe selber zu wenig Erfahrung mit C.



  • Funktioniert doch, obwohl die Compilerwarnungen durchaus zu beachten sind.

    http://www.ideone.com/CguVd



  • Ja mein code funktioniert. Ich bin bloß leider zu dumm, dass ich den Unterschied zwischen isalpha und isdigit zu erkennen. Meine eigentliche Intention war es, ein Programm zu schreiben, dass mir z.B. von einer Telefonnumer die Zeichen zu entfernen... Da is aber isalpha das grundsätzlich falsche dafür...

    Danke für eure Hilfe!


Anmelden zum Antworten