C Programmmenü für HeapSort

Unbitable

Cadet 2nd Year
Registriert
Dez. 2011
Beiträge
23
Hallo Community,

ich habe hier ein kleines Programmierproblem. Habe jetzt schon ein paar Tage verschiedene Tutorials durchforstet, aber komme nicht drauf, was genau falsch ist.
Ich studiere Telekommunikationstechnik, wozu programmieren jetzt nicht unbedingt zählt, aber da es auch Informatik beinhaltet, komme ich dem Ganzen nicht aus.
Wir haben die ersten zwei Semester die Grundlagen der Informatik erlernt. (Algorithmen, Schleifen, Sortierung usw.) Aber alles mit Pseudocode.
Unser Prof. will aber jetzt ein Funktionsfähiges Programm in C haben.

Ich kann ein wenig Java von daher ist mir Programmieren nicht komplett fremd.
Ich habe mich für den HeapSort-Algorithmus entschieden.

In der Aufgabenstellung wird verlangt, dass das Programm über ein Menü verfügt, mit dem man Werte Eingeben kann, diese sich ausgeben lassen kann und schrittweise sortieren kann.

Hier mal mein Quellcode:

Code:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

//Menueauswahl//

int main(void) 
{
	char wahl;
	wahl = ' ';

	while (wahl != 'B')	
	{
		printf("     Hauptmenue\n");
		printf("     =========\n");
		printf("     (A)usgabe\n");
		printf("     (E)ingabe\n");
		printf("     (S)ortierung\n");
		printf("     (B)eenden\n");
		printf("     Bitte waehle einen Menuepunkt aus!\n");
		wahl = toupper(getch());
		printf("---%c---\n", wahl);
		
		switch (wahl) 
		{
			case 'A' : printf("\nAusgabe wurde gewaehlt!\n\n"); Ausgabe(); break;
			case 'E' : printf("\nEingabe wurde gewaehlt!\n\n"); Eingabe(); break;
			case 'S' : printf("\nSortierung wurde gewaehlt!\n\n"); break;
			case 'B' : printf("\nDas Programm wird beendet...\n\n"); break;
			default  : printf("\nFalsche Taste!\n\n"); break;
			
		}
	}
}
int Ausgabe(int anzahl, int Eingabe[]) 
{
	printf("%i \n", anzahl);
	int j;
	for(j = 1; j <= anzahl; j++) 
	{
		printf("%i ",Eingabe[j]);
	}
}

int Eingabe(int anzahl, int Eingabe[]) 
{	
	printf("Bitte geben sie die Anzahl der Elemente an, die sie eingeben moechten.\n");
	
	scanf("%d", &anzahl);
	printf("Bitte geben sie nacheinander die Elemente ein.\n");
	anzahl = anzahl--;
	
	int i;
	for(i = 1; i <= anzahl; i++) 
	{
		printf("Bitte Element %i eingeben...\n", i);
		scanf("%d", &Eingabe[i]);
	}
	
	return anzahl, Eingabe[anzahl];
}

So. Meine Funktion Eingabe funktioniert wunderbar.

Wenn ich aber dann das Eingegebene ausgeben will, dann kommt immer nur "-1"

Da ich mir in der Funktion Ausgabe() mal testweise mit der Zeile "printf("%i \n", anzahl);" den Wert der Variable anzahl anzeigen lasse, vermute ich, dass die "-1" der Wert dieser Variable ist und er deswegen auch die darauffolgende for-Schleife nicht durchführt.

Weiterhin denke ich mal, dass er in der Eingabe-Funktion das Array Eingabe und den Wert von anzahl entweder nicht zurückgibt, damit ich ihn in der anderen Funktion aufrufen kann, oder ich den vielleicht irgendwo "überschreibe"?

Ich bin halt wirklich etwas unbeholfen, weil mir einfach die allgemeinen Regel von C fehlen, ich aber nicht so viel Zeit habe um die Sprache von Grund auf zu lernen.

Vielen Dank schon mal, wenn mir jemand weiterhelfen kann :)

mfg Unbitable
 
Ist schon länger her, dass ich C gemacht habe, aber...

Du arbeitest bei beiden Fkts mit lokalen Variablen.
Die Rückgabewerte werden nicht gespeichert (können also nicht weiterverwendet werden)

Sobald du die Fkt Eingabe() verlässt, wird Eingabe[] nicht mehr verfügbar sein.

Du rufst Ausgabe() auf, ohne Werte zu übergeben (würde jetzt das -1 erklären)
 
