C Schwierigkeiten mit C-Aufgabe

DRQ

Lt. Junior Grade
Registriert
Okt. 2008
Beiträge
398
Ich hab aktuell eine Aufgabe für C-Programmierung, an der ich mir die Zähne ausbeiße... Ich komme einfach nicht auf die Lösung.
Gegeben ist ein Beispiel-Programm:

#include <stdio.h>
struct student
{
char vorname[30];
char name[30];
int punkte;
};
void ausgabe(struct student *zeiger)
{
zeiger->vorname[2]='i';
printf("\n %s %s ",zeiger->vorname,zeiger->name);
printf(" hat %d Punkte",zeiger->punkte);
}
main()
{
struct student daten = {"Egon","Mustermann",55};
daten.punkte=72;
daten.vorname[1]='r';
ausgabe(&daten);
while(1);
}

Jetzt gibts folgende Aufgabe: "Schreiben Sie das Beispielprogramm so um, dass eine Eingabe der Daten über die Tastatur möglich ist. Verwenden Sie für die Eingabe der Daten eine weitere Funktion. Sollte diese Funktion vom Typ „Call by Value“ oder vom Typ „Call by Reference“ sein ?"

Ich krieg das umschreiben einfach nicht auf Kette...
Ich würd mich über Hilfe echt freuen! MfG, DRQ
 
Weißt du denn, wie man in C (wobei das hier ja C++ ist), eine Eingabe über die Konsole tätigt? Es geht mit dem Befehl cin. Sind dir die Begriffe "Call by Value" und "Call by Reference" klar?
 
Ich werf mal die Stichworte in den Raum:
-scanf();
-void eingabe(call by value oder call by reference muss hier entschieden werden);
 
andy_0 schrieb:
(wobei das hier ja C++ ist) [...] Es geht mit dem Befehl cin.
Wo siehst du da C++? Für mich ist das normales C89 :o
Und einlesen bitte auch nicht mit cin (C++, außerdem übrigens kein Befehl, sondern Objekt der Klasse istream), sondern mit scanf(...).

Gefragt ist wohl nach einer Methode void leseStudent(...), der Du einen Pointer auf einen struct student gibst, dass die entsprechenden Felder mit Inhalt füllt.
 
Call by Value und Reference sind soweit recht klar. Das hier ist aber C und nicht C++, alles andere würd mich schon recht wundern.
Ich hab halt Schwierigkeiten die Unterfunktion einzubringen. Ich müsste doch eine schreiben, mit scanf und die dann in Main einbinden. Aber genau das bekomme ich einfach nicht auf Kette.
 
@ Kanibal, DRQ
Auf den schnellen Blick dachte ich hier wird etwas dynamisch erzeugt, deswegen C++ ;).

@ DRQ
Schreib doch einfach mal den notwendigen Befehl so, dass er in der main() läuft. Dann hast du schon einen großen Schritt getan. Anschließend erstellst du eine Funktion eingabe() und verschiebst den Code von main() dorthin. Jetzt wird dir irgendwann klar, dass du an eingabe() den struct übergeben musst. Wie machst du das? Irgendwie so wie bei "ausgabe(struct student *zeiger)".

@ Kanibal
Cin ist genauso ein Befehl, wie alle Anweisungen in einer Programmiersprache ein Befehl darstellt. Würde man deine Logik befolgen, hätten manche Programmiersprachen keine Datentypen mehr, sind ja schließlich alles Objekte (welche wiederum in Klassen eingebunden sind) ...

Woran du dich WOMÖGLICH störst, wäre der Begriff Operator gewesen.
 
Richtig, du brauchst eine Unterfunktion, welche die Variablen des Structs mit Hilfe der scanf-Funktion einliest. Diese Unterfunktion kann, wie Kanibal vorgeschlagen hat, "void leseStudent()" heißen:

Code:
void leseStudent(struct student *zeiger)
{
    printf("Bitte Vornamen eingeben: ");
    scanf("%s", zeiger->vorname);
    getchar();
    printf("Bitte Nachnamen eingeben: ");
    scanf("%s", zeiger->name);
    getchar();
    printf("Bitte Punkte eingeben: ");
    scanf("%d", &zeiger->punkte);
}

