Forum: PC-Programmierung Formaler Parameter = globale variable oder = "Platzhalter?


von Der Lernende (Gast)


Lesenswert?

Definiere Funktion
1
int summe (int n)

Dann folgendes:
1
int summe (int n) //Funktionskopf
2
{
3
int i;
4
int zwsumme = 0;
5
for (i = 1; i <= n; i = i + 1) //Funktionsrumpf
6
zwsumme = zwsumme + i;
7
return zwsumme;
8
}
der Wert von zwsumme wird durch return an int n weitergeben?
1
resultat = summe (eingabe);
eingabe ist der aktuelle Parameter bzw. das Argument der
Funktion summe().

Warum geht man den Umweg über int n, wenn man doch dann einen anderen 
parameter nutzt? Dient int n als Platzhalter und die aktuelle Variable 
kann dadurch variieren?

von Der Lernende (Gast)


Lesenswert?

und ja, wenn wir bei c sind, hätte ich im Betreff == nutzen sollen =)

von Der Lernende (Gast)


Lesenswert?

Der Lernende schrieb:
> for (i = 1; i <= n; i = i + 1)

verdammt, ich hatte das nichtb gesehen. Also n bestimmt die Anzahl der 
Durchläufe

von cppbert (Gast)


Lesenswert?

> Warum geht man den Umweg über int n, wenn man doch dann einen anderen
> parameter nutzt? Dient int n als Platzhalter und die aktuelle Variable
> kann dadurch variieren?

Was meinst du mit Umweg?, n ist einfach ein Parameter der Funktion und 
das Ergebnis ist ein voellig anderer Wert - formuliere deine Frage bitte 
anders

von Der Lernende (Gast)


Lesenswert?

Der Lernende schrieb:
> zwsumme wird durch return an int n weitergeben?

stimmt auch nicht, sondern tritt an die Stelle der Funktion

von Nülli (Gast)


Lesenswert?

Nee, das hast Du nicht richtig interpretiert.
1
int summe (int n);

In diesem Prototyp erklärst Du dem Compiler, dass es eine Funktion gibt, 
die

1) einen 'int' als Wert zurückgibt
2) "summe" heisst
3) einen integer (n) als Parameter hat

Wobei der Name des PArameters (n) hier gar keine Rolle spielt. Es reicht
1
int summe(int);

Dein späterer Funktionsaufruf wäre also:
1
int ergebnis = summe(20);


Und in der Funktion, die Du daoben geschrieben hast, würde der wert 20 
nun
im Aktualparameter (int n) entgegengenommen und steht so innerhalb der 
Funktion als Variable zur Verfügung.

In der for-Schleife verwendest Du ihn dann ja auch um 'n' mal die 
Variable zwsumme zu inkrementieren.

zwsumme hat dann hinterher den gleichen Wert wie n... und wird zum 
Schluss per return() zurückgegeben.

Die Funktion macht so natürlich wenig Sinn.

Aber Du kannst ja mal Deine for-Schleife etwas abändern und zwsumme in 
jedem Durchlauf nicht um 1, sondern um 5 erhöhen.
1
int i = 0;
2
int zwsumme = 0;
3
for(i = 0; i<n; i++) {
4
  zwsumme = zwsumme + 5;
5
}

Dann unterscheiden sich auch ergebnis und Parameter ;)

von cppbert (Gast)


Lesenswert?

Nülli schrieb:
> zwsumme hat dann hinterher den gleichen Wert wie n... und wird zum
> Schluss per return() zurückgegeben.

Nein

von Jim M. (turboj)


Lesenswert?

Der Lernende schrieb:
> verdammt, ich hatte das nichtb gesehen. Also n bestimmt die Anzahl der
> Durchläufe

Der Code im OP ist ein verdammt schlechtes Beispiel, denn die Summer 
1..n ist offensichtlich gleich n*(n+1)/2 (gaußsche Summenformel).

Ein Programmierer sollte gut genug in Mathe sein um das sofort zu sehen.

Die Schleife bräuchte man wenn man z.B. die ersten n Elemente eines 
Arrays aufsummieren möchte.

von Dirk B. (dirkb2)