In C ist das ein bisschen anders als in Java oder C#. Wie mein vorredner schon sagte, werden in C keine Referenzen auf das Array an die Funktionen übergeben. In Java und C#allerdings schon. Wenn du also einen Pointer übergibts, dann müsste es gehen. Mein C ist allerdings auch schon laaaaaaaaange her :D
 
Code:
return anzahl, Eingabe[anzahl];
Ist dir bewusst, was dieses Stück Code macht?

@amokkx int Eingabe[] wird ja als Parameter übergeben und ist ein Synonym für int* Eingabe, insofern sollte das kein Problem sein. Problematischer ist eher, dass der Code hier unvollständig ist:

Code:
case 'A' : printf("\nAusgabe wurde gewaehlt!\n\n"); Ausgabe(); break;
case 'E' : printf("\nEingabe wurde gewaehlt!\n\n"); Eingabe(); break;

Was wird an Ausgabe und Eingabe als Parameter übergeben? Was passiert mit den Rückgabewerten? Auch da können Fehler passieren, gerade in Verbindung mit Arrays.
 
Zuletzt bearbeitet:
VikingGe schrieb:
Code:
return anzahl, Eingabe[anzahl];
Ist dir bewusst, was dieses Stück Code macht?
Also die return-Anweisung beendet die funktion und gibt die angegebenen Werte zurück...ich hatte eben gehofft, dass diese dann für die anderen Funktionen aufrufbar sind.

hab auch schon was von globalen variablen gelesen. Hab's damit auch schon versucht, aber da bin ich auch überfragt.
Das deklarieren einer globalen Variable is jetzt ned schlimm, aber ich weiß ned ganz, wie ich diese dann in der Funktion nutze und dann auch die Werte so abspeichere, dass diese wieder global nutzbar sind.

VikingGe schrieb:
@amokkx int Eingabe[] wird ja als Parameter übergeben und ist ein Synonym für int* Eingabe, insofern sollte das kein Problem sein. Problematischer ist eher, dass der Code hier unvollständig ist:

Code:
case 'A' : printf("\nAusgabe wurde gewaehlt!\n\n"); Ausgabe(); break;
case 'E' : printf("\nEingabe wurde gewaehlt!\n\n"); Eingabe(); break;

Was wird an Ausgabe und Eingabe als Parameter übergeben? Was passiert mit den Rückgabewerten? Auch da können Fehler passieren.

Kann ich denn hier z.b. bei der Funktion Ausgabe einfach die Variablen angeben, die ich in Eingabe bei return stehen hab?
Also Beispiel: Ausgabe(anzahl, Eingabe[]) ?

Grad ausprobiert...Da meckert er "undeclared (first use in this function)"
 
Zuletzt bearbeitet:
Unbitable schrieb:
Das deklarieren einer globalen Variable is jetzt ned schlimm, aber ich weiß ned ganz, wie ich diese dann in der Funktion nutze und dann auch die Werte so abspeichere, dass diese wieder global nutzbar sind.
Am besten gar nicht, denn das ist in 98% der Fälle extrem schlechter Programmierstil. Deswegen verrate ich dir das auch nicht.

Unbitable schrieb:
Also die return-Anweisung beendet die funktion und gibt die angegebenen Werte zurück...
Und jetzt rate mal - was genau gibt deine Funktion zurück?
Code:
a) anzahl?
b) Eingabe[anzahl]?
c) beides?

Unbitable schrieb:
Also Beispiel: Ausgabe(anzahl, Eingabe[])?
Du müsstest erst einmal irgendwo in deiner Main-Funktion ein Array deklarieren, das die nötige Anzahl Elemente speichern kann, und diese Anzahl überhaupt erstmal irgendwo definieren. Bei deinem Programm hast du aktuell gar keine Möglichkeit, diese anzugeben.

Übrigens:
Code:
	int i;
	for(i = 1; i <= anzahl; i++)

Lässt sich auch in C als
Code:
for(int i = 1; i <= anzahl; i++)
schreiben, falls C99 erlaubt ist (...was ja heutzutage wohl hoffentlich der Fall ist).
 
Hi

In C sollten die Funktionen vor dem Main deklariert werden.

Der Compiler arbeitet von oben nach unten, so wie du es gemacht hast, läuft der Compiler mit Warnings "implicit declaration" durch.
Wenn du die beiden Funktionen vor dem Main hinschreibst, gibt es Fehler "to few arguments".

Ich versuche mal eben, dein Programm zu korrigieren - ist für mich Prüfungsvorbereitung ^^

