• Keine Ergebnisse gefunden

Refenzen in C

N/A
N/A
Protected

Academic year: 2022

Aktie "Refenzen in C"

Copied!
6
0
0

Wird geladen.... (Jetzt Volltext ansehen)

Volltext

(1)

Korrekte Software: Grundlagen und Methoden Vorlesung 12 vom 09.07.20 Referenzen und Speichermodelle

Serge Autexier, Christoph Lüth Universität Bremen Sommersemester 2020

10:35:18 2020-07-16 1 [42]

Prüfungstermine

IMo, 20.07.2020: Präsenzprüfungen (9:00- 16:30, je zur vollen Stunde)

IDi, 21.07.2020: Onlineprüfungen (9:00- 13:00, alle 30 Minuten)

IMo, 24.08.2020: Präsenzprüfungen (9:00- 16:30, je zur vollen Stunde)

IDi, 25.08.2020: Onlineprüfungen (9:00- 13:00, alle 30 Minuten)

Korrekte Software 2 [42]

Prüfungsmodalitäten

IAnmeldung über stud.ip.

IPräsenzprüfungen:

IIm Raum 4380

IBittenicht vor dem Prüfungsraum versammeln(sondern kurz vorher hochkommen)

IWichtig: Ausweispapiere mitbringen, unten am MZH ausweisen. Eingang ins MZH nur über die Ostseite (zur Enrique-Schmidt-Straße).

IOnlineprüfung:

IÜber Zoom, gleiche Meeting-Id wie gewohnt.

IWir lassen euch zur Prüfung in das Meeting, alle anderen bleiben draussen.

IEine Kamera istzwingenderforderlich.

IDie Prüfung muss in einem ruhigen Raum stattfinden. Es darf sich keine weitere Person im Raum befinden. Hilfsmittel sind nicht zugelassen.

Korrekte Software 3 [42]

Fahrplan

IEinführung

IOperationale Semantik IDenotationale Semantik

IÄquivalenz der Operationalen und Denotationalen Semantik IDer Floyd-Hoare-Kalkül

IInvarianten und die Korrektheit des Floyd-Hoare-Kalküls IStrukturierte Datentypen

IVerifikationsbedingungen IVorwärts mit Floyd und Hoare IModellierung

ISpezifikation von Funktionen IReferenzen und Speichermodelle IAusblick und Rückblick

Korrekte Software 4 [42]

Motivation

IWarum Referenzen?

INötig fürcall by reference

IFunktion können sonst nurglobaleSeiteneffekte haben IEffizienz

IKurze Begriffsklärung:

IReferenzen: getypt, eingeschränkte Arithmetik IZeiger: ungetypt, Zeigerarithmetik

Korrekte Software 5 [42]

Refenzen in C

IPointer in C (“pointer type”):

ISchwach getypt (void∗kompatibel mit allen Zeigertypen, Typumwandlung)

IEingeschränkte Zeigerarithmetik (Addition, Subtraktion) IFelder werden durch Zeigerarithmetik implementiert IPointer sindfirst-class-values

IC-Standard läßt das Speichermodell relativ offen IRepräsentation von Objekten

Korrekte Software 6 [42]

Referenzen in anderen Sprachen

IJava:

I(Fast) alles ist eine Referenz

ISchwach getypt (Subtyping und Typumwandlung) IHaskell, SML, OCaml:

IStark getypt (typsicher) IScriptsprachen (Python, Ruby):

IÄhnlich Java

Korrekte Software 7 [42]

Ausdrücke

INeue Operatoren: Addressoperator (&a) und Derefenzierung (∗l) Lexpl::=Idt|l[a]|l.Idt|∗a

Aexpa::=Z|C|Lexp|&l

|a1+a2|a1a2|a1a2|a1/a2|Idt(Exp) Bexp b::=. . .

Expe:=Aexp|Bexp Stmtc::=. . .

Typet::=char|int|∗t|structIdt?{Decl+} |tIdt[a]

Korrekte Software 8 [42]

(2)

Das Problem mit Zeigern

IBisheriges Speichermodell: Σ =Loc*V IAliasing:

Verschiedene Bezeichner (Lexp) für die gleiche LokationlLoc

i n t a ; i n t ∗p ;

p= &a ; a= 0 ; //{a= 0}

∗p= 7 ; //{a= 7}(*)

IWert vonaändert sichohne dass aerwähntwird.