Wir übergeben der Funktion einen Zeiger des Typs "struct student". Wir lesen nun mit Hilfe von scanf() die Variablen "vorname", "name" und "punkte" ein. Die scanf()-Funktion erwartet als zweiten Parameter eine Adresse. Da char-Arrays meines Wissens nach selbst Zeiger auf Adressen sind (Bin selbst kein Informatiker), müssen wir in den Fällen "vorname" und "name" den Operator "&" nicht verwenden.
Die Variable "punkte" ist vom Typ int und muss deshalb mit dem Adress-Operator "&" innerhalb der scanf()-Funktion versehen werden.
Die Aufrufe von getchar() dienen nur dazu das Pufferproblem zu lösen.

Nun muss in main() noch unsere neue Funktion aufgerufen werden. Das kann dann z.B. so aussehen (ich habe den alten Code noch mit drin behalten):

Code:
void main()
{
    struct student daten = {"Egon","Mustermann",55};
    daten.punkte=72;
    daten.vorname[1]='r';
    ausgabe(&daten);

    printf("\n");
    leseStudent(&daten);
    ausgabe(&daten);
    while(1);
}

Ich denke, so müsste das in etwa der Aufgabenstellung entsprechen. Der Code überprüft allerdings nicht, ob die Benutzereingaben die Länge der Char-Arrays überschreitet. Das müsste man bei Bedarf noch dazu programmieren.
 
Oh super, da ist ja jetzt schon gut was zusammengekommen :)
Danke euch allen für die schnelle Hilfe! Ich werd mich jetzt gleich auch direkt dran setzen und die Geschichte fertig schreiben!
 
andy_0 schrieb:
@ Kanibal, DRQ
@ Kanibal
Cin ist genauso ein Befehl, wie alle Anweisungen in einer Programmiersprache ein Befehl darstellt. Würde man deine Logik befolgen, hätten manche Programmiersprachen keine Datentypen mehr, sind ja schließlich alles Objekte (welche wiederum in Klassen eingebunden sind) ...

cin ist definitiv KEIN "Befehl". Wenn ich in einem C++-Programm innerhalb einer Funktion / Methode einfach nur das cin-Objekt erwähne:

Code:
std::cin;

dürfte das zwar syntaktisch korrektes C++ sein, aber es hätte einfach null Effekt, da es nun mal eben kein Befehl sondern nur ein Objekt ist. Erst das Anwenden einer Methode / eine Operators auf das std::cin-Objekt stellt einen Befehl dar.
Ergänzung ()

HenMac10 schrieb:
Code:
void main()
{
    /* ... */
}

Böse böse! Die korrekt Signatur der main-Funktion in C heißt int main.
Ergänzung ()

Kanibal schrieb:
Wo siehst du da C++? Für mich ist das normales C89 :o.

Der Code, den er da stehen hat, legt C nahe, aber die Tatsache, daß in der Aufgabe call-by-reference erwähnt wird, impliziert C++, da C keine Referenzen kennt. Die Tatsache, daß die Aufgabe dann auch noch den C-Header <stdio.h> statt des C++-Äquivalents <cstdio> einzieht, führt mich zu dem Schluß, daß die "Lehrkraft", von dem er die Aufgabe bekommen hat, von Tuten und Blasen keine Ahnung hat.
 
Zuletzt bearbeitet:
Nee is nicht !

Call by Reference ist in ANSI-C ganz klar mit Adressoperator auf von mir aus einem static struct gegeben. ANSI_C klamüsert das dann auf, auf Offset zum Speicherwort. Alles hochgefährlich.