Gruss - jumpin
 
VikingGe schrieb:
Am besten gar nicht, denn das ist in 98% der Fälle extrem schlechter Programmierstil. Deswegen verrate ich dir das auch nicht.


Und jetzt rate mal - was genau gibt deine Funktion zurück?
Code:
a) anzahl?
b) Eingabe[anzahl]?
c) beides?
Genau das hab ich im Internet schon gelesen, dass Globale Variablen nicht gern gesehen sind...und da ja auch der Programmierstil bei der Aufgabe bewertet wird, habe ich das erstmal nicht versucht.

Zu der Frage. Ich würde jetzt sagen Antwort c) Beides.

VikingGe schrieb:
Übrigens:
Code:
	int i;
	for(i = 1; i <= anzahl; i++)

Lässt sich auch in C als
Code:
for(int i = 1; i <= anzahl; i++)
schreiben, falls C99 erlaubt ist (...was ja heutzutage wohl hoffentlich der Fall ist).

Wenn ich die Deklaration in der Schleife mache, dann weißt er mich freundlich darauf hin ;)
[Note] use option -std=c99 or -std=gnu99 to compile your code


jumpin schrieb:
Hi

In C sollten die Funktionen vor dem Main deklariert werden.

Der Compiler arbeitet von oben nach unten, so wie du es gemacht hast, läuft der Compiler mit Warnings "implicit declaration" durch.
Wenn du die beiden Funktionen vor dem Main hinschreibst, gibt es Fehler "to few arguments".

Ich versuche mal eben, dein Programm zu korrigieren - ist für mich Prüfungsvorbereitung ^^

Gruss - jumpin

Danke schon mal :D dann Bastel ich das mal um und mach die Funktionen vor der main.
 
Zu der Frage. Ich würde jetzt sagen Antwort c) Beides.
Du gibst einen int zurück (Rückgabetyp der Funktion), insofern kann das gar nicht beides sein. Was du da machst, ist den Komma-Operator zu verwenden:
Code:
a, b

Erst wird a ausgewertet, das Ergebnis verworfen, b ausgewertet und zurückgegeben. Insofern wäre b) die richtige Antwort gewesen.

Wenn du in C mehrere Werte zurückgeben willst, musst du entweder Pointer-Parameter verwenden oder einen Struct als Rückgabetypen verwenden, der die Werte dann enthält.
 
Zuletzt bearbeitet:
VikingGe schrieb:
Du gibst einen int zurück (Rückgabetyp der Funktion), insofern kann das gar nicht beides sein. Was du da machst, ist den Komma-Operator zu verwenden:
Code:
a, b[/b]

Erst wird a ausgewertet, das Ergebnis verworfen, b ausgewertet und zurückgegeben. Insofern wäre [b]b)[/b] die richtige Antwort gewesen.

Wenn du in C mehrere Werte zurückgeben willst, musst du entweder Pointer-Parameter verwenden oder einen Struct als Rückgabetypen verwenden, der die Werte dann enthält.[/QUOTE]

Achso. Ok :) Danke. Jetzt hab ich das verstanden.

Ich hab jetzt mit dem Tipp von jumpin, dass ich die Funktionen davor schreiben soll, nochmal rumgebastelt. 
Die zwei Funktionen mal anders benannt, weil Eingabe als Name für Funktion und Array fand ich auch bissl verwirrend, und nochmal bissl zu Funktionen nachgelesen.
Sieht jetzt so aus:

[CODE]#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

//Menueauswahl//

//int Output() 
//{
//	printf("%i \n", anzahl);
//	int j;
//	for(j = 1; j <= anzahl; j++) 
//	{
//		printf("%i ",Eingabe[j]);
//	}
//}

int Input(int anzahl) 
{	
	int Eingabe[anzahl];
	printf("Bitte geben sie nacheinander die Elemente ein.\n");
	anzahl = anzahl--;
	int i;
	for(i = 1; i <= anzahl; i++) 
	{
		printf("Bitte Element %i eingeben...\n", i);
		scanf("%d", &Eingabe[i]);
	}
	
	return Eingabe[anzahl];
}