IAn der Stelle (*) zwei Bezeichner für die gleiche Loc:aund∗p IGroßes Problem für Semantik und

Hoare-Kalkül.

IModellierung der Zuweisung durch Substitution nicht mehr möglich

Korrekte Software 9 [42]

Erweiterung des Zustandmodells

IBisheriger Zustand Σ=defLoc*Vmit ILocations:Loc::=Idt|Loc[Z]|Loc.Idt IWerte:V=Z

IAnsatz reicht nicht mehr:

(i)Werte müssen auch Locations sein:Vdef=Z+Loc

(ii)Idtals Location nicht ausreichend für Referenzen und Funktionen IMan kann den Zustandmodellbasiertoderaxiomatischbeschreiben.

Korrekte Software 10 [42]

Speichermodelle I: Konkret (Compiler)

Beispieldeklarationen:

i n t a ; s t r u c t {

i n t x ;

i n t y [ 3 ] } b [ 2 ] ; i n t c [ 3 ] ;

Übersetzung in konkretesSpeicherlayout:

a b c

b[0] b[1] c[0] c[1] c[2]

b[0].x b[0].y b[1].x b[1].y

b[0].y[0] b[0].y[1] b[0].y[2] b[1].y[0] b[1].y[1] b[1].y[2]

0 1 2 3 4 5 6 7 8 9 10 11

Denotatation vonb[0].y[1] ist 3

Korrekte Software 11 [42]

Speichermodelle II: Abstrakt (C-Standard)

Beispieldeklarationen:

i n t a ; s t r u c t {

i n t x ;

i n t y [ 3 ] } b [ 2 ] ; i n t c [ 3 ] ;

Übersetzung in abstraktesSpeicherlayout:

a b c

b[0] b[1] c[0] c[1] c[2]

b[0].x b[0].y b[1].x b[1].y

b[0].y[0] b[0].y[1] b[0].y[2] b[1].y[0] b[1].y[1] b[1].y[2]

l m+0 m+1 m+2 m+3 m+4 m+5 m+6 m+7 n n+1 n+2

Denotatation vonb[0].y[1] istm+ 3, mitmunbestimmteAdresse

Korrekte Software 12 [42]

Speichermodelle III: Symbolisch

Beispieldeklarationen:

i n t a ; s t r u c t {

i n t x ;

i n t y [ 3 ] } b [ 2 ] ; i n t c [ 3 ] ;

Übersetzung in symbolische Adressen:

a b c

b[0] b[1] c[0] c[1] c[2]

b[0].x b[0].y b[1].x b[1].y

b[0].y[0] b[0].y[1] b[0].y[2] b[1].y[0] b[1].y[1] b[1].y[2]

Denotatation vonb[0].y[1] istm[0].y[1], mitmunbestimmte Adresse

Korrekte Software 13 [42]

Abstrakte Zeigerarithmetik

IAdressen sind ein abstrakter DatentypLocso dass:

IEs gibtunbestimmteAdressen IOperationoffaddiert Offset (Feldzugriff) IOperationfldselektiert Feld (struct) IProblem: Gleichheit und Ungleichheit

off:LocZLoc off(l,0) =l off(off(l,a),b) =off(l,a+b)

off(l,a) =l=⇒a= 0 off(l,a) =off(l,b) =a=b

fld:LocIdtLoc fld(l,f)6=l fld(l,f) =fld(l,g) =⇒f =g fld(l,f) =fld(m,f) =⇒l=m f 6=g=⇒fld(l,f)6=fld(m,g)

Korrekte Software 14 [42]

Arbeitsblatt 12.1: Jetzt mit Zeigern!

Hier eine weitere Folge von Deklarationen:

i n t ∗a [ 1 ] ; s t r u c t {

i n t p [ 2 ] ; s t r u c t {

i n t x ;

i n t y ; } ∗q [ 2 ] ; } b ;

ISkizziert hier das Speichermodell — konkret, abstrakt, symbolisch.

IWelches sind die jeweiligen Adressen (Loc)?

IWas sind die Denotationen füra [1], b.p [1], (∗b.q [0]). x, (∗b.q [1]). y?

IWelche davon sind definiert/undefiniert?

Axiomatisches Zustandsmodell

IDer Zustand ist ein abstrakter Datentyp Σ mit zwei Operationen und folgenden Gleichungen:

read: Σ→Loc*V upd: Σ→LocV*Σ

Vdef=Z+Loc

