C/Funcións: Diferenzas entre revisións

Contido eliminado Contido engadido
Gallaecio (conversa | contribucións)
Revisado e completado coa información de «Función principal».
Gallaecio (conversa | contribucións)
Completado (bastante).
Liña 1:
{{Navegador|Instrucións de control|Directrices para o preprocesador}}
 
Un programa en C está formado pola [[{{PAGENAME}}#A función principal|función principal]] (o código que se executa ao chamar ao programa) e, xeralmente, outras funcións, xa formen parte da [[{{BASEPAGENAME}}#/Biblioteca estándar|biblioteca estándar de funcións de C]] ou sexan funcións escritas polo propio usuario. Toda instrución atópase por tanto dentro dunha función.
 
As funcións son fragmentosbloques de códigoinstrucións que poden chamarse en calquera parte do código da función principal ou doutra función. As funcións realizan unha serie de tarefas a partir dun ou varios datos que reciben como argumentos, e como resultado desas tarefas as funcións devolven un valor (opcionalmente) na función dende a que foron chamadas.
 
Dado que unha mesma función pode chamarse varias veces para traballar con distintos valores, as funcións son unha ferramenta moi potente á hora de programar. Entre os beneficios que achega o uso de funcións están os seguintes:
*'''Claridade no código'''. Ao reducir fragmentos de código a funcións, a estrutura do código queda moito máis clara, o que facilita non só a comprensión do código, senón a busca e solución de erros.
*'''Evitar repeticións innecesarias de código'''. En moitas ocasións, ao longo dun programa existen certos grupos de instrucións que conforman unha operación que nos gustaría repetir máis dunha vez no programa. Repetir as instrucións cada vez que sexan necesarias pode resultar traballoso, e dificulta o mantemento do código: se aparece un erro nesa operación, haberá que corrixilo en todas as súas repeticións. Estes problemas soluciónanse mediante o uso de funcións que conteñan a operación.
*'''Independencia'''. As funcións son relativamente independentes do reto do código (das funcións que a chaman). As funcións poden modificar variables globais ou punteiros, pero limitándose a aqueles que se lle fornezan na chamada á función.
 
Antes de analizar os compoñentes das funcións cómpre ter en conta algunhas cousas relativas ao vocabulario usado ao tratar con funcións:
*Cando falamos de que unha función utiliza outra función, dicimos que a primeira “chama” á segunda.
*Os datos que se lle envían a unha función para que traballe con eles son os “argumentos”. Estes, vistos dende o punto de vista da función chamada, adóitanse denominar “parámetros”.
*Cando unha función responde á que a chamou con algún dato, a función “devolve” ese dato.
 
==Compoñentes das funcións==
Liña 11 ⟶ 21:
 
===Definición dunha función===
A definición de unha función é a función en si mesma. É un algoritmo que pode recibir ningún, un valor,ou varios valores ou mesmo─chamados ningún valor“parámetros”─, e que pode devolver ningún ou un valor ou─chamado ningún“valor de saída”─. Consta dunha serie de instrucións que rematan coa saída da función ([[{{BASEPAGENAME}}/Instrucións de control#return|<source lang=c enclose=none>return</source>]]).
 
A definición dunha función consta de dúas partes ben diferenciadas: a cabeceira e o corpo.
Liña 19 ⟶ 29:
As variables estre parénteses son variables locais da función. Defínense durante a execución da función ─tras ser esta chamada por outra función─, ''inicializadas'' cos valores da chamada, e non as pode usar outra función. É dicir, as variables cos datos de entrada só teñen “xurisdición” dentro da función para a que se definen. É coma unha declaración de variables corrente, sendo a única diferencia respecto ás outras declaracións de variables que a variable se ''inicializa'' cun valor que se lle fornece na [[{{PAGENAME}}#Chamada a unha función|chamada á función]], que se realiza dende outra función.
 
O '''corpo''' da función confórmao o bloque de instrucións que segue á cabeceira. Cómpre ter en conta que para definir a saída da función (devolvendo ou non un valor) no corpo utilízase a [[{{BASEPAGENAME}}/Instrucións de control#return|instrución de control <source lang=c enclose=none>return</source>]]. Non fai falla utilizala para aqueles casos en que a función non devolve ningún valor, nos cales a función rematará en canto a execución chegue ao final de bloque, pero utilizar a instrución de control para especificar a saída da función nunca está de máis. Nótese que ademais o <source lang=c enclose=none>return</source> permite saír da función ''antes'' de chegar ao final do bloque.
O '''corpo''' da función confórmao o bloque de instrucións que segue á cabeceira.
 
A sintaxe fundamental da definición dunha función sería a seguinte:
Liña 32 ⟶ 42:
Un exemplo de definición dunha función podería ser o seguinte:
<source lang=c>
signed int Produto(signed int operando1, signed int operando2){
signed int resultado;
resultado = operando1 * operando2;
return resultado; // O seu tipo debería coincidir co tipo de
// saída definido na cabeceira.
}
</source>
 
Por suposto, o código anterior podería resumirse no seguinte:
<source lang=c>
int Produto(int operando1, int operando2){
return operando1 * operando2;
}
</source>
Liña 51 ⟶ 68:
<source lang=c>
resultadode3por5 = Produto(3, 5);
</source>
 
E outro exemplo, desta vez sen que a función devolva nada, podería ser o seguinte:
<source lang=c>
Saudar("Carlos"); // Imaxínese que logo imprime en pantalla: «Ola, Carlos!».
</source>
 
Liña 58 ⟶ 80:
O caso máis común é o paso por valor. Neste caso, o que se lle pasa á función é o valor que contén a variable. Para pasarlle unha variable a unha función por valor, abonda con escribir o identificador da función. Ao executarse a función, esta crea unha nova variable cuxo identificador queda definido na [[{{PAGENAME}}#Definición dunha función|definición da función]], e ''inicialízaa'' co valor da variable que se lle pasa.
 
Porén, tamén é posible pasarlle a unha función, en vez do valor da variable, o seu enderezo na memoria. Neste caso, a función non recibe o valor que contén a variable, senón o enderezo na memoria. Dese modo, a función non traballará co valor, senón coacun [[{{BASEPAGENAME}}/Punteiros|punteiro]] á variable en si mesma, de xeito que poderá modificar a variable durante a execución da función. Isto é o que se coñece coma “paso por referencia”. Para facelo, é necesario preceder o identificador da función do carácter <code>&amp;</code>.
<source lang=c>
funcion1(variable); // Aquí prodúcese un paso por valor.
Liña 89 ⟶ 111:
}
</source>
 
O seu tipo de saída sempre é <source lang=c enclose=none>signed int</source>, o seu identificador sempre é <source lang=c enclose=none>main</source> e, se non recibe argumentos, indícase mediante a palabra clave <source lang=c enclose=none>void</source> ou deixando baleiro o contido dos parénteses.
 
É unha boa práctica subdividir a función principal noutras funcións, de xeito que esta quede case como un guión do que fai o programa, permitindo así unha lectura rápida e comprensión do mesmo.
 
===Argumentos da función principal===
Liña 100 ⟶ 126:
<source lang=c>
int main(int argc, char * argv[]){
// Instrucións que conforman oa programafunción principal.
}
</source>
 
Por convención, <code>argv[0]</code> conterá o nome co que se chamou ao executable (xeralmente será a ruta completa do ficheiro executable). Este valor fornéceo automaticamente o sistema operativo, polo que o valor mínimo de <code>argc</code> será un. O resto de celas da matriz conterán os argumentos cos que se chamou ao programa, en forma de [[{{BASEPAGENAME}}/Cadeas de caracteres|cadeas de caracteres]]. Se se quere traballar cun argumento coma se se tratase doutro tipo de dato, será necesario realizar un proceso de conversión.
 
Xeralmente <code>argc</code> utilízase para controlar os argumentos fornecidos polo usuario ao chamar ao programa, xeralmente rematando a súa execución, non sen antes indicarlle ao usuario a forma correcta de chamar á función.
 
==Funcións recursivas==
Denomínase recursividade ao feito de que unha función se chama a si mesma, xa sexa directa ou indirectamente ─con outras funcións de por medio─. A súa sintaxe fundamental sería a seguinte:
<source lang=c>
función(parámetros){
// [...]
función();
// [...]
}
</source>
 
Se se utiliza sen realizar cambios sobre os argumentos fornecidos, a función entraría nun ciclo sen fin. En cambio, ben usada a recursividade permite realizar en poucas liñas de código tarefas que resultarían sumamente longas ou complicadas de realizarse sen aproveitarse da recursividade.
 
Toda función recursiva necesita contemplar un “caso base”, que consiste ha condición de saída, para evitar entrar nun ciclo sen fin. Cando se recoñece un caso base, remata a recursividade.
 
Esta técnica úsase en tarefas tales como percorrer árbores de directorios, buscar o fin dunha lista encadeada, analizar unha estrutura de árbore nunha base de datos, buscar os factores primos de números, calcular o factorial dun número, etc.
 
O seguinte exemplo é dunha función recursiva que calcula o {{W|factorial}} dun número:
<source lang=c>
unsigned long factorial(unsigned int numero){
if(!n)
return 1; // 0! = 1 ← Caso base.
else
return n * factorial(--n); // Chamada á mesma función.
}
</source>
 
E o seguinte é un exemplo de recursividade indirecta, en que chamando á primeira función co argumento «z» conséguese o alfabeto ASCII en minúsculas ata o «z»:
<source lang=c>
void funcion1(unsigned char letra){
if(letra > 'a') // Se a letra vai despois do «a» (valor ASCII maior) ← Caso base.
funcion1(letra);
printf("%uc ", letra); // Imprímese a letra.
}
 
void funcion2(unsigned char letra){
funcion1(--letra); // Chamada á primeira función diminuíndo o valor da letra.
}
</source>
 
==Funcións estáticas==
Unha función considérase estática cando só vai ser chamada dende as funcións que se atopan no mesmo ficheiro no que está [[{{BASEPAGENAME}}/Definición dunha función|definida]]. Sabendo isto, o compilador pode compilala de xeito que se impida a súa chamada dende outros ficheiros.
 
Para declarar unha función como estática, abonda con engadirlle o modificador <source lang=c enclose=none>static</source>, como se pode observar no seguinte exemplo:
<source lang=c>
static int Produto(int operando1, int operando2){
return operando1 * operando2;
}
</source>
 
==Bibliotecas de funcións==
As '''bibliotecas de funcións''' son conxuntos de funcións feitas previamente que se poden aproveitar, evitando a necesidade de volver codificalas para cada un dos distintos programas que se realicen. Abonda con indicarlle ao compilador que se quere engadir a biblioteca ao executable.
 
Unha biblioteca de funcións non é máis que un ficheiro que contén as [[{{PAGENAME}}#Definición dunha función|definicións]] dunha serie de funcións, así como definicións de estruturas de datos, unións, etc. Unha biblioteca pode mesmo utilizar as funcións doutra biblioteca de funcións.
 
Pero á hora de traballar de verdade coas funcións da biblioteca e utilizalas en programas, necesítanse dous ficheiros distintos: o [[{{PAGENAME}}#Ficheiro de cabeceira|ficheiro de cabeceira]] e a propia biblioteca [[{{PAGENAME}}#Biblioteca compilada|compilada]].
 
===Ficheiro de cabeceira===
O ficheiro de cabeceira será un ficheiro de texto, xeralmente coa extensión <code>.h</code>, que conterá os [[{{PAGENAME}}#Declaración dunha función|prototipos]] das funcións da biblioteca, así como os tipos de [[{{BASEPAGENAME}}/Estruturas|estruturas]], [[{{BASEPAGENAME}}/Unións|unións]] ou [[{{BASEPAGENAME}}/Enumeracións|enumeracións]] usadas se procede. Cando as bibliotecas son moi complexas, utilízanse xeralmente varios ficheiros distintos.
 
Unha vez creado o ficheiro, nos códigos nos que se utilicen as funcións da biblioteca haberá que incluír o ficheiro de cabeceira ─de xeito similar a como se fai para a biblioteca estándar de C─ mediante a [[{{BASEPAGENAME}}/Directrices para o preprocesador|directriz para o preprocesador]] <source lang=c enclose=none>#include "FICHEIRO"</source>, onde <code>FICHEIRO</code> será o ficheiro de cabeceira en cuestión.
 
:''Para máis informacións sobre a inclusión de ficheiros de cabeceira en códigos, vaiase ao capítulo sobre as [[{{BASEPAGENAME}}/Directrices para o preprocesador|directrices para o preprocesador]].''
 
===Biblioteca compilada===
O proceso necesario para compilar unha biblioteca de funcións ou para ligala a un programa durante o proceso de compilación escapa aos obxectivos deste libro. Para máis información léase, por exemplo, o libro sobre a '''[[GNU Compiler Collection]]'''.
 
==Véxase tamén==
*[[{{BASEPAGENAME}}/Biblioteca estándar|Biblioteca estándar de funcións]]