2012-04-26 10 views
5

Cuando compilo y ejecuto este código de forma consecutiva un par de veces, informa la dirección de cc como 0x0012FF5C. Pero cuando trato de imprimir la cadena en esa dirección usando la segunda llamada a printf in foo, imprime basura en lugar de imprimir "Hola"? ¿¿Porque?? Qué sucede si directamente explico la dirección como argumento cuando sé que la dirección se encuentra dentro del espacio de direcciones de la aplicación (al menos hasta que no reinicie mi PC, o inicie alguna otra aplicación que requiera mucho espacio y que cause mi aplicación debe ser eliminada) ??¿Por qué no podemos usar el direccionamiento directo en el código c o C++?

void foo(char *cc[]) 
{ 
    printf("%x\n",cc); 
    printf("%s\n",(char *)(0x0012FF5C)); 
} 

int main() 
{ 
    char *c[] = {"Hello","World"}; 
    foo(c); 
} 
+2

¿Por qué quieres hacer esto ya que solo estás cubriendo tus apuestas de que se usará la misma dirección? Haz un pequeño cambio y rompes el código.Parece algo bastante tonto de hacer o incluso contemplar. –

+0

No elimine las preguntas que se responden. Alguien se esforzó por responder tu pregunta. –

Respuesta

2

La ubicación de la memoria de su proceso puede haber cambiado entre las dos ejecuciones. No puede hacer eso, está intentando leer una dirección que no está asignada por su proceso. Por otra parte tengo muchas advertencias:

test.c: En función de 'foo': test.c: 6: advertencia: formato '% x' espera escribir 'unsigned int', pero el argumento tiene 2 escribir 'char * * '

test.c: 7: advertencia: formato '% s' espera escribir 'char *', pero el argumento 2 tiene por tipo 'int'

test.c: 9: advertencia: formato' % x 'espera tipo' unsigned int ', pero el argumento 2 tiene tipo' char ** '

12

Porque no hay nada en el estándar C o C++ que garantice eso. Esas direcciones pueden ser predecibles dependiendo de su compilador/sistema operativo, pero no cuente con ello.

#include <stdio.h> 

int main(void) { 
    char s[] = "okay"; 
    printf("%p", (void*)s); 
    return 0; 
} 

puedo obtener una dirección diferente cada vez que (gcc en linux). No utilice "literales de dirección";)

Proceso de espacio de direcciones de modernos sistemas operativos se asignaron al azar para la seguridad en cada ejecución:

http://en.wikipedia.org/wiki/Address_space_layout_randomization

+0

Debe convertir a nulo * su dirección para que sea estándar. – md5

+1

Hmmph. -Wall -pedantic no dice nada pero tiene usted razón, el borrador C99 dice para fprintf "p El argumento debe ser un puntero al vacío". Editado – delicateLatticeworkFever

+0

@Kirilenko: ¿No hay una conversión implícita de 'T *' a 'void *' para –

3

No creo que su (0x0012FF5C) representa poiter. Pruebe (char *) (0x0012FF5C).

Además de eso, como otros dicen, esto no tiene ningún valor práctico, ya que no hay garantía de que la cadena se ubicará en esa dirección en cada ejecución. No se trata de un ensamblaje incrustado en el que se dice poner esta cadena en esta ubicación y luego usar la dirección directamente.

2

cuando sé que la dirección

Bueno, en realidad no sé nada acerca de la dirección cuando estás-codificación duro, estás adivinando en ella.

Hay muchas razones por las que la dirección de una cosa podría cambiar entre las ejecuciones del mismo programa. Hay aún más razones por las cuales la dirección podría cambiar si está cambiando el código (como parece estar haciendo aquí).

2

Como alguien dijo anteriormente, la ubicación de su código en la memoria, puede variar entre ejecuciones, y lo mismo ocurre con las ubicaciones de las variables. Intenta ejecutar este código. Imprime la dirección real de la variable a la que apunta en la memoria. Verá que las ejecuciones múltiples ceden a direcciones completamente diferentes.¡Recuerda siempre eso!

