Newsgroup: it.comp.lang.c
Titolo: puntatori ad array-- dubbi amletici

Salve a tutti, avrei delle domande cervellotiche da porre ad un vero 
espertone...
Consideriamo il seguente frammento:
int	topo[10];
..
..
printf("\ntopo <%d>  &topo <%d>  sizeof(topo) <%d>  sizeof(&topo) <%
d> ", topo, &topo, sizeof(topo), sizeof(&topo));
..
Il risultavo che mi aspettavo era :
topo <1244888>  &topo <1244888>  sizeof(topo) <40>  sizeof(&topo) <4>
e invece e` stato il seguente:
topo <1244888>  &topo <1244888>  sizeof(topo) <40>  sizeof(&topo) <40>
Ora la mia domanda e`: in che cosa differiscono topo ed &topo ?
Mi aspettavo differissero almeno nella dimensione...e invece...
Riflessione:
topo dovrebbe essere un int* ed &topo non puo` che essere lo stesso 
puntatore (visto che non si puo` salire ulteriormente in una ipotetica 
catena di dereferencing) ma &topo DEVE essere necessariamente un 
puntatore (non puo` che essere cosi` visto che ho 
applicato 'operator& ) 
tant'e` che se io faccio:
char c;
printf("\nsizeof(c) <%d> sizeof(&c) <%d>", sizeof(c), sizeof(&c));
ottengo:
sizeof(c) <1> sizeof(&c) <4>
Allora perche` la dimensione di &topo non e` 4 ovvero la dimensione di 
un puntatore?
Sono giunto ad una conclusione:
se penso al nome di un'array come ad un riferimento (a'la C++) penso 
bene o penso male?
In tal caso beh...mi torna gia` di piu`..."l'indirizzo di un 
riferimento non e` altro che l'indirizzo dell'oggetto riferito"...
Dunque in questa ottica, topo non sarebbe altro che un riferimento 
(cioe` un oggetto appartenente all'ambiente e non alla memoria) ad 
un'area di memoria contenente un buffer di interi.
In ogni caso mi domando: se proprio tra il topo e &topo non c'e` alcuna 
differenza, perche` non far segnalare un errore dal compilatore e 
togliere dai piedi questa ambiguita`?
C'e` qualche veterano che sa dare delle risposte a queste mie domande?
Inviato da 
www.mynewsgate.net

 togliere dai piedi questa ambiguita`?
Perche` le differenze ci sono (il tipo), e non esiste alcuna ambiguita` 
una volta comprese.
Spero di essere stato utile, ma dato che l'argomento e` piuttosto 
intricato, mi risulta difficile chiarire ogni possibile dubbio. Ti 
consiglio di leggere le FAQ del newsgroup comp.lang.c (in inglese), 
contengono molto materiale sulla differenza tra array e puntatori.
-- 
Enrico `Trippo' Porreca

 
Mi ha fatto molto piacere confrontarmi con una persona che conosce il 
linguaggio certamente meglio di me!!! Ritengo inoltre che per me sia 
stato molto utile nonostante abbia ancora diversi dubbi a riguardo.
Se hai voglia di continuare a discutere su questo argomento ne sono ben 
lieto.
Grazie tante!
Ale.
Inviato da 
www.mynewsgate.net

 topo <1244888>  &topo <1244888>  sizeof(topo) <40>  sizeof(&topo) <40>
Sostanzialmente sei rimasto stupito per ciò che concerne
    sizeof &topo
Ti aspettavi 4 e invece ottieni 40.
La specifica del C... questa sconosciuta!
   - Except when it is the operand of the sizeof operator
     or the unary & operator, or is a string literal used
     to initialize an array, an expression that has type
     ‘‘array of type’’ is converted to an expression with
     type ‘‘pointer to type’’ that points to the initial
     element of the array object and is not an lvalue.
     If the array object has register storage class,
     the behavior is undefined.
Così nelle seguenti espressioni
   topo         il tipo di topo     è convertito a: int *
   &topo        il tipo di topo NON è convertito a: int *
                                         ma rimane: array of int
   sizeof topo  il tipo di topo NON è convertito a: int *
                                         ma rimane: array of int
La specifica di sizeof è anche essa molto chiara e dipende dal tipo
del parametro a cui è applicta:
   - When applied to an operand that has type char, unsigned char,
     or signed char, (or a qualified version thereof) the result is 1.
   - When applied to an operand that has array type, the result is
     the total number of bytes in the array.
   - When applied to an operand that has structure or union type,
     the result is the total number of bytes in such an object,
     including internal and trailing padding.
Quindi, applicando la specifica:
     sizeof  topo  == 40 // se sizeof int == 4
     sizeof &topo  == 40 // se sizeof int == 4
- Dario (che ha riletto la specifica del C)
P.S. Ha inoltre completamente ragione Enrico `Trippo' Porreca
      quando sottolinea, nella sua accurata risposta, i molteplici
      errori presenti nel tuo codice sorgente: ad esempio, tra i molti,
       -  l'uso scorretto di %d invece di %p,
       -  la necessità di castare il risultato di sizeof
          ad un appropriato tipo intero,
       -  il fatto che puntatori a diversi tipi potrebbero
          avere sizeof diversi,
       -  etc...

 ha scritto:

