Cos'è ElectroYou | Login Iscriviti

ElectroYou - la comunità dei professionisti del mondo elettrico

Ricerca personalizzata

C: Come gestire una funzione che restituisce due valori?

Linguaggi e sistemi

Moderatore: Foto UtentePaolino

1
voti

[1] C: Come gestire una funzione che restituisce due valori?

Messaggioda Foto UtenteMax2433BO » 28 apr 2017, 15:24

Buon dì a tutti,

sto facendo un po' di malestri nel mentre che cerco di farmi entrare in testa la programmazione in C e mi è sorto questo problema.

Realizzando una funzione che mi permette di fare una divisione tra interi, che mi restituisca quoziente e resto, solo tramite le operazioni di sottrazione e somma, mi sono venuto a trovare che la stessa, a fine operazioni, mi dovrebbe restituire due valori, appunto quoziente e resto.

Ora, se ho ben capito, una funzione può restituire un unico valore (o nulla, come, ad esempio, una funzione di stampa), quindi a me sono venute in mente due sole possibilità, o usare variabili globali o usare variabili puntatore, come nei due seguenti esempi:

Variabili globali
Codice: Seleziona tutto
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/

/*
* File:   Prova_divisione_2.c
* Author: massimiliano
*
* Divisione con sotrazzioni successive
* con variabili globali
*
* Created on 28 aprile 2017, 14.32
*/

#include <stdio.h>
#include <stdlib.h>

/* Prototipo funzione*/
void divisione (int numeratore, int denominatore);

/*Dichiarazione ed inizializzazione variabili globali*/
int quoziente, resto;

quoziente = 0;
resto = 0;

/*
*
*/
int main(int argc, char** argv) {
   
    /*Dichiarazione ed inizzializzazione variabili*/
    int dividendo, divisore;
       
    dividendo = 16;
    divisore = 2;
       
    /*Chiamata funznione divisione*/
    divisione (dividendo, divisore);
   
    printf ("%d diviso %d = %d con resto %d  \n", dividendo, divisore, quoziente, resto);
   
    return (EXIT_SUCCESS);
}

/*Funzione per il calcolo del quoziente e del resto della divisione tra
* dividendo e divisore.
* Utilizza le variabili globali quoziente e resto
*/
void divisione (int numeratore, int denominatore) {
   
    resto = numeratore;
   
    /* Controllo se il dividendo è minore del divisore*/
    if (numeratore < denominatore) {
       
        return ;
       
    }
   
    do {
       
        resto = resto - denominatore;
        quoziente = ++quoziente;
               
    }
   
    while ( resto >= denominatore);
   
    return;
}


Variabili puntatore
Codice: Seleziona tutto
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/

/*
* File:   Funzione_divisione.c
* Author: massimiliano
*
* Divisione tramite sottrazioni successive
* con variabili puntatore (chiamata funzione per riferimento)
*
* Created on 28 aprile 2017, 13.20
*/

#include <stdio.h>
#include <stdlib.h>

/* Prototipo funzione*/
void divisione (int numeratore, int denominatore, int *quozintePtr, int *restoPtr);

/*
*
*/
int main(int argc, char** argv) {
   
    /*Dichiarazione ed inizzializzazione variabili*/
    int dividendo, divisore, quoziente, resto;
       
    dividendo = 15;
    divisore = 2;
    quoziente = 0;
    resto = 0;
   
    /*Chiamata funznione divisione*/
    divisione (dividendo, divisore, &quoziente, &resto);
   
    printf ("%d diviso %d = %d con resto %d  \n", dividendo, divisore, quoziente, resto);
   
    return (EXIT_SUCCESS);
}

/*Funzione per il calcolo del quoziente e del resto della divisione tra
* dividendo e divisore.
* Modifica le variabili quoziente e divisore nel main
*/
void divisione (int numeratore, int denominatore, int *quozientePtr, int *restoPtr) {
   
    *restoPtr = numeratore;
   
    /* Controllo se il dividendo è minore del divisore*/
    if (numeratore < denominatore) {
       
        return ;
       
    }
   
    do {
       
        *restoPtr = *restoPtr - denominatore;
        *quozientePtr = ++*quozientePtr;
               
    }
   
    while ( *restoPtr >= denominatore);
   
    return;
}


Entrambi i sistemi, però, vanno contro il "principio del minimo privilegio" nell'utilizzo delle variabili e quindi meno sicuri dell'utilizzo di sole variabili locali.

Avevo pensato di utilizzare delle variabili vettore ma, da dove sono arrivato a studiare, non mi sembra sia possibile avere una funzione che restituisca una vettore, lo può modificare, ma allora si ricade nel caso delle variabili puntatore (Vi prego di correggermi se sbaglio...).