read(upd(σ,l,v),l) =v l6=m=⇒read(upd(σ,l,v),m) =read(σ,m)

upd(upd(σ,l,v),l,w) =upd(σ,l,w) l6=m=⇒upd(upd(σ,l,v),m,w) =upd(upd(σ,m,w),l,v)

IDiese Gleichungen sindvollständig.

(3)

Axiomatisches Speichermodell

IEs gibt einenleerenSpeicher, und neue (“frische”) Adressen:

empty: Σ fresh: Σ→Loc

rem: Σ→Loc→Σ IfreshmodelliertAllokation,remmodelliertDeallokation Idombeschreibt denDefinitionsbereich:

dom(σ) ={l| ∃v.read(σ,l) =v}

dom(empty) =

IEigenschaften vonempty,freshundrem:

fresh(σ)6∈dom(σ) dom(rem(σ,l)) =dom(σ)\ {l}

l6=m=⇒read(rem(σ,l),m) =read(σ,m)

Korrekte Software 17 [42]

Erweiterung der Semantik: Umgebung

IFür Funktionen brauchten wir eineUmgebung(Environment):

Env=Idt*[[FunDef]]

=Idt*VN*Σ*(Σ×Vu)

IDiese muss erweitert werden für Variablen:

Env=Idt*([[FunDef]]]Loc)

IInsbesondere: gleicher Namensraum für Funktionen und Variablen (C99 Standard, §6.2.3)

Korrekte Software 18 [42]

Kurze Frage

IWieso modellieren wirLocnicht als Datentyp (so wie bisher):

l::=Idt|l[Z]|l.Idt Dann wäreoff(l,n)def=l[n],fld(l,i)def=l.i.

I[[a]] wäre immera. Damit funktionieren drei Dinge nicht:

1 Wir können globale nicht von lokale Variablen unterscheiden.

2 Beim rekursiven Aufruf wird keine neue Instanz erzeugt.

3 Generell funktioniert call-by-reference nicht, z.B.

v o i d f (i n t ∗x ) {

i n t a ; a= ∗x ; }

v o i d g ( ) {

i n t a ; f (&a ) ; }

Korrekte Software 19 [42]

Erweiterung der Semantik: Problem

IProblem:Lochaben unterschiedliche Semantik auf der linken oder rechten Seite einer Zuweisung.

Ix = x+1— Links: Addresse der Variablen, rechts: Wert an dieser Adresse

ILösung in C: “Except when it is (. . . ) the operand of the unary&

oprerator, the left operand of the.operator or an assigment operator, an lvalue that does not have array type is converted to the value stored in the designated object (and is no longer an lvalue)”

C99 Standard, §6.3.2.1 (2)

INicht spezifisch für C

Korrekte Software 20 [42]

Erweiterung der Semantik: Lexp

[[−]]L:EnvLexp→Σ*Loc

[[x]]LΓ ={(σ,Γ!x)|σ∈Σ}

[[lexp[a]]]LΓ ={(σ,off(l,i))|(σ,l)∈[[lexp]]LΓ,(σ,i)∈[[a]]AΓ}

[[lexp.f]]LΓ ={(σ,fld(l,f))|(σ,l)∈[[lexp]]LΓ}

[[∗e]]LΓ =[[e]]AΓ

Korrekte Software 21 [42]

Erweiterung der Semantik: Aexp(1)

[[−]]A:EnvAexp→Σ*V

[[n]]AΓ ={(σ,n)|σ∈Σ} fürn∈N [[e]]AΓ ={(σ,read(σ,l))|(σ,l)∈[[e]]LΓ}

eLexpundekein Array-Typ [[e]]AΓ ={(σ,l)|(σ,l)∈[[e]]LΓ}

eLexpundeist Array-Typ [[&e]]AΓ ={(σ,l)|(σ,l)∈[[e]]LΓ}

Korrekte Software 22 [42]

Erweiterung der Semantik: Aexp(2)

[[−]]A:EnvAexp→Σ*V

