Formaler Parameter = globale variable oder = "Platzhalter?

Gast #6255604
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?
Gast #6255610
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
Gast #6255618
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 ;)
#6255637
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.
Gast #6255957
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
#6256004
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 ?
#6256051
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.
Gast #6256135
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...
Gast #6256376
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
Gast #6257286
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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren