Estructura de control

De la Viquipèdia, l'enciclopèdia lliure.
Saltar a la navegació Saltar a la cerca

En tots els paradigmes de programació imperatius , les estructures de control són construccions sintàctiques d’un llenguatge de programació la semàntica del qual pertany al control del flux d’ execució d’un programa , és a dir, serveixen per especificar si , quan , en quin ordre i quantes vegades s’han d’executar instruccions que componen el codi font segons les especificacions del projecte del programari a crear.

Estructures de control fonamentals

Seqüència

La seqüència és l'estructura de control fonamental de qualsevol llenguatge imperatiu, inclosos els llenguatges de màquina . Determina l'ordre en què s'han d'executar les instruccions del text del programa en temps d' execució . Com a regla general, no té una expressió sintàctica explícita: en canvi, ve donada per la simple successió d’instruccions; en aquest cas, la màquina abstracta del llenguatge en ús les executa en seqüència, una darrere l’altra.

Anar a

Juntament amb la seqüència, anar a (anar a) és l'estructura de control més senzilla; també apareix, d'alguna forma, en tots els llenguatges de la màquina . El significat general de goto és "saltar" o "passar" el control a una instrucció especificada, que pot estar a qualsevol part del programa. Aneu sempre (o només) admet una forma condicional , el significat de la qual es pot parafrasejar de la següent manera: "si la condició C és certa, aneu a la declaració I ". En els llenguatges de màquina, la condició C sol adoptar una de les dues formes següents: "el contingut de la cel·la de memòria M és 0" o "el contingut de la cel·la de memòria M és diferent de 0"; la instrucció I també s’identifica per l’ adreça de memòria on emmagatzema I. En llenguatges d'alt nivell com C , la condició C es pot expressar com qualsevol expressió booleana (ja que el resultat de multiplicar A per B és diferent de X ), i la instrucció I es pot identificar amb un nom o un codi numèric explícitament associats pel programador a la pròpia instrucció (independentment de la seva ubicació a la memòria).

Des dels anys setanta , l’estructura de control de Goto ha estat sotmesa a fortes crítiques ja que permet (o afavoreix) el desenvolupament de programes potencialment molt il·legibles i modificables (l’anomenat codi spaghetti ). Encara que segueix sent una estructura de control fonamental de llenguatges de màquina moderns, en els llenguatges de programació d'alt nivell, com pot ser el cas, anar a no es proporciona o es proporciona però el seu ús no es recomana.

Estructures de control de programació estructurada

El 1966 , amb un famós teorema , Corrado Böhm i Giuseppe Jacopini van introduir els fonaments teòrics del paradigma de programació estructurada demostrant que qualsevol programa escrit mitjançant l’estructura de control goto es podia reescriure utilitzant només seqüències , iteracions i estructures de control alternatives . Juntament amb les crítiques esmentades anteriorment, aquest resultat va contribuir al final de la programació basada en el vot . Tots els llenguatges moderns ofereixen un conjunt d’estructures de control dels tres tipus introduïts per Böhm i Jacopini, tot i que molts també conserven goth (tot i que no recomanen el seu ús indiscriminat).

Alternativa

Les estructures de control "alternatives" us permeten especificar que s'hauria d'executar una instrucció o un bloc de sentències determinat "(només) si" es compleix una determinada condició. Per tant, també s’anomenen estructures condicionals .

Alternativa if-then i if-then-else

L'alternativa if-then (si-llavors) és la forma més simple d'alternativa. El seu significat es pot parafrasejar amb la frase "si es manté la condició C , executeu la instrucció (bloc) I ". La majoria dels llenguatges de programació també admeten (com a variant) la forma més articulada if-then-else (si-llavors-un altre tipus), que pot parafrasejar: "si la condició C es manté, executar la instrucció (bloc) I1, en cas contrari executar "instrucció (bloc) I2 ".

Les cases alternatives