[[a0+a1]]AΓ ={(σ,n0+n1|(σ,n0)∈[[a0]]AΓ∧(σ,n1)∈[[a1]]AΓ}

[[a0a1]]AΓ ={(σ,n0n1)|(σ,n0)∈[[a0]]AΓ∧(σ,n1)∈[[a1]]AΓ}

[[a0a1]]AΓ ={(σ,n0n1)|(σ,n0)∈[[a0]]AΓ∧(σ,n1)∈[[a1]]AΓ}

[[a0/a1]]AΓ ={(σ,n0/n1)|(σ,n0)∈[[a0]]AΓ∧(σ,n1)∈[[a1]]AΓ

n16= 0}

Korrekte Software 23 [42]

Erweiterung der Semantik: Stmt

[[x=e]]CΓ ={(σ,upd(σ,l,a))|(σ,l)∈[[x]]LΓ

∧(σ,a)∈[[e]]AΓ}

[[x=f(t1, . . . ,tn)]]CΓ ={(σ,upd(σ0,l,v))|(σ,(σ0,v))∈Γ(f)(v1, . . . ,vn)

∧(σ,vi)∈[[ti]]AΓ

∧(σ,l)∈[[x]]LΓ}

}

Korrekte Software 24 [42]

(4)

Arbeitsblatt 12.2: Pop-Quiz

Gegeben folgende Funktionen:

i n t f (i n t ∗x ) {

i n t a ; a= ∗x ;

∗x= a +1;

r e t u r n a ; }

i n t a [ 3 ] = { 0 , 0 , 0 } ; v o i d g ( )

{

i n t x= 1 ; a [ x ]= f (&x ) ; }

Was ist der Wert des Feldesaam Ende vong?

1 a == {0, 0, 1}

2 a == {0, 0, 2}

3 a == {0, 1, 0}

4 a == {0, 2, 0}

Korrekte Software 25 [42]

Arbeitsblatt 12.3: Kurze Semantik

Gegeben folgende Deklarationen:

s t r u c t { i n t x ; i n t y ; } p [ 5 ] ; i n t a ;

mit folgender Umgebung

Γ=defhp7→l1,a7→l2i,l16=l2 Berechnet die denotationale Semantik von a= a+ p [ 3 ] . x ;

Korrekte Software 26 [42]

Und jetzt?

IZustand erweitert, so dass wir Zeiger modellieren können.

ISemantik entsprechend erweitert.

IWas machen wir mit dem Hoare-Kalkül, speziell derZuweisung?

IVorherige Modellierung — Zuweisung durch Substitution modelliert — nicht mehr ausreichend.

IDaher:explizite Zustandsprädikate

Korrekte Software 27 [42]

Explizite Zustandsprädikate

IZusicherungenen (Assn) sind zustandsabhängige Prädikate

IMit anderen Worten, Prädikate über Programmvariablen.

IAxiomatische Beschreibung des Zustandes erforderte neue Modellierung auf der Ebene der Prädikate

IExplizite Zustandsprädikate modellieren die Zustandsoperationenread undupdexplizit

Korrekte Software 28 [42]

Explizite Zustandsprädikate

IErweiterung vonAexpvumread, neue SorteStatemit Operation upd:

Lexps l::=. . .| ∗a Assns b::=. . .

Aexps a::=read(S,l)|Z|C|l| &l |. . .|\old(e)|. . . State S::=StateVar|upd(S,l,e)

IZustandsvariablenStateVar:

IAktueller Zustandσ, Vorzustandρold, Zwischenzuständeρ0,ρ1,ρ2, . . . IExplizite Zustandsprädikate enthalten kein∗oder&

IIm Gegensatz zur Semantik rechnen wir mitsymbolischen Namen IDamit Semantik:

Bsp[[.]] :EnvAssns*(Σ×(Σ×VU))→B Asp[[.]] :EnvAexps*(Σ×(Σ×VU))→V

Korrekte Software 29 [42]

Hoare-Triple

Γ|={P}c{Q|R}

IP,Q,RAssnssindexplizite Zustandsprädikate

IDeklarationen (Decl) allozieren für jede Variable eine Location (fresh), und ordnen diese in Γ dem Namen zu.

IGültigkeit von Hoare-Tripeln (partielle, totale Korrektheit) wie vorher

Korrekte Software 30 [42]

Floyd-Hoare-Kalkül

Alte Regel

