View Full Version : [C] Media numeri dinamica
Sto facendo qualche semplice esercizio sull'allocazione dinamica della memoria, per capire bene come funziona.
Ho già dei problemi a fare l'esercizio proposto: inseriti quanti voti si vogliono inserire, allocare memoria sufficiente per contenerli tutti e calcolarne la media.
Ho scritto questo:
#include <stdio.h>
#include <stdlib.h>
void get_numbers (float array[], int num);
float sum ( float array[], int num);
float average ( float sum, int num);
void print_values ( float array[], float sum, int num, float avg);
int main ()
{
int num=0;
float *array, sumvalue, avg;
printf("Quanti numeri vuoi inserire?\n");
scanf("%d", &num);
if( (array= (float *)calloc(num, sizeof(float)))== NULL)
{
printf("Allocation error\n");
return -1;
}
else {
get_numbers( array, num);
sumvalue = sum ( array, num);
avg = average ( sumvalue, num);
print_values(array, sumvalue, num, avg);
return 0;
}
}
void get_numbers ( float array[], int num)
{
int i;
for ( i=0; i < num; i++)
{
scanf("%f", &array[i]);
}
}
float sum ( float array[], int num)
{
int i;
float sum;
for (i=0; i < num; i++)
sum += array[i];
return sum;
}
float average ( float sum, int num)
{
float average;
average= sum/num;
return average;
}
void print_values ( float array[], float sum, int num, float avg)
{
int i;
printf("You've enter %d numbers\n", num);
printf("These are: ");
for ( i=0; i < num; i++)
printf("%f ", array[i]);
printf("\nThe sum is: %f\n", sum);
printf("The average is: %f\n", avg);
}
Ma sembra ci sia qualche problema nell'allocazione della memoria perchè dal debug vedo che quello che creo non prende la forma di un vettore quando vado ad allocargli la memoria ( si dovrebbe vedere il nome dell'array con x indici in base al numero di elementi da inserire... ).
Che sto sbagliando?
Inoltre, nel programma d'esempio viene usata questa dicitura:
v= (float *)calloc(num, sizeof( float ));
È indispensabile (float * ) prima di calloc? Perchè?
Nei prototipi ho provato a sostituire *array con array[] ma la sostanza non cambia...
Grazie,
Kwb
A me così ad occhio sembra corretta l'allocazione della memoria. Non capisco quale sia il problema...
Quel (*float) è un casting esplicito del valore restituito dalla funzione calloc, ossia un puntatore di tipo void. Ti avverto però che potresti anche trovare codici dove invece il casting è implicito e quindi senza (*float).
PS: perchè la funzione sum la chiami nel main, non sarebbe logicamente più corretto chiamarla in average? Poi a funzionare funziona comunque....
A me così ad occhio sembra corretta l'allocazione della memoria. Non capisco quale sia il problema...
Quel (*float) è un casting esplicito del valore restituito dalla funzione calloc, ossia un puntatore di tipo void. Ti avverto però che potresti anche trovare codici dove invece il casting è implicito e quindi senza (*float).
PS: perchè la funzione sum la chiami nel main, non sarebbe logicamente più corretto chiamarla in average? Poi a funzionare funziona comunque....
Il fatto è che se fai girare il programma, i numeri inseriti vengono stampati correttamente, mentre media e somma sono errati ( prova con più di due numeri, finchè ne usi due funziona ) e non ne riesco a venire a capo...
Col debugger si vede che terminato il primo ciclo for ( stiamo parlando della funzione per acquisire in numeri ) e immagazzinato nel vettore il primo valore inserito, dal secondo in poi gli altri valori non vengono salvati all'interno del vettore ( o almeno il debugger non li fa vedere... ).
Per la funzione sum: si hai ragione, ma è un programma che ho fatto alla svelta...
EDIT: Ma era impazzito XCode... Ora funziona... Va a sapere...
Per quanto riguarda (float *): ho provato a toglierlo e a metterlo e non cambia assolutamente nulla. Se ho ben capito, da quello che hai detto, serve a convertire il risultato della funzione calloc ( che è generalmente void ) in un float, corretto?
float sum;
for (i=0; i < num; i++)
sum += array[i];
le variabili in C vanno sempre inizializzate, se vuoi che sum parta da 0 devi scriverlo esplicitamente, l'errore che riportavi probabilmente dipende da questo
Teo@Unix
13-08-2010, 16:22
A me il programma funziona bene. Nessun errore anche con più numeri.
matteo@Moon:~$ ./a.out
Quanti numeri vuoi inserire?
10
1
2
3
4
5
6
7
8
9
10
You've enter 10 numbers
These are: 1.000000 2.000000 3.000000 4.000000 5.000000 6.000000 7.000000 8.000000 9.000000 10.000000
The sum is: 55.000000
The average is: 5.500000
se non mi ricordo male,
sul fatto che con il debugger non ti ritrovi i numeri nell'array come vorresti è probabilmente, perchè stiamo lavorando con il tipo float (http://en.wikipedia.org/wiki/Floating_point#IEEE_754:_floating_point_in_modern_computers)
infatti se guardo la memoria all'altezza di dove l'array è allocato non mi trovo i numeri espressi in integer, anzi non si capisce proprio niente....
...
Breakpoint 1, get_numbers (array=0x804b008, num=5) at test.c:39
39 }
(gdb) print array
$1 = (float *) 0x804b008
(gdb) x/10x array
0x804b008: 0x3f800000 0x40000000 0x40400000 0x40800000
0x804b018: 0x40a00000 0x00020fe9 0x00000000 0x00000000
0x804b028: 0x00000000 0x00000000
...
EDIT:
mi pare che usi la mantissa il calcolatore.
ma può anche essere che mi sia fumato il cervello e non sia così, mi pare...
float sum;
for (i=0; i < num; i++)
sum += array[i];
le variabili in C vanno sempre inizializzate, se vuoi che sum parta da 0 devi scriverlo esplicitamente, l'errore che riportavi probabilmente dipende da questo
Si a volte il problema è per quello... L'ho imparato a mie spese...
Fatto sta che non si sa perchè XCode era impazzito e c'era qualcosa hc enon andava... Ora funziona perfettamente il probramma, sia con interi che con numeri con la virgola.
Per la visualizzazione nel debugger: Non mi cruccio più di tanto, mi basta che il programma funzioni... Alla fine non poteva essere un problema di caricamento nel vettore perchè tutti i valori venivano caricati correttamente ( infatti venivano stampati giusti ).
Domanda, faccio un programma allocando la memoria come questo, quindi:
float *v;
v= calloc(qta_elementi, grandezza)
Poi quando lo devo utilizzare in una funzione secondaria, è indifferente chiamarlo così:
void funzione ( float *v )
O così:
void funzione ( float v[] )
?
Grazie
Kwb
Teo@Unix
14-08-2010, 09:35
Poi quando lo devo utilizzare in una funzione secondaria, è indifferente chiamarlo così:
void funzione ( float *v )
O così:
void funzione ( float v[] )
?
Grazie
Kwb
direi di si.
Per quanto riguarda (float *): ho provato a toglierlo e a metterlo e non cambia assolutamente nulla. Se ho ben capito, da quello che hai detto, serve a convertire il risultato della funzione calloc ( che è generalmente void ) in un float, corretto?
Esatto, si tratta di una conversione, generalmente detta casting, ma nel tuo caso se si vuol essere più precisi si parla di coercizione, perchè sei stato tu programmatore ad esplicitare questa conversione, mentre se è il compilatore ad applicarla automaticamente allora si parla di casting, ed è il caso che ti dicevo prima di codici dove quel (float*) viene omesso.
Poi quando lo devo utilizzare in una funzione secondaria, è indifferente chiamarlo così:
void funzione ( float *v )
O così:
void funzione ( float v[] )
E' indifferente perchè la notazione v sarebbe l'equivalente più elegante di scrivere v+i ([I]aritmetica dei puntatori).
Un'ultima domanda: quale è l'utilità di convertire un risultato di una funzione void in qualcos'altro?
Nel caso specifico, qual è l'utilità di convertire il void del calloc in float?
Più che un utilità la conversione è una necessità che si ha quando il tipo dell'espressione richiesta non è lo stesso tipo dell'espressione passata. Ma non sempre è possibile il casting, infatti i tipi devono essere tra loro compatibili.
Nel tuo caso hai avuto la necessità di fare un casting perchè la calloc ti restituiva un void* ma a te serviva un float* da mettere dentro array.
Più che un utilità la conversione è una necessità che si ha quando il tipo dell'espressione richiesta non è lo stesso tipo dell'espressione passata. Ma non sempre è possibile il casting, infatti i tipi devono essere tra loro compatibili.
Nel tuo caso hai avuto la necessità di fare un casting perchè la calloc ti restituiva un void* ma a te serviva un float* da mettere dentro array.
Ma in realtà io il ( float * ) davanti a calloc non c'è l'ho messo e funziona uguale :confused: :confused: :confused:
E poi scusa, che utilità ha dichiarare una variabile di tipo nulla ( a patto che si possa )?
il tipo void* viene usato per avere una specie di genericità, infatti vedrai che non è possibile dereferenziare un void*, quindi è necessario un cast
se il tuo compilatore non è del paleolitico il cast da void* a float* lo fa implicitamente se scrivi
float *f = malloc(sizeof(float));
quindi non serve esplicitarlo
Ma in realtà io il ( float * ) davanti a calloc non c'è l'ho messo e funziona uguale :confused: :confused: :confused:
In un precedente post avevo scritto
Ti avverto però che potresti anche trovare codici dove invece il casting è implicito e quindi senza (*float).
Se tu non espliciti il cast in quel caso lo fa il compilatore per te durante la compilazione. Questo però non avviene sempre, quindi è buona abitudine esplicitarlo, così si rende anche il codice più leggibile.
E poi scusa, che utilità ha dichiarare una variabile di tipo nulla ( a patto che si possa )?
Come ti ha detto tuccio restituire un void ti permette di usare la medesima funzione nei più svariati contesti senza dover tener conto del tipo di puntatore che si sta utilizzando, altrimenti sarebbe stato necessario scrivere una calloc per ogni tipo di puntatore.
il tipo void* viene usato per avere una specie di genericità, infatti vedrai che non è possibile dereferenziare un void*, quindi è necessario un cast
se il tuo compilatore non è del paleolitico il cast da void* a float* lo fa implicitamente se scrivi
float *f = malloc(sizeof(float));
quindi non serve esplicitarlo
In un precedente post avevo scritto
Se tu non espliciti il cast in quel caso lo fa il compilatore per te durante la compilazione. Questo però non avviene sempre, quindi è buona abitudine esplicitarlo, così si rende anche il codice più leggibile.
Ah si, ecco mi era sfuggito, non avevo colto il senso dell'implicito :D
Come ti ha detto tuccio restituire un void ti permette di usare la medesima funzione nei più svariati contesti senza dover tener conto del tipo di puntatore che si sta utilizzando, altrimenti sarebbe stato necessario scrivere una calloc per ogni tipo di puntatore.
Si è vero, ci ho pensato ora, grazie di queste delucidazioni che non vengono mai dette dai professori :muro:
( Tanto per dirne una, i miei due professori di programmazione non hanno mai usato il casting sui calloc/malloc ... )
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.