L’ alternativa de casos es pot comparar amb una cadena if-then-else amb certes restriccions. En aquest cas, l'elecció d'una entre N instruccions o blocs alternatius es fa sobre la base del valor d'una variable o expressió determinada , generalment del tipus enter . Es pot parafrasejar de la següent manera: "avalueu el valor N ; si el seu valor és V1 , executeu I1 ; si és V2 , executeu I2 (etc.)". El següent fragment de codi pseudo-C il·lustra el concepte:

 cas d'elecció Menú de 
 1: openFile (); 
 2: closeFile (); 
 3: saveFile ();
 4: sortida ();
final;

El fet que el valor N hagi de ser (sovint) de tipus enter està relacionat amb consideracions d’eficiència en la implementació del mecanisme. De fet, el cas es presta a transformar-se, a nivell de llenguatge màquina , en un goto amb adreçament indirecte , que podria basar-se en una taula en memòria de la qual N selecciona una entrada concreta, en la qual l'adreça de les instruccions a s'especifica l'execució. per a aquest valor de N.

Iteració

Icona de la lupa mgx2.svg El mateix tema en detall: Iteració .

Les estructures de control "iteratives" permeten especificar que una determinada instrucció o bloc d'instruccions s'ha d'executar repetidament. També s’anomenen cicles . Cada estructura de control d’aquest tipus ha de permetre especificar en quines condicions ha d’acabar la iteració (repetició) d’aquestes instruccions, és a dir, la condició de terminació del bucle o, de manera equivalent, la condició de permanència al bucle . A continuació s’examinen les estructures de control més conegudes d’aquesta categoria.

Per a bucle

Icona de la lupa mgx2.svg El mateix tema en detall: per a bucle .

El bucle for s'utilitza quan la forma més natural d'expressar la condició de persistència en un bucle és especificar quantes vegades s'ha de repetir la sentència o el bloc controlat pel bucle. Les formes tradicionals dels bucles poden ser parafraseadas com "repetició (el codi controlada) per i anant d'un cert valor inicial per a un cert valor final, amb un cert pas". i és en general una variable de tipus enter , anomenada comptador . El següent fragment de codi BASIC il·lustra el concepte:

 PER I = 1 AL 9 PAS 2
 IMPRIMIR I
SEGÜENT I 

Aquest fragment repeteix la instrucció per imprimir a la pantalla de la variable de comptador I. Comença a partir del valor inicial 1 per arribar al valor final 10. La indicació del "pas" (STEP) especifica com el valor de I varia d'un iteració a la següent. A continuació, el fragment imprimirà la seqüència 1, 3, 5, 7, 9.

Mentre bucle

El bucle while ( mentre o sempre que ) s’indica quan la condició de persistència en un bucle és una condició booleana genèrica, independent del nombre d’iteracions realitzades. Les formes tradicionals de bucle mentre es poden parafrasejar com a "repetir (el codi controlat) sempre que la condició C sigui certa". Un exemple típic és la lectura de dades d’un fitxer la mida de la qual no es coneix a priori; pot adoptar la forma "llegir les dades següents fins al final del fitxer". El següent fragment de codi pseudo- C mostra un exemple d'un temps :

 contrasenya d’usuari = readPassword ();
while (contrasenya d'usuari <> contrasenya correcta) {
 reportErrorePassword ();
 contrasenya d’usuari = readPassword ();
}

Mentre C (i molts altres idiomes) es comprova la condició de permanència al bucle abans d'executar la primera iteració del bucle; si és fals immediatament, les instruccions del bucle no s'executen . A l'exemple anterior, si la contrasenya llegida és correcta, el bloc de codi que indica l'error d'entrada i que demana tornar a introduir la contrasenya (òbviament) no s'executa.

Bucle-fins a bucle

El bucle-fins ( repeteix fins ) difereix de la mentre que de dues maneres. En primer lloc, assegura que sempre es realitza almenys una iteració del bucle (la condició que controla el bucle es comprova després d’ acabar la primera iteració). En segon lloc, la condició de finalització del cicle s’expressa més que la de permanència en el cicle (aquesta última diferència, però, no té un impacte conceptual molt important, ja que les dues condicions es poden expressar simplement com a negació l’una de l’altra). El següent fragment pseudo- Pascal il·lustra el concepte:

 bucle
 contrasenya d'usuari: = readPassword ();