int main(void) 
{
	char wahl;
	wahl = ' ';

	while (wahl != 'B')	
	{
		printf("     Hauptmenue\n");
		printf("     =========\n");
		printf("     (A)usgabe\n");
		printf("     (E)ingabe\n");
		printf("     (S)ortierung\n");
		printf("     (B)eenden\n");
		printf("     Bitte waehle einen Menuepunkt aus!\n");
		wahl = toupper(getch());
		printf("---%c---\n", wahl);
		
		switch (wahl) 
		{
			case 'A' : printf("\nAusgabe wurde gewaehlt!\n\n"); break;
			case 'E' : printf("\nEingabe wurde gewaehlt!\n\n"); 
			{
				printf("Bitte geben sie die Anzahl der Elemente an, die sie eingeben moechten.\n");
				int anzahl;
				scanf("%d", &anzahl);
				int Eingabe[anzahl];
				Eingabe[anzahl] = Input(anzahl);
				break;
			} 
			case 'S' : printf("\nSortierung wurde gewaehlt!\n\n"); break;
			case 'B' : printf("\nDas Programm wird beendet...\n\n"); break;
			default  : printf("\nFalsche Taste!\n\n"); break;
			
		}
	}
}
 
Du hast immer noch einen Denkfehler bei dem Return. Du returnst nicht das ganze Array Eingabe[] sondern nur den einen Wert an der Stelle Eingabe[anzahl].
Außerdem solltest in der For-Schleife bei i=0 anfangen, da ein Array a von der Länge 15 nicht von a[1]-a[15], sondern von a[0]-a[14] geht.
 
Jetzt musst du hier noch Heapsort implementieren.

Code:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

void Ausgabe(int Anzahl, int *Zahlen)
{
    if(!(Zahlen) || !Anzahl){
        printf("Fehler: Noch keine Eingabe!\n");
        return;
    }
    printf("Anzahl Zahlen:%i \n", Anzahl);
    int j;
    for(j = 0; j < Anzahl; j++)
    {
        printf("%i ",Zahlen[j]);
    }
    printf("\n");
}

int Eingabe(int **Zahlen)
{
    printf("Bitte geben sie die Anzahl der Elemente an, die sie eingeben moechten.\n");
    int Anzahl;
    scanf("%d", &Anzahl);
    if(*Zahlen){
        *Zahlen = (int *)realloc(*Zahlen, Anzahl*sizeof(int));
    }
    else{
        *Zahlen = (int *)malloc(Anzahl*sizeof(int));
    }
    if(!(*Zahlen)){
        return 0;
    }
    printf("Bitte geben sie nacheinander die Elemente ein.\n");

    int i;
    for(i = 0; i < Anzahl; ++i)
    {
        printf("Bitte Element %i eingeben...\n", i+1);
        scanf("%d", &(*Zahlen)[i]);
    }

    return Anzahl;
}

void heapsort(int Anzahl, int *Zahlen){
    Ausgabe(Anzahl, Zahlen);
};

//Menueauswahl//
int main(void)
{
    char wahl = ' ';
    int Anzahl = 0;
    int* Zahlen;
    while (wahl != 'B')
    {
        printf("     Hauptmenue\n");
        printf("     =========\n");
        printf("     (A)usgabe\n");
        printf("     (E)ingabe\n");
        printf("     (S)ortierung\n");
        printf("     (B)eenden\n");
        printf("     Bitte waehle einen Menuepunkt aus!\n");
        wahl = toupper(getchar());
        printf("---%c---\n", wahl);

        switch (wahl)
        {
            case 'A' : printf("\nAusgabe wurde gewaehlt!\n\n"); Ausgabe(Anzahl, Zahlen); break;
            case 'E' : printf("\nEingabe wurde gewaehlt!\n\n"); Anzahl = Eingabe(&Zahlen); break;
            case 'S' : printf("\nSortierung wurde gewaehlt!\n\n"); heapsort(Anzahl, Zahlen); break;
            case 'B' : printf("\nDas Programm wird beendet...\n\n"); break;
            default  : printf("\nFalsche Taste!\n\n"); break;

        }
    }
    free(Zahlen);
}

Edit: Speicherfehler korrigiert.
 
Zuletzt bearbeitet:
Ebrithil schrieb:
Du hast immer noch einen Denkfehler bei dem Return. Du returnst nicht das ganze Array Eingabe[] sondern nur den einen Wert an der Stelle Eingabe[anzahl].
Außerdem solltest in der For-Schleife bei i=0 anfangen, da ein Array a von der Länge 15 nicht von a[1]-a[15], sondern von a[0]-a[14] geht.

Ja, danke :)
Das hab ich vorhin auch gemerkt, als er mir nur eine Zahl ausgespuckt hatte.

Aber immerhin wird's langsam.
Schon mal Danke an alle, die mir bisher geholfen haben. Echt super! :)