Lesenswert?

Jim M. schrieb:
> Ein Programmierer sollte gut genug in Mathe sein um das sofort zu sehen.

Aber auch gut genug, um zu sehen dass es im Grenzbereich (n*(n+1) > 
INT_MAX) zu unterschiedlichen Ergebnissen kommt.

von sid (Gast)


Lesenswert?

Dirk B. schrieb:
> Aber auch gut genug, um zu sehen dass es im Grenzbereich (n*(n+1) >
> INT_MAX) zu unterschiedlichen Ergebnissen kommt.

Während ich Dir da recht geben wollte;
hat Jim aber dennoch Recht was die Unsinnigkeit der Schleife angeht..

sollte n²+n > INT_MAX
kann man das Ergebniss noch immer Retten;
und sollte (n²+n)/2> INT_MAX ist eh alles verloren (naja ebenfalls 
rettbar aber eben nichtmehr mit der Funktion mit deklarierter 
int-Rückgabe.

Nun reicht also eine Vorab-Prüfung ob n nur halbsoviele bits hat wie 
INT_MAX
für eine 32bit uint also 65535 oder kleiner
( 65535²+65535 erzeugt nur 1111 1111 1111 1111 0000 0000 0000 0000 
schön, oder?)
und das Muster ist immer dasselbe egal ob man 8,16,32,64 oder welchen 
zweier-exponenten man auch immer nutzt.
das wär also schonmal leicht.

Grenzfälle (2^(log2(INT_MAX)/2)< n < 2^((log2(INT_MAX)/2)+1))
sind ebenfalls leicht an den bits abzuzählen
können aber direkt einfach vermieden werden indem man der Hilfsvariable 
ein ulong verpasst, gell ;)
(Son Tee am mittag kann ganz schön beruhigend sein ;))

Insofern:
Ich bin da ganz auf Jim's Seite

'sid

von Dirk B. (dirkb2)


Lesenswert?

sid schrieb:
> sollte n²+n > INT_MAX
> kann man das Ergebniss noch immer Retten;

Richtig. Aber wenn man es nicht bedenkt, verhalten sich die Funktionen 
unterschiedlich.

> und sollte (n²+n)/2> INT_MAX ist eh alles verloren

Dafür steht dann in der Referenz zur Funktion das maximale n drin, bzw 
es wird ein Fehler gesetzt.

Das ist halt Programmiererwissen. Sonst könnte das ja jeder ?

von Rolf M. (rmagnus)


Lesenswert?

Der Lernende schrieb:
> der Wert von zwsumme wird durch return an int n weitergeben?

So ganz verstehe ich nicht, was du damit sagen willst. n hat mit dem 
return oder mit zwsumme nichts zu tun.

> resultat = summe (eingabe);
> eingabe ist der aktuelle Parameter bzw. das Argument der
> Funktion summe().

Ja.

> Warum geht man den Umweg über int n, wenn man doch dann einen anderen
> parameter nutzt?

Welchen anderen? Es gibt nur n. Und was meinst du mit "Umweg"? Ich sehe 
hier keinen Umweg.

> Dient int n als Platzhalter und die aktuelle Variable kann dadurch variieren?

in n ist der Parameter. Das Argument, das du beim Aufruf übergibst, wird 
dort hinein kopiert. Innerhalb der Funktion lässt sich n wie eine 
gewöhnliche lokale Variable verwenden.

von Teo D. (teoderix)


Lesenswert?

Der Lernende schrieb:
> der Wert von zwsumme wird durch return an int n weitergeben?

Nein

von DPA (Gast)


Lesenswert?

Der Stack in modernen Programiersprachen, wie z.B. C, ist ein echter 
Luxus. In, z.B. fortran, gab es das früher nicht. Heute kann man das 
dort mittlerweile wohl angeben, wenn den bei ner Funktion braucht. Und 
das ist nicht die einzige solche Sprache, mit der ich schon das 
Vergnügen hatte. Bei denen verhalten sich die Variablen meistens 
tatsächlich ein bisschen wie globale variablen, was dann echt lustig 
wird, wenn man mal ne Rekursion bräuchte...

von Yalu X. (yalu) (Moderator)