fins (userpassword = contrasenya correcta)

Variants de while i loop-until

Les dues diferències esmentades anteriorment entre while i loop-until són de fet independents entre si, de manera que es poden imaginar fàcilment dues combinacions més (encara que menys esteses per motius històrics): bucles que garanteixen una iteració però en què s’especifica la condició de permanència al bucle i bucles que admeten 0 iteracions però en què s’especifica la condició de terminació del bucle. Un exemple del primer cas és l'estructura do-while (sempre que ho faci) de C i les seves derivades , exemplificades en aquest fragment de pseudocodi:.

 fer
 contrasenya d’usuari = readPassword ();
while (contrasenya d'usuari <> contrasenya correcta);

Iteració basada en col·leccions

Alguns llenguatges (per exemple, Smalltalk , Perl , C # , Java ) proporcionen variants del bucle for en què el "comptador" és una variable genèrica (no necessàriament un enter) que pren una seqüència de valors del tipus corresponent , per exemple, tots els valors continguts en una matriu o col·lecció . El següent fragment de codi C # il·lustra el concepte:

 foreach (string s in aStringCollection) {print (s); }

Terminació anticipada de bucles i iteracions

Molts idiomes proporcionen una instrucció específica per finalitzar un bucle "prematurament", és a dir, fer que finalitzi d'una manera alternativa a la principal del bucle (per exemple, basada en el valor del comptador en el for o en el veritat / falsedat d’una condició en bucles while o repetir-fins ). El fragment següent il·lustra el concepte en un bucle Java:

 // cerqueu un valor N en una matriu
booleà trobat = fals;
per a (int i = 0; i <100; i ++)
 if (v [i] == N) {
  trobat = cert;
  trencar;
 }
}

En aquest fragment de Java, el programa ha de determinar si hi ha un número determinat N en una matriu . Tan aviat com es troba N, resulta inútil continuar recorrent la matriu mateixa: el salt finalitza el bucle for .

L'ús indiscriminat de mecanismes com el break (proporcionat per llenguatges com C , C ++ i Java ) sovint es critica i es desaconsella perquè es perd una propietat útil de llegibilitat dels bucles de programació estructurada: de fet, quan s'enfronta a un temps bucle amb una condició C , el lector tendeix a suposar que, al final del cicle, C és fals. L'ús de construccions break o similars, introduint "una altra" possible raó per acabar el bucle (a més, potencialment "amagat" dins del bloc controlat durant el temps ) fa que aquesta suposició no sigui del tot segura. Tanmateix, també hi ha casos en què l’estat del programa al final del cicle, amb o sense interrupció , és el mateix, de manera que no apareix el problema anterior. És el cas de l'exemple de Java anterior (el comptador i és local per a for i, per tant, es distribueix al final del bucle).

Un mecanisme similar (generalment considerat menys perillós) és el que permet finalitzar prematurament una determinada iteració d’un bucle, passant immediatament al següent. Consulteu el programa següent:

 per a (int i = 1; i <= 100; i ++)
 if (nombre (s)) {)
  impressió (s);
  continuar;
 }
 // calcular i imprimir els factors d’i
}

Aquest programa imprimeix els factors de tots els enters de l'1 al 100. Si i és un nombre primer, només heu d'imprimir el nombre en si; en cas contrari, es requereixen altres operacions per desglossar-lo. La instrucció continue indica que la iteració actual està acabada i fa que el bucle salti immediatament a la següent.

Nidificació

Totes les estructures de control es poden anidar juntes o inserir unes dins de les altres dins del codi del programa, respectant la sintaxi del llenguatge utilitzat.

Estructures de control no locals

