Problem mit Array als return-Wert!



  • 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!



  • Das Problem kann sein, dass isalpha(..) nicht alle Zeichen entfernt, die du möchtest. Ich würde es gerade umgekehrt machen und auf isdigit(..) überprüfen. Falls das Zeichen eine Ziifer ist drinnen lassen, andernfalls das Zeichen entfernen. Dann nimmst du bestimmt alle anderen Zeichen raus.



  • Schau doch mal die Tabelle auf http://www.cplusplus.com/reference/clibrary/cctype/ an.



  • Ich will euch hier nur nochmal kurz meinen vollständig und vor allem so wie ich es mir vorstelle funktionierenden Code präsentieren. Ich hab mir jetzt sogar nochmals die "Mühe" gemacht und hab die bisher genutzten Bibliotheksfunktionen selbst nachgebaut; quasi als Übung 🙂 Wenn ihr Verbesserungsvorschläge habt, dann nur her damit!

    #include<stdio.h>
    
    void zeichen_entfernen(char zeichen[])
    {
    	char zeichen_ohne[100], ziffer = 0;
    	int i, j, len;
    
    	i = 0;
    	ziffer = getchar();
    	while(ziffer != '\n')
    	{
    		zeichen[i] = ziffer;
    		i = i + 1;
    		ziffer = getchar();
    	}
    	zeichen[i] = '\0';
    
    	len = i;
    
    	j = 0;
    	for(i=0; i<len; i=i+1)
    	{
    		if((zeichen[i] > 47) && (zeichen[i] < 58))
    		{
    			zeichen_ohne[j] = zeichen[i];
    			j = j + 1;
    		}
    	}
    
    	len = j;
    
    	for(i=0; i<len; i=i+1)
    	{
    		printf("%c", zeichen_ohne[i]);
    	}
    }
    
    int main()
    {
    	char zeichen[100];
    
    	zeichen_entfernen(zeichen);
    
    return 0;
    }
    

    So, dann noch einen schönen Sonntag!



  • Als Hinweis:
    Du hast doch sicherlich schon mal beim Programmieren vom EVA-Prinzip gehört.

    Für dein Programm wäre das dann

    #include<stdio.h>
    
    char * zeichen_entfernen(char zeichen_ohne[], char zeichen[])
    {
        // Kopiere nur Zahlen von zeichen nach zeichen_ohne
        return zeichen_ohne;
    }
    
    int main()
    {
        char zeichen[100];
        char zeichen_ohne[100]
    
        fgets(zeichen,100,stdin);                   // Eingabe
    
        zeichen_entfernen(zeichen_ohne, zeichen);   // Verarbeitung
    
        printf("%s\n", zeichen_ohne);               // Ausgabe
    
    return 0;
    }
    

    So macht zeichen_entfernen genau das, wofür es da ist: Zeichen entfernen, sonst nichts.



  • DAS EVA-Prinzip ist mir durchaus klar. Ich werd dann wohl meinen Code dazu noch etwas verändern 🙂



  • Ich hab jetzt meinen Code mal so verändert. Ich Will jetzt das EVA Prinzip jeweils in einer Funktion bearbeiten. Ich will hier mit call by reference arbeiten. Jetzt hab ich aber zwei problem. erstes problem in zeile 30 und zweites problem in zeile 45. Ich vergleiche hier einen int mit einem int* was ich nicht darf. aber wie mache ich das dann?

    #include<stdio.h>
    
    char* zeichen_eingeben(char zeichen[], int* len)
    {
    	int i;
    	char ziffer;
    	i = 0;
    	ziffer = getchar();
    	while(ziffer != '\n')
    	{
    		zeichen[i] = ziffer;
    		i = i + 1;
    		ziffer = getchar();
    	}
    	zeichen[i] = '\0';
    	*len = i;
    	return zeichen;
    }
    
    char* zeichen_entfernen(char zeichen[], int* len)
    {
    	char zeichen_ohne[100];
    	int i, j, len;
    
    	j = 0;
    	for(i=0; i<len; i=i+1)
    	{
    		if((zeichen[i] > 47) && (zeichen[i] < 58))
    		{
    			zeichen_ohne[j] = zeichen[i];
    			j = j + 1;
    		}
    	}
    	return zeichen_ohne;
    }
    
    void zeichen_ausgeben(char zeichen_ohne[], int* len)
    {
    	int i;
    	for(i=0; i<len; i=i+1)
    	{
    		printf("%c", zeichen_ohne[i]);
    	}
    }
    
    int main()
    {
    	char zeichen[100];
    	int len;
    
        zeichen_eingeben(zeichen, &len);
    	zeichen_entfernen(zeichen, &len);
    	zeichen_ausgeben(zeichen, &len);
    
    return 0;
    }
    


  • Naja, len ist der Zeiger. Mit *len hast du den Inhalt
    Kannst du dir so merken:

    int i, *len; // i und *len sind beides int
    

    Du brauchst aber gar kein *len, da das Stringende durch '\0' markiert ist.
    Worauf soll sich *len beziehen? zeichen oder zeichen_ohne?

    In zeichen_eingeben kannst du die maximale Größe übergeben

    In zeichen_entfernen ebenso. Allerdings ist nach Ende von zeichen_entfernen auch das array zeichen_ohne[100] weg.
    Außerdem achtest du ja gar nicht auf den Rückgabewert von zeichen_entfernen.
    (evtl reicht ein

    zeichen_ohne[j] = 0; 
    strcpy(zeichen, zeichen_ohne);
    return zeichen ;
    

    )

    Wenn du in zeichen_ausgeben auf das "%s" bei printf verzichtest, dann nimm doch gleich putc().



  • Ich hab jetzt mal den Code abgeändert.

    #include<stdio.h>
    
    char* zeichen_eingeben(char zeichen[])
    {
    	int i;
    	char ziffer;
    	i = 0;
    	ziffer = getchar();
    	while(ziffer != '\n')
    	{
    		zeichen[i] = ziffer;
    		i = i + 1;
    		ziffer = getchar();
    	}
    	zeichen[i] = '\0';
    	return zeichen;
    }
    
    char* zeichen_entfernen(char zeichen[])
    {
    	char zeichen_ohne[100];
    	int i, j;
    
    	i = 0;
    	j = 0;
    	while(zeichen[i] != '\0')
    	{
    		if((zeichen[i] > 47) && (zeichen[i] < 58))
    		{
    			zeichen_ohne[j] = zeichen[i];
    			j = j + 1;
    		}
    		i = i + 1;
    	}
    	return zeichen_ohne;
    }
    
    void zeichen_ausgeben(char zeichen_ohne[])
    {
    	printf("%s", zeichen_ohne);
    }
    
    int main()
    {
    	char zeichen[100];
    	int len;
    
        zeichen_eingeben(zeichen);
    	zeichen_entfernen(zeichen);
    	zeichen_ausgeben(zeichen);
    
    return 0;
    }
    

    Wenn ich ihn nun ausführe, dann bekomm ich den gleichen String wieder zurückgeliefert welchen ich eingegeben habe. Ich denke, da passt was mit dem return-Wert der Funktion zeichen_entfernen nicht. Ich versteh aber grad nicht was da nicht passen soll...



  • Nochmal:
    1. Alle Variablen die du in einer Funktion deklarierst sind nach beenden der Funktion weg.
    Du gibst den Zeiger auf zeichen_ohne zurück. In dem Moment weißt du zwar wo die Daten sein sollen, sie sind aber schon wieder ungültig.

    2. Wenn du etwas zurück gibst musst du diesen Wert dann auch irgendwie zuweisen.

    3. zeichen_eingeben sollte schon wissen wie viel Platz in zeichen ist.

    #include<stdio.h>
    
    #define ZLEN 100
    
    char* zeichen_eingeben(char zeichen[], int n)
    {
        int i;
        char ziffer;
        i = 0;
        ziffer = getchar();
        while(ziffer != '\n')
        {
            zeichen[i] = ziffer;
            i = i + 1;
            if (i == (n-1)) break;
            ziffer = getchar();
        }
        zeichen[i] = '\0';
        return zeichen;
    }
    
    char* zeichen_entfernen(char zeichen_ohne[], char zeichen[], int n)
    {
        int i, j;
    
        i = 0;
        j = 0;
        while(zeichen[i] != '\0')
        {
            if((zeichen[i] > 47) && (zeichen[i] < 58))
            {
                zeichen_ohne[j] = zeichen[i];
                ++j; // j = j + 1;
                if (j == (n-1) break;
            }
            i = i + 1;
        }
        zeichen_ohne[j] = 0; 
        return zeichen_ohne;
    }
    
    void zeichen_ausgeben(char zeichen_ohne[])
    {
        printf("%s", zeichen_ohne);
    }
    
    int main()
    {
        char zeichen_ohne[ZLEN], zeichen[ZLEN];
        char *z_o;
    
        zeichen_eingeben(zeichen, sizeof(zeichen));
        zeichen_entfernen(zeichen_ohne,zeichen, sizeof(zeichen_ohne));
        zeichen_ausgeben(zeichen);
    
        // Als Beispiel wofür der Rückgabewert gebraucht werden kann:
        zeichen_ausgeben(zeichen_entfernen(zeichen_ohne, zeichen_eingeben(zeichen, sizeof(zeichen)), sizeof(zeichen_ohne)));
    //                   ------------------------------, =========================================  ----------------------
    
    return 0;
    }
    

Anmelden zum Antworten