2010-10-31 17 views
5

Por lo que sé sobre el operador '&', devuelve la dirección base del operando en la memoria.Comprensión del operador '&'

Imaginemos el siguiente escenario (como en mi máquina):

  • sizeof (int) = 4 bytes
  • sizeof (float) = 4 bytes
  • sizeof (char) = 1 byte

Ahora, si escribo algo como esto:

void main() { 
int i = 5411; 
int *ip = &i; 
char *c = &i; 

printf("%d",*ip); 
printf("%c",*c); 
} 

El primer printf() debería darme 5411. Hablando del segundo printf(), la dirección base de i contiene 10101001 (orden superior 8 bits = 1 byte para el puntero de tipo char). Por lo tanto, * c debería dar 169, que cuando se convierte a% c es un carácter no válido.

Pero el compilador me está dando '#' u otro resultado válido. Por que es esto entonces ? ¿Alguna entrada?

EDITAR (tomado del comentario del autor sobre una de las respuestas):

Eso era sólo un caso ficticio, ya que estaba lejos de la máquina real.
El caso actual es i = 5411

+0

En cualquier caso, si intenta "imprimir" un "char" se mostrará como un carácter, no como el código entero correspondiente. –

+0

probablemente tenga algo que ver con la codificación de caracteres que se usa, supongo. –

+0

Sí, yo también estoy de acuerdo con eso. Pero debe haber una razón para obtener el valor '#' de la última impresión(). No es un valor de basura. –

Respuesta

24

Parece que tiene problemas para entender cómo se almacenan los enteros en la memoria. Tome 5411 como ejemplo.

5411 = 1010100100011 

este número de 13 dígitos binarios tiene sin embargo, ya que un int es de 32 bits, que debe ser la almohadilla de 32 dígitos

5411 = 00000000 00000000 00010101 00100011 

En una pequeña máquina endian (x86, ARM por defecto), los bytes menos significativos se almacenan en la parte delantera, por lo que en la memoria:

00100011 00010101 00000000 00000000 
^ 
c   c + 1  c + 2  c + 3 
ip 

por lo tanto, *c deberían volver 00100011 es decir, 35 ('#').

+0

¡¡Muchas gracias !! Esto es exactamente lo que estaba buscando :-) –

+0

¿De dónde vino '5411'? El código del OP inicializa claramente 'i' con' 1154'. – AnT

+0

@AndreyT: ver los comentarios de OP sobre otras respuestas. – kennytm

5

ASCII sólo define los caracteres hasta 127. Además de eso, lo que realmente quiere hacer es imprimir el numérico correspondiente al valor en *c, esto también se hace usando %d. ..

printf("%d",*c); 

... debe mostrar el número como usted espera.

+0

Eso fue solo un caso falso, ya que estaba lejos de la máquina real. El caso real es i = 5411.% c da '#' y% d da 35 (en lugar de 169) –

+0

@Guarav: ASCII solo define caracteres hasta 127, y lo que realmente parece querer es imprimir números, por lo que imprimir números, no caracteres. –

+2

@Gaurav - ¿Por qué esperas 169? En una pequeña máquina endian, debería ser 35. En una máquina endian grande, debería ser 0. –

1

La dirección de * c es la de i, porque ha asignado c a & i. Luego tomará el más alto o más bajo (depende del endian) e imprimirá ese carácter.

+0

El caso de i = 5411 está imprimiendo '#' como el caracter. Un ASCII de 35 (10101001), que no es el 8 superior ni el inferior de 8 bits. –

+0

@Gaurav - 35 en binario es 00100011 –

+0

De acuerdo. No habrá un truncamiento con el * c porque el puntero del carácter es lo suficientemente grande como para contener todo el valor de la ubicación de la memoria. –

1

sólo para aprender algo acerca de la codificación de los números enteros que debe experimentar un poco y hacer

printf("0x%X, %X|%X|%X|%X\n", 
    i, 
    i & 0xFF, 
    (i >> 8) & 0xFF 
    (i >> 16) & 0xFF 
    (i >> 24) & 0xFF 
); 

Una luego hacer lo mismo con c[0], c[1] etc y otras cadenas de formato como %c.

3

En primer lugar, su programa está mal formado. Ni C ni C++ permiten inicializar un puntero char * con un valor de int *. Necesita una conversión explícita en su inicialización del puntero c.

En segundo lugar, qué byte del número entero original i - orden superior o inferior - reside en su "dirección base" está definido por la implementación. Hay arquitecturas little-endian, donde el orden inferior pero se verá a través de *c (que tiene el valor 130 en una máquina de 8 bits char, no 114). Y hay arquitecturas de big-endian, donde el orden superior se verá a través de *c (que es 0 en una máquina de 8 bits char). Por lo tanto, debe esperar que el carácter con el código 130 o el carácter con el código 0 se imprima con el especificador de formato %c.

En tercer lugar, en una implementación típica, normalmente no existe el "código de carácter no válido". Para cualquier código, algo generalmente se imprimirá de una forma u otra. Sin embargo, no veo cómo logró obtener # como resultado de su código. ¿Es este el verdadero código que estabas ejecutando?

+0

Hola Andrey. 1-> El código está compilando. ¿Debería importarme el casting explícito entonces? ... 2-> Sí, no estaba al tanto de esto, que KennyTM respondió ... 3-> Mencioné, es un código falso –

+1

@Gaurav Kalra: ¿compilar como qué? Usted etiquetó su pregunta [C] y [C++]. Este código no se compilará como C++ por ningún compilador de C++ que se precie. Los compiladores de C con una comprobación de errores excesivamente relajada pueden permitir eso (con una advertencia), pero el código sigue siendo ilegal incluso como C, por lo que si le importa escribir código C válido, se requiere el reparto. – AnT