En la majoria dels llenguatges de programació d'alt nivell , l'execució d'un programa evoluciona a través de diferents contextos , en cadascun dels quals són possibles algunes accions i no d'altres. Per exemple, l'execució d'una subrutina es produeix en un context que normalment es pot descriure en termes d' un registre d'activació , que inclou dades locals a les quals només pot accedir aquesta activació de subrutina. A més, s’estableixen regles molt precises que estableixen com i quan l’execució del programa transita d’un context a un altre (en el cas de les subrutines, aquestes regles són generalment consistents amb el model de la pila de registres d’activació . Per a estructures de control no locals s’entenen aquelles estructures de control que provoquen un salt de el flux de control, que és independent de (poden constitueixen una excepció a) aquestes regles. l'GOTO és el cas extrem, i de fet en gran mesura basat en Goto idiomes sense restricció (tal com llenguatges de màquina ) sovint es caracteritzen per nocions de context molt febles o completament absents.

En els llenguatges estructurats , de vegades hi ha estructures de control no locals que passen per alt les restriccions normals a l’evolució del context d’un programa en execució, però no són totalment incompatibles amb elles; es poden definir com a estructures de control no locals estructurades . Els exemples més coneguts d’estructures de control no locals (tant no estructurades com estructurades) es mostren a continuació i fan referència al problema general del tractament d’excepcions .

Condicions a PL / 1

El llenguatge PL / 1 té un mecanisme d’excepció bastant senzill. Hi ha diverses condicions (llegiu: excepcions, situacions anòmales; per exemple, intents de dividir un nombre per 0 o d'accedir a una matriu amb un valor d'índex il·legal) que automàticament "augmenten" (RAISE) pel llenguatge. El programador pot indicar què fer quan es planteja una condició mitjançant una clàusula de la forma "ON <condition> <action>". En la majoria dels casos, la <acció> que s'ha de dur a terme quan es produeix la <condició> s'especifica en forma de goto . El mecanisme PL / 1 es pot considerar com una versió primitiva (i poca o cap "estructurada" de la gestió d'excepcions en C ++ i en llenguatges derivats.

Excepcions en llenguatges C ++ i derivats

Icona de la lupa mgx2.svg El mateix tema en detall: Gestió d'excepcions .

C ++ , D , Java i C # gestionen excepcions amb una estructura de control no local especialment estructurada, normalment anomenada estructura try-catch , la sintaxi de la qual es mostra a continuació:

 provar {
 ...
 ... // codi que pot provocar excepcions de diversos tipus
 ...
}
catch (tipus d'excepció e) {
  ... // gestionar el problema
}
catch (UnAltroTipoDiExcezione e) {
  ... // gestionar el problema
}
finalment {
  ... // codi que cal executar de totes maneres
}

En aquest esquema, el bloc de codi controlat per try conté una o més sentències que poden provocar una excepció. Si això succeeix, el control salta del context de blocs associats amb try passant a un bloc controlat per una captura (com suggereix l'exemple, podeu tenir diverses captures associades a diferents tipus d'excepcions). El bloc de captures és el gestor de l' excepció , és a dir, conté aquelles operacions que constitueixen, en un sentit ampli, la "contramedida" prevista pel programador en cas que es produeixi una excepció particular. El bloc finalment controlat (que es troba a D , Java i C # ) conté sentències que s’han d’executar de totes maneres , tant si es produeix una excepció com si no (normalment s’alliberen operacions de recursos com tancar fitxers o connexions a la xarxa de blocs finalment controlats ) ; per a aquestes situacions, C # també té una altra construcció ad hoc , la clàusula using ).

Si es planteja una excepció en un bloc de prova per al qual no s'esperava cap captura (o si es produeix una excepció en algun lloc del codi que no s'ha comprovat amb un intent ), la subrutina o mètode actual finalitza i l'excepció es propaga a la subrutina o mètode de trucada , que la capturarà si la declaració de trucada de subrutina fallida s'inclou en un bloc try amb una captura associada adequada per a aquest tipus d'excepció; al contrari, el propi interlocutor finalitzarà i l'excepció es propagarà "cap amunt" (fins a la persona que truca). Es poden fer dues observacions sobre aquest model de gestió:

  • es pot definir com a estructurat en el sentit que, tot i saltar d’un context a un altre segons regles diferents de les que "normalment" regulen el canvi de context d'un programa estructurat, no infringeix els seus principis fonamentals: el control no pot passar a assenyaleu qualsevol programa (com passa a goto ), però respecta el model de la pila de registres d'activació (pas del context de la trucada al de la persona que truca);
  • es justifica pel fet que, en la pràctica de la programació, no totes les excepcions es poden gestionar efectivament "localment"; sovint, prendre contramesures per a un problema determinat requereix informació addicional que només està disponible en un context més ampli. Per exemple, si s'ha d'informar a l'usuari d'un error en obrir un fitxer amb un missatge en una finestra emergent , no és raonable esperar que ho faci una rutina genèrica d'accés a fitxers (el disseny del qual, per motius de reutilització , probablement no "assumeix" que l'aplicació actual té una GUI en lloc d'una interfície de text).

Un model similar al que s’acaba de descriure també es troba en els idiomes Python , Ruby , Objective C i altres.

Estructures de control simultànies

En el context de la programació paral·lela i simultània , s’han introduït estructures de control específiques que especifiquen o impliquen l’execució conceptualment simultània de determinats conjunts d’operacions o instruccions. El llenguatge més representatiu en aquest sentit és probablement el llenguatge de programació paral·lel Occam . Aquest llenguatge proporciona almenys dues estructures de control innovadores, respectivament per a l'execució en paral·lel d'instruccions i una forma especial d'alternativa que implica l'avaluació paral·lela de les condicions que la regeixen.

L’estructura PAR d’Occam

L’estructura de control PAR especifica que un determinat conjunt d’instruccions s’han d’executar en paral·lel. En la seva forma més senzilla, l’estructura PAR té la sintaxi següent:

 PAR
 x: = x + 1
 y: = y + 1

En aquest fragment de codi, l'increment de les dues variables es produeix simultàniament. PAR també admet una forma més complexa que presenta algunes similituds amb un bucle for , i es fa referència constantment amb les paraules clau PAR-FOR. El següent fragment de codi adquireix un enter donat de quatre canals paral·lels.

 PAR i = 0 PER 4
 INT n
 allà]? n [i]