#include <stdio.h> 

void foo(char *cc[]) 
{ 
    printf("%x\n",cc); 
    printf("%s\n",(0x0012FF5C)); //this line will fail, there is no guarantee to that 
    cc++; 
    printf("%x\n",cc); 
} 

int main() 
{ 
    char *c[] = {"Hello","World"}; 
    printf("c array location: %p",c); //print location 
    foo(c); 
} 
5

bien, lo primero es, nunca asuma que múltiples ejecuciones devolverá las mismas direcciones

ahora. digamos que tienes suerte y obtén las mismas direcciones. Observe que cc es una matriz de punteros. Y está enviando la dirección base de esta matriz. Es necesario enviar el valor del primer elemento de la matriz

Prueba de esto, y si tienes suerte que funciona,

printf("%s\n",*((char**)(0x0012FF5C))); 
+0

bien ... el valor de la dirección base y el valor del primer elemento será el mismo. – user1232138

+1

@ user1232138 ¡Verifique mi edición! ** La dirección base y el valor no son lo mismo. La desreferenciación de la dirección base y el valor en la dirección base son los mismos ** –

4

Si ejecuta su programa en una máquina sin virtual memory y memory protection, que muy probablemente Tendría éxito. Estas tecnologías/características son la razón por la cual no funciona.

Cada proceso tiene su propio espacio de direcciones virtuales, cuyas direcciones se traducen a direcciones de hardware mediante el procesador memory-management unit.

6

Porque la primera printf le da la dirección de una matriz de char * cuando la segunda printf intenta imprimir esta matriz de char * como una cadena.

+0

Sí, cc necesita desreferenciarse para que el puntero llegue al comienzo de la cadena real. –

1

En primer lugar, printf("%x\n",cc); no imprime la dirección de cc. En el mejor de los casos, imprime el valor de cc, pero el comportamiento no está definido porque ha pasado el argumento de tipo incorrecto para el formato %x. Espera unsigned int, has proporcionado un puntero.

El comportamiento más probable en la práctica es que imprimirá la parte menos significativa del valor de cc (por lo que en una máquina de 32 bits parecerá que funciona, mientras que en una máquina de 64 bits no verá el todo dirección). Pero podría salir mal de diferentes maneras.

Lo segundo, cc tiene tipo char**, por lo que el valor de cc no es un puntero al primer carácter de una cadena, que es un puntero al primer elemento de la matriz de cmain. El formato %s espera un puntero al primer carácter de una cadena. Entonces, incluso si el valor de cc es realmente 0x0012FF5C, pasar ese valor a printf con el formato %s es incorrecto.

La "basura" que está viendo es un intento de imprimir los datos del puntero desde esa matriz de punteros, como si se tratara de datos de caracteres pertenecientes a una cadena. No lo es

0

He simplificado un poco su ejemplo. Si conoce la dirección de la cadena, puede leer desde esa dirección.

#include <stdio.h> 

void foo(char cc[]) 
{ 
    int i; 
    printf("%p\n",cc); 
    printf("Type the address you would like to read:"); 
    scanf ("%x",&i); 
    printf("Character value at your address: %c\n",*((char *)(i))); 
} 

int main() 
{ 
    char c[] = "Hello"; 
    foo(c); 
} 

Esto le permitirá leer desde la dirección que especifique desde la línea de comando. Primero imprimirá la dirección base de la matriz de caracteres, para que sepa dónde buscar la cadena.

Ejemplo:

$ ./a.out 
0xbfcaaf3a 
Type the address you would like to read:bfcaaf3d 
Character value at your address: l 

Como era de esperar esta opción se imprime la cuarta letra del Hello.

+0

¿Por qué no podemos usar esa dirección para imprimir toda la cadena? – user1232138

+0

@ user1232138: Puedes. Cambie la última línea de foo a 'printf (" Valor del carácter en su dirección:% s \ n ", (char *) (i));' – Lucas

+0

Intenté eso pero no funcionó ... – user1232138

Cuestiones relacionadas