Inviato da 
www.mynewsgate.net

 modificabile?
Il seguente programma mostra cosa è valido o no con le tue assunzioni:
#include <stdio.h>
#define MAX_LEN 10
typedef char mioArray[MAX_LEN];
void f1(const mioArray * ma) {
   /* (*ma)[0] = (*ma)[0]+1; ILLEGAL */
   printf("f1 -> %s\n", (char *) ma);
   /* *ma = *ma;             ILLEGAL */
   ma = ma;
}
void f2(mioArray * ma) {
   (*ma)[0] = (*ma)[0]+1;
   printf("f2 -> %s\n", (char *) ma);
   /* *ma = *ma;             ILLEGAL */
   ma = ma;
}
void f3(mioArray ma) {
   (ma)[0] = (ma)[0]+1;
   printf("f3 -> %s\n", (char *) ma);
   *ma = *ma;
   ma = ma;
}
void f4(char * ma) {
   (ma)[0] = (ma)[0]+1;
   printf("f4 -> %s\n", (char *) ma);
   *ma = *ma;
   ma = ma;
}
int main() {
    const mioArray ma = "Hello";
          mioArray mb = "Hello";
    f1(&ma);
/* f1(&mb); ILLEGAL */
/* f2(&ma); ILLEGAL */
    f2(&mb);
/* f3(ma); ILLEGAL */
    f3(mb);
/* f4(ma);  ILLEGAL */
    f4(mb);
    return 0;
}
Studialo un po'!

 lieto.
Si`, ma ti prego leggi le FAQ di comp.lang.c e/o una bozza dello 
standard C e vedrai che quello che sto dicendo non me lo sono inventato.
I tuoi discorsi sono ragionevoli da un punto di vista teorico, ma non 
dal punto di vista del C standard, che e` l'argomento di discussione di 
questo newsgroup.
-- 
Enrico `Trippo' Porreca

> medesimo.
Perbacco (avrei voluto dire "C" "A" "Z" "Z" "Z" ma la netiquette me lo 
impedisce!) se invece del tuo codice scorretto tu invece scrivi il corretto:
   printf("ntopo <%p> &topo <%p> sizeof topo <%lu> sizeof &topo <%lu>",
          (void *) topo,
          (void *) &topo,
          (unsigned long) sizeof topo,
          (unsigned long) sizeof &topo);
Cosa ottieni?
Io ottengo un risultato valido. Tu no?
Posta qui, per favore, cosa ottieni.
Grazie !
- Dario

Caro Enrico,
complimenti per la tua preparazione!
Ho letto lo standard...e dice pari pari quello che dici tu escluso che 
per 
una cosa (come mi ha fatto notare anche Dario ca?&egrave;inomane):
   topo         il tipo di topo     &egrave; convertito a: int *
   &topo        il tipo di topo NON &egrave; convertito a: int *
                                         ma rimane: array of int
   sizeof topo  il tipo di topo NON &egrave; convertito a: int *
                                         ma rimane: array of int
quindi e` giusto che mi stampi 4 e non 40 !
Come mai a te stampa 4 ?
Bah...comunque mi hai convinto! 
Grazie!
Inviato da 
www.mynewsgate.net

 
Inviato da 
www.mynewsgate.net

 topo <0012FED8> &topo <0012FED8> sizeof topo <40> sizeof &topo <40>