L'analogia amb el bucle for consisteix a utilitzar el "comptador" i. Igual que un bucle tradicional per al bucle, el fragment de codi que es mostra fa cinc vegades l'anterior, "per a i que va de 0 a 4"; tanmateix, les cinc operacions d'entrada no es realitzen de manera seqüencial, sinó en paral·lel.

Estructura ALT d'Occam

La construcció ALT us permet definir un conjunt de "ordres guardades". Una ordre vigilada consisteix en una condició anomenada guardia i una declaració, amb alguna analogia amb una estructura if . No obstant això, el significat de l'ordre vigilat no és que la sentència s'executi si la condició és certa; més aviat, la sentència es pot executar quan la condició es compleixi. La construcció ALT agrupa una sèrie d'ordres vigilades; s'executa la primera ordre per a la qual es fa cert el guarda. Si hi ha diverses ordres la protecció és certa, una d'elles és seleccionada (arbitràriament) per la màquina virtual de llenguatge.

 ALT
 en una? v
  fora! v
 en B? v
  fora! v

La construcció ALT que es mostra aquí inclou dues ordres amb protecció. En aquest cas, les proteccions són instruccions ( suspensives ) que esperen a l’entrada un valor d’un dels dos canals ( in.a i in.b ). Tan bon punt les dades estiguin disponibles en qualsevol dels dos canals, s'adquiriran, es considerarà "veritable" la protecció corresponent i s'executarà la instrucció associada (de sortida), que finalitzarà l'execució del bloc ALT.

Bibliografia

Anar a
Estructures de control de programació estructurada

Articles relacionats