Ci sono valide soluzioni alternative all'utilizzo di due variabili in questo caso?

O_/ Max

Nota 1: Lo so che esistono già funzioni, in C, che permettono di fare la divisione tra interi ricavando il resto, ma volete togliermi il divertimento di farlo solo con somme e sottrazioni...

Nota 2: Questo è solo un prototipo valido per numeri positivi...

Nota 3: Peccato che Foto UtenteTardoFreak non abbia più continuato il suo corso di programmazione, anche se era orientato verso Java, era una fonte di buoni spunti...
Disapprovo quello che dite, ma difenderò fino alla morte il vostro diritto di dirlo [attribuita a Voltaire]

Sapere sia di sapere una cosa, sia di non saperla: questa è conoscenza. [Confucio, "I colloqui"]
Avatar utente
Foto UtenteMax2433BO
4.550 2 5 9
Master
Master
 
Messaggi: 1329
Iscritto il: 25 set 2013, 15:29
Località: Un puntino insignificante nell'universo!!

1
voti

[2] Re: C: Come gestire una funznione che restituisce due valori

Messaggioda Foto Utentesimo85 » 28 apr 2017, 15:28

Non capisco il problema di modificare i valori per riferimento.
Avatar utente
Foto Utentesimo85
30,8k 6 12 13
Disattivato su sua richiesta
 
Messaggi: 10004
Iscritto il: 30 ago 2010, 3:59

0
voti

[3] Re: C: Come gestire una funznione che restituisce due valori

Messaggioda Foto UtenteMax2433BO » 28 apr 2017, 15:34

Non c'è alcun problema specifico Foto Utentesimo85, è solo una questione di sicurezza, in qunato sul testo che sto usando viene indicato che è sempre meglio (quando è possibile) fare una chiamata per valore che per riferimento in quanto così si impedisce la modifica accidentale degli argomenti del chiamante...

... per questo chiedevo se, in questo frangente, esiste un modo per evitare la chimata per riferimento.

O_/ Max
Disapprovo quello che dite, ma difenderò fino alla morte il vostro diritto di dirlo [attribuita a Voltaire]

Sapere sia di sapere una cosa, sia di non saperla: questa è conoscenza. [Confucio, "I colloqui"]
Avatar utente
Foto UtenteMax2433BO
4.550 2 5 9
Master
Master
 
Messaggi: 1329
Iscritto il: 25 set 2013, 15:29
Località: Un puntino insignificante nell'universo!!

3
voti

[4] Re: C: Come gestire una funznione che restituisce due valori

Messaggioda Foto Utentesimo85 » 28 apr 2017, 15:39

Usa una struttura:

Codice: Seleziona tutto
#include <stdio.h>

typedef struct
{
   double a;
   double b;
} info;

info foo (double a, double b)
{
   info aa;
   aa.a = a;
   aa.b = b;

   aa.a *= 2;
   aa.b *= 3;

   return aa;
}

int main(void)
{
   info blabla;
   blabla = foo(3, 4);
   printf("%f - %f\n", blabla.a, blabla.b);
}


è la prima soluzione che mi è venuta in mente.

O_/
Avatar utente
Foto Utentesimo85
30,8k 6 12 13
Disattivato su sua richiesta
 
Messaggi: 10004
Iscritto il: 30 ago 2010, 3:59

1
voti

[5] Re: C: Come gestire una funznione che restituisce due valori

Messaggioda Foto UtenteTardoFreak » 28 apr 2017, 15:45

Si, un modo c'è: dichiarare una struct ed usarla come valore di ritorno
Codice: Seleziona tutto
typedef struct doppioInt_t
{
  int a;
  int b;
};

doppioInt_t dividi(int dividendo, int divisore)
{
  doppioInt_t r;
  r.a = dividendo / divisore;
  t.b = dividendo % divisore;
  return r;
}

void main(void)
{
  doppiInt_t ris = dividi(11, 4);
  printf("valore: %d, resto: %d\n", ris.a, ris.b);
}


Codice buttato giù al volo e non testato.
Nel data sheet si trova tutto. Anche gli errori.
"La follia sta nel fare sempre la stessa cosa aspettandosi risultati diversi".
"Parla soltanto quando sei sicuro che quello che dirai è più bello del silenzio".
PIERIN-PIC18
Avatar utente
Foto UtenteTardoFreak
70,8k 8 12 13
Disattivato su sua richiesta
 