Direi che è perfetto!
In particolare
    sizeof topo ==  sizeof &topo
    == numero di bytes richiesti per la memorizzazione dell'array
come richiesto dallo standard
- Dario


Certo, topo rimane array di 10 int, ma *poi* ci metti la & davanti, 
ottenendo puntatore ad array di 10 int. Quindi,
     sizeof &topo
e` la dimensione di un puntatore ad un array di 10 int, probabilmente 4 
sulla macchina dell'OP.
Riporto quanto accade dalle mie parti:
     /* file junk.c */
     #include <stdio.h>
     int main(void)
     {
         int a[10];
         printf("%lu\n", (unsigned long) sizeof a);
         printf("%lu\n", (unsigned long) sizeof &a);
         return 0;
     }
Compilazione (con gcc in modalita` ANSI C) ed esecuzione:
     [tmp][0]$ gcc -Wall -ansi -pedantic -o junk junk.c
     [tmp][0]$ ./junk
     40
     4
-- 
Enrico `Trippo' Porreca

 quindi e` giusto che mi stampi 4 e non 40 !
No, vedi la mia risposta a Dario.
-- 
Enrico `Trippo' Porreca

 Infatti non sono programmatori, sono professori...
Certo, ma in un mondo ideale si presuppone che un professore che debba 
insegnare il C lo conosca.
Un mondo ideale e` lasciato come esercizio per il lettore.
                                              [Paul Graham]
-- 
Enrico `Trippo' Porreca


Ehm, credo che qui tu intendessi "40 e non 4", giusto? Devo imparare a 
leggere con attenzione prima di rispondere :-)
-- 
Enrico `Trippo' Porreca

     4
Dalle tue parti non si segue lo standard C.
Dirò di più: il seguente programma:
   #include <stdio.h>
   int main(void) {
     int a[10];
     printf("%lu\n", (unsigned long) sizeof a);
     printf("%lu\n", (unsigned long) sizeof &a);
     printf("%lu\n", (unsigned long) sizeof "Hello world");
     printf("%lu\n", (unsigned long) sizeof &"Hello world");
     return 0;
   }
Se sizeof(int) == 4 dovrebbe stampare:
   40
   40
   12
   12
Se invece stampa
   40
   4
   12
   4
allora è bacato.
E ciò perché la specifica parla anche di string literal...
- Dario (per quello che ho capito io leggendo lo standard)

   12
Potreste gentilmente indicarmi il nome del compilatore che stampa questi 
risultati? Onestamente sono basito.
-- 
Enrico `Trippo' Porreca

   - etc...
Dalle parti di comp.lang.c in questi casi si suol dire "Demons may fly 
out of your nose" :-)
-- 
Enrico `Trippo' Porreca

 risultati? Onestamente sono basito.
Il compilatore Microsoft presente in VisualStudio 6.0... sigh!
A questo punto sono basito anch'io!
- Dario

 ha scritto:

Inviato da 
www.mynewsgate.net


E` quello che uso anch'io! Aih aih!!
Inviato da 
www.mynewsgate.net

 Il compilatore Microsoft presente in VisualStudio 6.0... sigh!
Qualcuno sa se anche l'ultima versione produce questo risultato? Se si`, 
sarebbe il caso di segnalarlo al produttore... (Forse posso verificarlo 
personalmente domani, nel caso vi faccio sapere).
-- 
Enrico `Trippo' Porreca


Ma ROTFL! Visual Studio 2003: stesso identico problema. A questo punto 
chissa` da quanti anni se lo portano dietro... Ma la cosa piu` grave e` 
che il compilatore pensa che due oggetti dello stesso tipo possano avere 
dimensione diversa (nell'esempio che segue, i puntatori ad array di 10 
int &a e p):
     #include <stdio.h>
     int main(void)
     {
         int a[10];
         int (*p)[10];
         printf("%lu\n", (unsigned long) sizeof &a);
         printf("%lu\n", (unsigned long) sizeof p);
         return 0;
     }
Questo programma (compilato con il flag /Za per disabilitare le 
estensioni) produce il seguente risultato:
     40
     4
Inviterei caldamente gli utilizzatori di questo software a segnalare il 
bug al produttore, il quale si vanta di "ANSI/ISO compliance".
-- 
Enrico `Trippo' Porreca