Den Code für Heapsort hab ich zum Glück, weil wir den in einer Vorlesung mal probeweise durchgegangen sind ;)

Werd dann das mit dem Array mal über Pointer versuchen, damit ich in der Output() darauf zugreifen kann.
 
Du musst int* Zahlen schon am Anfang auf 0 setzen, wenn du später prüfst, ob Zahlen 0 ist...
 
Bitte hol dir ein C-Buch für Einsteiger oder such ein Tutorial und wenn du damit fertig bist (dauert bloß ein paar Tage), dann kannst du anfangen heapSort zu programmieren. Solange dir die Grundlagen fehlen verlierst du einfach viel zu viel Zeit mit dem Versuch herauszufinden, was genau jeweils nicht funktioniert und die Antworten von Leuten zu verstehen, die dir beim Debuggen helfen wollen.
 
Magogan schrieb:
Du musst int* Zahlen schon am Anfang auf 0 setzen, wenn du später prüfst, ob Zahlen 0 ist...

Meinst du jetzt bei meinem Code Zeile 25 bzw. 31?
Zahlen ist in demfall ein Doppelpointer, *Zahlen also immer noch ein Pointer und Pointer werden automatisch als Nullpointer initialisiert.
 
jumpin schrieb:
Pointer werden automatisch als Nullpointer initialisiert.
Wie kommst du denn auf die Idee? Oder ist das ein neues C11 - Feature, das mir entgangen ist?

Davon abgesehen glaube ich, dass es Magogan zum die Variable "Zahlen" in "main" ging (die ja an Eingabe und Ausgabe übergeben wird)
Ergänzung ()

Noch ein kleiner Verbesserungsvorschlag:
Code:
if(*Zahlen){
   *Zahlen = (int *)realloc(*Zahlen, Anzahl*sizeof(int));
}else{
    *Zahlen = (int *)malloc(Anzahl*sizeof(int)); 
}
kann man auch kürzer schreiben:
Code:
*Zahlen = realloc(*Zahlen, Anzahl*sizeof(**Zahlen));
Realloc prüft bereits intern, ob der übergebene Pointer ein nullpointer ist und macht in dem Fall einen Fallback auf malloc. Außerdem is es in C glaube ich Best-Practice, den Rückgabewert von malloc/realloc nicht explizit zu casten (wen es interessiert, der kann sich die Diskussionen dazu auf stack_overflow durchlesen)
 
Zuletzt bearbeitet:
Wie kommst du denn auf die Idee? Oder ist das ein neues C11 - Feature, das mir entgangen ist?
Es ist und bleibt undefined behaviour und die Compiler machen da auch unterschiedliche Dinge mit. Testprogramm:

Code:
#include <stdio.h>
int testPointer(void* p) {
  return p == NULL;
}


int main(int argc, char** argv) {
  int* a;
  printf("%d\n", testPointer(a));
  return 0;
}

GCC-Code:
Code:
0000000000400510 <main>:
  400510:       48 83 ec 08             sub    rsp,0x8
  400514:       be 01 00 00 00          mov    esi,0x1
  400519:       bf c4 05 40 00          mov    edi,0x4005c4
  40051e:       b8 00 00 00 00          mov    eax,0x0
  400523:       e8 b8 fe ff ff          call   4003e0 <printf@plt>
  400528:       b8 00 00 00 00          mov    eax,0x0
  40052d:       48 83 c4 08             add    rsp,0x8
  400531:       c3                      ret

Clang-Code:
Code:
00000000004004f0 <testPointer>:
  4004f0:       48 85 ff                test   rdi,rdi
  4004f3:       0f 94 c0                sete   al
  4004f6:       0f b6 c0                movzx  eax,al
  4004f9:       c3                      ret    

0000000000400500 <main>:
  400500:       50                      push   rax
  400501:       e8 ea ff ff ff          call   4004f0 <testPointer>
  400506:       89 c1                   mov    ecx,eax
  400508:       bf a4 05 40 00          mov    edi,0x4005a4
  40050d:       31 c0                   xor    eax,eax
  40050f:       89 ce                   mov    esi,ecx
  400511:       e8 aa fe ff ff          call   4003c0 <printf@plt>
  400516:       31 c0                   xor    eax,eax
  400518:       5a                      pop    rdx
  400519:       c3                      ret

GCC nimmt den Pointer als NULL an und elimitiert den Call, weswegen immer 1 ausgegeben wird. Das Clang-Programm testet irgendeinen Wert und gibt in der Regel 0 aus.
 
Zuletzt bearbeitet:
Zurück
Oben