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


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Der Lernende (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Definiere Funktion
int summe (int n)

Dann folgendes:
int summe (int n) //Funktionskopf
{
int i;
int zwsumme = 0;
for (i = 1; i <= n; i = i + 1) //Funktionsrumpf
zwsumme = zwsumme + i;
return zwsumme;
}
der Wert von zwsumme wird durch return an int n weitergeben?
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)


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

von Der Lernende (Gast)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht lesenswert
Nee, das hast Du nicht richtig interpretiert.
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
int summe(int);

Dein späterer Funktionsaufruf wäre also:
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.
int i = 0;
int zwsumme = 0;
for(i = 0; i<n; i++) {
  zwsumme = zwsumme + 5;
}

Dann unterscheiden sich auch ergebnis und Parameter ;)

von cppbert (Gast)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


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

Nein

von DPA (Gast)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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
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
int summe (int n) // ich bin immernoch für unsigned!
{
  if(n < 1) return n; // Vollbremsung

  int mxroot = sqrt(INT_MAX); // sollte man als Konstante definieren  falls man die funktion öfter aufruft mMn

  if (n > 14142 * mxroot /10000) // Summe(n) ist grösser als INT_MAX
    return 0;    // 0 zurückgeben
  
  if (n > (INT_MAX-n)/n) // 2xSumme(n) ist grösser als INT_MAX
  {
    int ret = (mxroot*mxroot+mxroot)/2; // auch dieser Wert ist eine Konstante eigentlich
    for (; n>mxroot; n--)
      ret += n;
    return ret;

    /* mMn besser:
    long ret = n*n+n;
    return (int) ret/2;
    */
  }
  return (n*n+n)/2; // schnell und problemlos
}

nur so als skizzierte Richtung...
denn ernsthafterweise ist mir n pauschales long lieb was das angeht..
das säh dann so aus:
int summe (int n)
{
  if ((n < 1) || (n > 14142 * sqrt(INT_MAX) /10000))
    return 0;

  long ret = n*n+n;
  return (int)ret/2;
}
scheint mir schöner zu lesen und ist vermutlich auch schneller ;)

'sid

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.