Messaggi: 15449
Iscritto il: 16 dic 2009, 10:10
Località: Torino - 3° pianeta del Sistema Solare

0
voti

[6] Re: C: Come gestire una funznione che restituisce due valori

Messaggioda Foto UtenteMax2433BO » 28 apr 2017, 15:46

... struttura... mmhhh... :-M

Mi sa che mi tocca saltare un po' avanti nel libro, comunque grazie Foto Utentesimo85, andrò a vedere se ci capisco qualcosa, perché scritto così mi è un po' fumoso... :mrgreen:

O_/ Max

... vedo che anche Foto UtenteTardoFreak è per la stessa soluzione...

... dovrò proprio saltare un po' avanti nel libro... :mrgreen:
Disapprovo quello che dite, ma difenderò fino alla morte il vostro diritto di dirlo [attribuita a Voltaire]

Sapere sia di sapere una cosa, sia di non saperla: questa è conoscenza. [Confucio, "I colloqui"]
Avatar utente
Foto UtenteMax2433BO
4.550 2 5 9
Master
Master
 
Messaggi: 1329
Iscritto il: 25 set 2013, 15:29
Località: Un puntino insignificante nell'universo!!

3
voti

[7] Re: C: Come gestire una funznione che restituisce due valori

Messaggioda Foto Utentexyz » 28 apr 2017, 16:00

La copia della struttura come parametro di ritorno viene chiamata in inglese "shallow copy". Il compilatore C in molti casi, se la struttura è piccola, esegue questa copia direttamente tra i registri.
Avatar utente
Foto Utentexyz
3.625 2 4 5
Master EY
Master EY
 
Messaggi: 1023
Iscritto il: 5 dic 2009, 17:37
Località: Italy Turin

0
voti

[8] Re: C: Come gestire una funznione che restituisce due valori

Messaggioda Foto UtenteMax2433BO » 28 apr 2017, 16:05

... Ok, vado studio e ritento...

O_/ Max
Disapprovo quello che dite, ma difenderò fino alla morte il vostro diritto di dirlo [attribuita a Voltaire]

Sapere sia di sapere una cosa, sia di non saperla: questa è conoscenza. [Confucio, "I colloqui"]
Avatar utente
Foto UtenteMax2433BO
4.550 2 5 9
Master
Master
 
Messaggi: 1329
Iscritto il: 25 set 2013, 15:29
Località: Un puntino insignificante nell'universo!!

5
voti

[9] Re: C: Come gestire una funznione che restituisce due valori

Messaggioda Foto UtenteDirtyDeeds » 28 apr 2017, 20:09

Nota che in C esiste già una struttura definita nella libreria standard stdlib.h e adatta allo scopo. Si tratta della struttura div_t, definita come

Codice: Seleziona tutto
struct div_t { int quot; int rem; };


e le corrispondenti per long e long long:

Codice: Seleziona tutto
struct ldiv_t { long quot; long rem; };
struct lldiv_t { long long rem; long long quot; };


Queste strutture vengono proprio usate per i valori di ritorno di funzioni che fanno la divisione tra interi:

Codice: Seleziona tutto
div_t     div( int x, int y );   
ldiv_t    ldiv( long x, long y );   
lldiv_t   lldiv( long long x, long long y );


Le funzioni sopra sono definite in stdlib.h. Altri dettagli li trovi qui.
It's a sin to write sin instead of \sin (Anonimo).
...'cos you know that cos ain't \cos, right?
You won't get a sexy tan if you write tan in lieu of \tan.
Take a log for a fireplace, but don't take log for \logarithm.
Avatar utente
Foto UtenteDirtyDeeds
54,8k 7 11 13
G.Master EY
G.Master EY
 
Messaggi: 7006
Iscritto il: 13 apr 2010, 15:13
Località: Somewhere in nowhere

1
voti

[10] Re: C: Come gestire una funznione che restituisce due valori

Messaggioda Foto UtenteTardoFreak » 28 apr 2017, 21:28

Grande Max! iOi iOi iOi
Nel data sheet si trova tutto. Anche gli errori.
"La follia sta nel fare sempre la stessa cosa aspettandosi risultati diversi".
"Parla soltanto quando sei sicuro che quello che dirai è più bello del silenzio".
PIERIN-PIC18
Avatar utente
Foto UtenteTardoFreak
70,8k 8 12 13
Disattivato su sua richiesta
 
Messaggi: 15449
Iscritto il: 16 dic 2009, 10:10
Località: Torino - 3° pianeta del Sistema Solare

Prossimo

Torna a PC e informatica

Chi c’è in linea

Visitano il forum: Nessuno e 2 ospiti