Γ` {Q[upd(σ,x,e)/σ]}x=e{Q|R}

IEinLexplauf der rechten Seiteewird durchread(σ,l) ersetzt.1 I&dient lediglich dazu, diese Konversion zuverhindern.

I∗erzwingtdiese Konversion, auch auf der linken Seitex.

IBeispiel:∗a =∗&b;

1Außerlist ein Array-Typ.

Formal: Konversion in Zustandsprädikate

(−):LexpLexps i=i (i∈Idt) l.id=l.id l[e]=l[e#]

∗l=l#

(−)#:AexpAexps e#=read(σ,e) (e∈Lexp) n#=n

v#=v (vlogische Variable)

&e#=e e1+e2#

=e1# +e2#

\result#=\result

\old(e)#=\old(e)

(5)

Angepasste Regeln des Hoare-Kalküls

Γ` {Q[upd(σ,x,e#)/σ]}x=e{Q|R}

Γ` {Q[e#/\result]}return e{P|Q}

Korrekte Software 33 [42]

Arbeitsblatt 12.4: Ein kurzes Beispiel

Betrachtet folgendes Beispiel:

v o i d f o o ( ) { i n t x , y , z ; x= 1 ; z= x ; y= x ; z= 5 ; //{0<y}

}

1 Konvertiert das Prädikat 0<yin ein explizites Zustandsprädikat.

2 Berechnet (rückwärts) die jeweils gültigen Zwischenzustände.

3 Vereinfacht nach jedem Schritt die Zwischenzustände.

Korrekte Software 34 [42]

Ein Beispiel mit Zeigern

v o i d f o o ( ) { i n t x , y , ∗z ; z= &x ; x= 0 ;

∗z= 5 ; y= x ; //{0<y}

Korrekte Software 35 [42]

Ein Beispiel mit Zeigern

v o i df o o ( ) { i n tx , y ,∗z ; /∗∗{ 0< 5 }∗/

/∗∗{ 0< r e a d ( upd ( . . . , x , 5 ) , x ) }∗/

/∗∗{ 0< r e a d ( upd ( upd ( upd ( s , z , x ) , x , 0 ) , x , 5 ) , x ) }∗/

/∗∗{ 0< r e a d ( upd ( upd ( upd ( s , z , x ) , x , 0 ) ,r e a d ( upd ( s , z , x ) , z ) ,5 ) , x ) }∗/

z= &x ;

/∗∗{ 0< r e a d ( upd ( upd ( s , x , 0 ) ,r e a d ( s ,z ) , 5 ) , x ) }∗/

/∗∗{ 0< r e a d ( upd ( upd ( s , x , 0 ) ,r e a d ( s , z ) , 5 ) , x ) }∗/

/∗∗{ 0< r e a d ( upd ( upd ( s , x , 0 ) ,r e a d ( upd ( s , x ,0 ) , z ) , 5 ) , x ) }∗/

x= 0 ;

/∗∗{ 0< r e a d ( upd ( s , r e a d ( s ,z ) , 5 ) , x ) }∗/

∗z= 5 ;

/∗∗{ 0< r e a d ( s , x ) }∗/

/∗∗{ 0< r e a d ( s , x ) }∗/

/∗∗{ 0< r e a d ( upd ( s , y , r e a d ( s , x ) , y ) }∗/

y= x ;

/∗∗{ 0< r e a d ( s , y ) }∗/

}

Korrekte Software 36 [42]

Ein problematisches Beispiel

v o i df o o (i n t∗p ) {

i n t x ;

//{read(upd(upd(s,x,7),read(s,p),99),x) = 7}

//{read(upd(upd(s,x,7),read(upd(s,x,7),p),99),x) = 7}

x= 7 ;

//{read(upd(s,read(s,p),99),x) = 7}

∗p= 9 9 ; //{read(s,x) = 7}

//{x= 7}

}

IKönnenwederbeweisen, dassread(s,p) =xnochread(s,p)6=x IErfordert Spezifikation: wenn∗pauf eingültigesObjekt zeigt, dann

∗p6=xdaxlokaleVariable.

IGenerelles Problem — was ist mit v o i d f o o (i n t ∗p , i n t ∗q ) { . . . }

IKönnen weder beweisen, dass∗p=∗qnoch∗p6=∗q

Korrekte Software 37 [42]

Weitere Beispiele: Felder

i n t f i n d m a x (i n t a [ ] , i n t a _ l e n ) /∗∗ pre \array(a,a_len)∧0<a_len; ∗/

/∗∗ post∀i.0i<a_len−→a[i]\result; ∗/

{

i n t x ; i n t j ; x= INT_MIN ; j= 0 ; w h i l e ( j < a _ l e n )

/∗∗ inv (∀i.0i<j−→a[i]x)ja_len; ∗/

{

i f ( a [ j ]> x ) x= a [ j ] ; j= j +1;

} r e t u r n x ; }

Korrekte Software 38 [42]

Felder und Zeiger revisited

IIn C sind Zeiger und Felder schwach spezifiziert IInsbesondere:

Ia[ j ]=∗(a+j)füraArray-Typ

IDerefenzierung von∗xnur definiert, wennx“gültig” ist (d.h. auf ein Objekt zeigt)C99 Standard, §6.5.3.2(4)

IBisher in den Hoare-Regeln ignoriert —partielleKorrektheit.

IIst das sinnvoll? Nein, bekannte Fehlerquelle

Korrekte Software 39 [42]

Spezifikation von Zeigern und Feldern

Das Prädikat\valid(x)

\valid(x)⇐⇒read(σ,x) ist definiert

IInsbesondere:\valid(∗x)⇐⇒read(σ,read(σ,x)) ist definiert.

IFelder als Parameter werden zu Zeigern konvertiert, deshalb müssen wir spezifizieren können, dass ein Zeiger ein Feld ist.

I\array(a,n) bedeutet:aist ein Feld der Längen, d.h.

\array(a,n)⇐⇒(∀i.0≤i<n=⇒\valid(a[i]))

IGültigkeit kann abgeleitet werden:

x= &e

\valid(*x)

\array(a, n) 0≤i i<n

\valid(a[i])

Korrekte Software 40 [42]

(6)

Was noch fehlt. . .

IVorwärtsrechungmit expliziten Zustandsprädikaten.

IStatt Existenzquantoren über Variablenwerteunbestimmte Zwischenzuständeρ1, ρ2, . . .:

ρi6∈FV(P)

Γ` {P}x=e{P[ρi/σ]σ=upd(ρi,xi/σ],e#i/σ])|R}

IZwischenzustände sindexistenzquantifiziert, d.h. das Prädikat gilt für irgendeinenZustandρi(aber für alleσ).

ISchwächsteVorbedingungund stärksteNachbedingung:

IErgibt sich aus den Hoare-Regeln.

IErfordert durchgängige und agressiveVereinfachung.

Korrekte Software 41 [42]

Zusammenfassung

IUm Referenzen (Pointer) in C behandeln zu können, benötigen wir ein erweitertesZustandsmodell

IReferenzen werden zu Werten wie Zahlen oder Zeichen.

IArrays und Strukturen sindkeinefirst-class values.

IGroßes Problem:aliasing

IErweiterung der Semantik und der Hoare-Tripel nötig:

IVor/Nachbedingungen werden zuexpliziten Zustandsprädikaten.

IZuweisung wird zuZustandsupdate.

IProblem:

IZustände werdensehr groß

IRückwärtsrechnung erzeugt schnell sehr große „unbestimmte“ Zustände, die nicht vereinfacht werden können

IHier ist Vorwärtsrechnung vorteilhaft

Korrekte Software 42 [42]

Referenzen

ÄHNLICHE DOKUMENTE

I Felder als Parameter werden Zeigern konvertiert, deshalb müssen wir spezifizieren können, dass ein Zeiger “in Wirklichkeit” ein Feld ist. I \array(a, n) bedeutet: a ist ein Feld

I Felder als Parameter werden Zeigern konvertiert, deshalb müssen wir spezifizieren können, dass ein Zeiger “in Wirklichkeit” ein Feld ist. I \array(a, n) bedeutet: a ist ein Feld

I Felder als Parameter werden Zeigern konvertiert, deshalb müssen wir spezifizieren können, dass ein Zeiger “in Wirklichkeit” ein Feld ist. I \array(a, n) bedeutet: a ist ein Feld

I Felder als Parameter werden Zeigern konvertiert, deshalb müssen wir spezifizieren können, dass ein Zeiger “in Wirklichkeit” ein Feld ist. I \array(a, n) bedeutet: a ist ein Feld

I Felder als Parameter werden Zeigern konvertiert, deshalb müssen wir spezifizieren können, dass ein Zeiger “in Wirklichkeit” ein Feld ist. I

conjunctivam tanquam telas inter se plane diversas esse statuunt, nihiiorainus tamen in tela, telae conjunctivae simili, corpuscula cart. inesse cognoverunt, easque igitur telas

TitrIC 2 Vollautomatisches System für die direkte Messung von Temperatur, Leitfähigkeit und pH-Wert, die titrimetrische Bestimmung von p- und m-Wert und die ionenchromato-

bool* begin = crossed_out; // pointer to first element bool* end = crossed_out + 1000; // pointer after last element // in the loop, pointer p successively points to all