Lesenswert?

DPA schrieb:
> Der Stack in modernen Programiersprachen, wie z.B. C, ist ein echter
> Luxus. In, z.B. fortran, gab es das früher nicht.

Dafür hatte man in klassischen Fortran- und auch Cobol-Implementationen
den Luxus, keine Stack-Overflows befürchten zu müssen :)

von sid (Gast)


Lesenswert?

Dirk B. schrieb:
> Dafür steht dann in der Referenz zur Funktion das maximale n drin, bzw
> es wird ein Fehler gesetzt.
>
> Das ist halt Programmiererwissen.

Naja wenn Du jetzt Einschränkungen für n definierst, dann ist Dein 
erster Einwand auch überflüssig, denn diese (bei zugegeben kleineren n) 
hätten das Problem ja auch gelöst nicht wahr? ;)

Oder willst DU mir weissmachen Du hast das Programmiereerwissen erst in 
den letzten paar Stunden erlangt? Na eben.

'sid

von Dirk B. (dirkb2)


Lesenswert?

sid schrieb:
> denn diese (bei zugegeben kleineren n)
> hätten das Problem ja auch gelöst nicht wahr? ;)

klar, aber ein höheres n ist doch besser.

von sid (Gast)


Lesenswert?

Dirk B. schrieb:
> sid schrieb:
>> denn diese (bei zugegeben kleineren n)
>> hätten das Problem ja auch gelöst nicht wahr? ;)
>
> klar, aber ein höheres n ist doch besser.

Nuja, aber dann reden wir schnell von BigInt libraries;

denn wie gesagt, ne long Krücke danebengestellt nutzt ja die volle 
int-Breite aus und kostet den Programmierer ein müdes Lächeln um solche 
Fehler zu umgehen.

Ne simple Abfrage vor dem berechnen kann auch n rudimentären "Fehler"
ausgeben .. q&d sowas wie
1
if ((n > 0) && (n > (INT_MAX-n) /n)) return 0;
wenn man long nicht mag
oder man zweigt dann ab,
berechnet die Summe für n^(log2(INT_MAX)/2)
(ist ja konstant bei bekanntem INT_MAX zum glück.. man 'merkt' sie sich 
einfach)
und fängt an der Stelle an zu addieren
also bei i=sqrt(INT_MAX)
(wieso auch immer man son blödsinn machen wollte)
spart man sich immernoch ne gaaanze Menge an Rechenezeit

die grenze von n ist ja immer 14142 * sqrt(INT_MAX) /10000
(int approx für Wurzel Zwei mal wurzel int_max)
das weiss man ja auch schon vorher (wenn man in Mathe aufgepasst hat)

Oder kurz.. im Grunde wär ich dann für etwas wie
1
int summe (int n) // ich bin immernoch für unsigned!
2
{
3
  if(n < 1) return n; // Vollbremsung
4
5
  int mxroot = sqrt(INT_MAX); // sollte man als Konstante definieren  falls man die funktion öfter aufruft mMn
6
7
  if (n > 14142 * mxroot /10000) // Summe(n) ist grösser als INT_MAX
8
    return 0;    // 0 zurückgeben
9
  
10
  if (n > (INT_MAX-n)/n) // 2xSumme(n) ist grösser als INT_MAX
11
  {
12
    int ret = (mxroot*mxroot+mxroot)/2; // auch dieser Wert ist eine Konstante eigentlich
13
    for (; n>mxroot; n--)
14
      ret += n;
15
    return ret;
16
17
    /* mMn besser:
18
    long ret = n*n+n;
19
    return (int) ret/2;
20
    */
21
  }
22
  return (n*n+n)/2; // schnell und problemlos
23
}

nur so als skizzierte Richtung...
denn ernsthafterweise ist mir n pauschales long lieb was das angeht..
das säh dann so aus:
1
int summe (int n)
2
{
3
  if ((n < 1) || (n > 14142 * sqrt(INT_MAX) /10000))
4
    return 0;
5
6
  long ret = n*n+n;
7
  return (int)ret/2;
8
}
scheint mir schöner zu lesen und ist vermutlich auch schneller ;)

'sid

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.