Call by Value meint da einzelne Variablen, auch die auf die ich Zeiger übergeben kann. Pointerarithmetics, die Leute tun sich schwer damit, und auch hochgefährlich, überhaupt Speicheradressen an schreibende Assemblerbefehle ohne Schutz zu übergeben. Um sich zu schützen vor wilden Zeigern, hat man mal die MMUs erfunden. Memory Management Units. Iss nicht Programm, hier läuft Betriebsystem im geschütztem Rahmen, Blue Screen. Protected fault wollte man so vermeiden. Da ein C Programm alles angreifen kann, fast wie Assembler hat man weiter ausgeholt. Nur die besten Programmierer der Welt schreiben Kernel in schierem schnellen C. Alle Anderen schreiben in Frameworks ihre Programme. Dann ist das hierarchisch auch stabil soweit.
 
Zuletzt bearbeitet:
Junge, hast du dir einen getrunken? Deine Ablenkung in dem anderen Thread mit void main() war ja schon grober Quatsch und jetzt auch noch hier.

Der Adressoperator gibt überhaupt kein Offset, sondern die Adresse der Variablen. Das ist überhaupt nicht gefährlich. Genauso, wie es nicht "hochgefährlich" ist, diese Adressen "ohne Schutz" zu übergeben. Eine MMU vermeidet auch keinen Protection Fault, sondern löst diesen überhaupt erst aus. Das ist gerade ihr Sinn. Und ein Programm kann auch nicht "alles angreifen", weil es in einer bestimmten Programmiersprache geschrieben ist. Gängige CPUs haben seit Jahrzehnten verschiedene Betriebsmodi, die unterschiedliche Berechtigungen haben. Siehe Supervisor Mode bzw. Hypervisor mode. Die Tatsache, einen Kernel zu schreiben, bringt mit sich, dass man leider kein Framework hat, in dem man sich bewegen kann, sondern wenn man eines möchte, dieses selbst implementieren muss. Und die Existenz eines Frameworks heißt auch nicht, dass dann auch alles "hierarchisch stabil" läuft. Also eigentlich war jeder einzelne Satz von dir Bullshite.
 
antred schrieb:
Der Code, den er da stehen hat, legt C nahe, aber die Tatsache, daß in der Aufgabe call-by-reference erwähnt wird, impliziert C++, da C keine Referenzen kennt.
Es wird sogar noch besser:
Code:
#include <stdio.h>

void func(char arr[]) {
    printf("(func)  => %p\n", arr);
    printf("(func)  => %s\n", arr);
}

void func2(char arr[]) {
    printf("(func2) => %p\n", arr);
    arr[5] = 'M';
}

int main() {
    char foo[] = {'H','e','l','l','o','W','o','r','l','d','\0'};
    printf("(main)  => %p\n", foo);
    func(foo);
    func2(foo);
    func(foo);
    return 0;
}
Ausgabe: http://codepad.org/7ryDoCgT
Arrays werden in C IMMER per Call-by-Reference übergeben (einzige Ausnahme: Container-structs.).

Ansonsten möchtest Du dir vielleicht den Address-Of-Operator ansehen ;-)
 
Willst du mich veräppeln? Zeiger sind für mich keine Referenzen, auch wenn sie stark ähnlich sind. Und der Address-Operator gibt dir eben die Adresse des Operanden, also effektiv einen Pointer - keine Referenz.

EDIT: Das muß ich vielleicht etwas präzisieren. Ein wichtiges Merkmal von Referenzen, das Zeiger nicht haben, ist daß der Zugriff auf das referenzierte Datum syntaktisch völlig transparent erfolgt - also eben OHNE Zeigersemantik. Gut, bei Arrays ist das sogar in C gegeben, aber in allen anderen Fällen eben nicht.

EDIT 2: Na ja, genau genommen bekommen deine func() und func2()-Funktionen keine Arrays sondern Zeiger übergeben, da das Array bei Übergabe an die Funktion einfach zu einem Zeiger "verfällt".
Den Unterschied wirst du merken, wenn du in der func()-Funktion mal versuchst, mit sizeof die Größe des Arguments zu nehmen. Hättest du innerhalb der Funktion tatsächlich immer noch ein Array, würdest du hier die Größe des Arrays in Byte bekommen. Stattdessen wirst du nur die Größe des Zeigers kriegen.
 
Zuletzt bearbeitet:
Zurück
Oben