Lenguaje C 8 Dachang pointer pen test preguntas - agarre el puntero

Para la precisión de las preguntas y el hábito de nuestro proceso de aprendizaje general, todos los códigos de preguntas aquí se ejecutan en el entorno X86 (plataforma de 32 bits) .

Tema uno:

#include <stdio.h>
int main()
{
	int a[5] = { 1, 2, 3, 4, 5 };
	int* ptr = (int*)(&a + 1);
	printf("%d,%d", *(a + 1), *(ptr - 1));
	return 0;
}
//程序的结果输出什么?

Primero estudiemos lo que está almacenado en la variable de puntero ptr. &a+1 significa sacar la dirección completa y saltar hacia atrás según el tamaño del tipo de matriz, es decir, señalar el espacio del tamaño del tipo de matriz detrás del último elemento 5 de la matriz .

Pero no podemos dar esta dirección a la variable de puntero ptr, porque los tipos son diferentes (&a+1 es un tipo de puntero de matriz, prt es un tipo de puntero de entero), así que antes (&a+1) (int* ) para emitir el tipo Entonces averiguamos qué está almacenado en la variable de puntero ptr.

Así que ahora mira la sección de salida. *(a+1) es relativamente simple, a es la dirección del primer elemento, a+1 es la dirección del segundo elemento, y desreferencia para obtener el segundo elemento 2, que es una respuesta incuestionable. Para *(ptr-1), conocemos la dirección almacenada en ptr, y sabemos que ptr es un puntero de número entero , ptr-1 es equivalente a saltar hacia adelante el tamaño de un tipo de número entero, es decir, apuntar a la posición de el último elemento 5 de la matriz . Elimina la referencia para obtener el elemento 5 .

 

 Así que el resultado de salida final es: 2, 5 .

Tema dos:

#include <stdio.h>

struct Test
{
	int Num;
	char* pcName;
	short sDate;
	char cha[2];
	short sBa[4];
}*p;
//如下表表达式的值分别为多少?
//已知,结构体Test类型的变量大小是20个字节
int main()
{
	printf("%p\n", p + 0x1);
	printf("%p\n", (unsigned long)p + 0x1);
	printf("%p\n", (unsigned int*)p + 0x1);
	return 0;
}
//程序最后输出什么?

Prestamos atención a la definición de la estructura y definimos una variable de puntero de estructura p .

p+0x1 es muy simple, 0x1 es 1, simplemente escrito en formato hexadecimal. Esto es lo mismo que el cálculo del puntero al que estamos acostumbrados, p es un puntero de estructura, luego p+1 debería saltar hacia atrás por el tamaño de un tipo de estructura, es decir, apuntar a la posición del espacio de estructura después del espacio de estructura . Y sabemos que p es una variable global, y la variable global se inicializa en 0 por defecto , entonces podemos saber que p=0, p+1=20. Y %p es un formato de impresión hexadecimal, por lo que el resultado es: 00000014 .

(largo sin firmar) p + 0x1 parece más simple. El tipo p se convierte en un entero largo, lo que significa que p ya no es un puntero y el 0 que almacena es un número en un sentido simple. Entonces 0 + 0x1 es igual a 00000001 .

(int unsigned*)p + 0x1 también es muy simple. p era originalmente un puntero de estructura, pero ahora se convierte en un puntero de entero, lo que significa que el paso de p cambia de 20 bytes a 4 bytes al sumar y restar números enteros . Entonces p=0, p+1=4 está fuera de toda duda. El resultado de la salida es: 00000004 .

 Tema tres:

#include <stdio.h>

int main()
{
	int a[4] = { 1, 2, 3, 4 };
	int* ptr1 = (int*)(&a + 1);
	int* ptr2 = (int*)((int)a + 1);
	printf("%x,%x", ptr1[-1], *ptr2);
	return 0;
}
//程序的结果输出什么?

El análisis de ptr1 no es diferente al del título 1. ptr1 almacena la dirección del tamaño del tipo de matriz detrás del último elemento de la matriz . Y ptr1 es un puntero entero.

ptr1[-1] se puede reescribir como *(ptr-1), porque hemos dicho que mientras las operaciones de los subíndices de matriz sean operaciones de puntero, las operaciones de los subíndices de matriz son solo una forma abreviada de operaciones de puntero . Luego, ptr1[-1] debería apuntar al último elemento 4 de la matriz y quitarle la referencia para obtener el resultado de salida 00000004 .

(int*)((int)a+1) ¿Cómo entenderlo? a es el nombre de la matriz, luego apunta a la dirección del primer elemento de la matriz y luego lo coacciona al tipo, luego la dirección almacenada en a es un número en un sentido simple , agregamos 1 a este número , y luego forzar el tipo Convertido a un puntero entero y almacenado en ptr2. Es decir, a es la dirección que apunta al primer elemento del arreglo, (int)a+1 representa el número de dirección + 1, y el número de dirección + 1 significa que si es un puntero, apuntará al byte siguiente . Luego transfiéralo a un puntero entero, luego la dirección a la que apunta ptr2 es:

 

Elimina la referencia de nuevo para encontrar el contenido del espacio en el cuadrado rojo. Debido a que está almacenado en Little Endian, el resultado de salida es: 02000000 .

Cabe señalar que el formato de impresión utilizado en esta pregunta es %x, que es hexadecimal, y se omitirá el 0 antes de los dígitos significativos .

Tema cuatro:

#include <stdio.h>

int main()
{
	int a[3][2] = { (0, 1), (2, 3), (4, 5) };
	int* p;
	p = a[0];
	printf("%d", p[0]);
	return 0;
}
//程序的结果输出什么?

En primer lugar, observemos que tres expresiones de coma se almacenan en la matriz bidimensional a . Creo que alguien pisará el pozo aquí. Es decir, tres expresiones de coma, entonces el contenido en la matriz bidimensional a debe ser 1, 3, 5, 0, 0, 0 (la matriz a tiene 6 elementos, y el contenido no es suficiente y se llena automáticamente con 0).

 

Después de descubrir qué almacena la matriz bidimensional, estudiemos qué es a[0]. a[0] es el primer elemento del arreglo bidimensional, que es un arreglo, es decir, la variable puntero p almacena el primer elemento del arreglo bidimensional, que es un arreglo unidimensional, es decir , lleva a un nombre de matriz . Entonces p[0] es fácil de entender, p es un nombre de matriz y p[0] es el primer elemento de la matriz, que es 1. Entonces salida 1 .

 

 

Tema cinco:

#include <stdio.h>

int main()
{
	int a[5][5];
	int(*p)[4];
	p = a;
	printf("%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
	return 0;
}
//程序的结果输出什么?

Podemos ver que el puntero de matriz p almacena la dirección del primer elemento de la matriz bidimensional a, que no es difícil de analizar. La matriz a la que apunta p tiene el mismo contenido de almacenamiento que la matriz a, pero la asignación de memoria es diferente

Superponemos estos dos espacios:

 Se puede ver que la diferencia entre &p[4][2] y &a[4][2] es de 4 elementos , pero debido a que la posición de la dirección de &p[4][2] es relativamente baja, la resta de dos es negativa. número, es decir -4. Pero queremos imprimir como %p, %p es un número sin signo, por lo que sabemos que el resultado debe ser un número hexadecimal muy grande. Entonces la negación original de -4 es:

Entonces la salida del primero es: fffffffc .

Sabemos que al restar los punteros (direcciones), obtenemos la cantidad de elementos que difieren, como hemos mencionado anteriormente. Entonces %d es un formato de impresión firmado, por lo que la salida es -4 .

 

Tema seis:

#include <stdio.h>

int main()
{
	int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	int* ptr1 = (int*)(&aa + 1);
	int* ptr2 = (int*)(*(aa + 1));
	printf("%d,%d", *(ptr1 - 1), *(ptr2 - 1));
	return 0;
}
//程序的结果输出什么?

El resultado de *(ptr1-1) es 10 , ¿no debería estar bien?

*(aa+1) se puede reescribir como aa[1], que es el segundo elemento de un arreglo bidimensional, que es un arreglo unidimensional, es decir , se obtiene un nombre de arreglo . El nombre de la matriz se convierte a la fuerza en un puntero de número entero y se almacena en la variable de puntero ptr2.En este momento, se conoce la posición de puntero específica de ptr2. (¡Las matrices bidimensionales se almacenan de forma contigua en el espacio de memoria!)

*(ptr2-1) es saltar ptr2 hacia adelante por el tamaño de un tipo de número entero y eliminar la referencia, es decir, se encuentra el elemento 5, por lo que el resultado de salida es 5

Tema siete:

#include <stdio.h>

int main()
{
	char* a[] = { "work","at","alibaba" };
	char** pa = a;
	pa++;
	printf("%s\n", *pa);
	return 0;
}
//程序的结果输出什么?

La matriz de punteros a almacena tres constantes de cadena ( las constantes sobre cadenas se introdujeron en blogs anteriores), y el puntero secundario pa se usa para apuntar a esta matriz (char** pa=a;), lo que indica que pa La variable almacena la dirección del primer elemento de la matriz . pa++ apunta al segundo elemento de la matriz, *pa indudablemente obtiene la dirección del primer elemento de la constante de cadena "at", y luego la imprime a través de %s para llegar a .

Tema ocho:

#include <stdio.h>

int main()
{
	char* c[] = { "ENTER","NEW","POINT","FIRST" };
	char** cp[] = { c + 3,c + 2,c + 1,c };
	char*** cpp = cp;
	printf("%s\n", **++cpp);
	printf("%s\n", *-- * ++cpp + 3);
	printf("%s\n", *cpp[-2] + 3);
	printf("%s\n", cpp[-1][-1] + 1);
	return 0;
}
//程序的结果输出什么?

 Primero analicemos lo que se almacena en c, cp y cpp. Hay cuatro constantes de cadena almacenadas en la matriz de punteros c . La matriz de punteros cp almacena las direcciones de cuatro constantes de cadena . El puntero de tercer nivel cpp almacena la dirección del primer elemento de la matriz de punteros cp . Entonces el croquis se puede dibujar como:

 

**++cpp , debido a la asociatividad , necesitamos calcular ++cpp primero, luego cpp apunta a la dirección del segundo elemento de cp, y luego elimina las referencias para obtener el segundo elemento de cp, que nuevamente apunta al tercero elemento de c, y luego eliminar la referencia para obtener el tercer elemento de c, que es la dirección del primer carácter de la constante de cadena "PUNTO", e imprimir el PUNTO en forma de %s . Cabe señalar que la operación ++ está involucrada en la operación de cpp, por lo que la siguiente operación comenzará desde la posición calculada .

 *--*++cpp+3 , o calcule ++cpp primero, en este momento cpp apunta a la dirección del tercer elemento de cp, luego elimina la referencia para obtener c+1, luego --, c+1 se convierte en c , y luego eliminar la referencia para obtener la dirección del primer elemento de c. Sobre la base de esta dirección +3, obtiene la dirección del cuarto carácter de la constante de cadena "ENTER", y luego la imprime en forma de %s para obtener ER .

 *cpp[-2]+3 se puede reescribir como *(*(cpp-2))+3 , es decir, en este momento cpp apunta a la dirección del primer elemento de cp, y al desreferenciarlo se obtiene c+3 , c+3 es apuntar a la dirección del cuarto elemento de c, desreferencia para obtener el cuarto elemento de c, este elemento es la dirección del primer elemento de la cadena constante "FIRST", sobre la base de esta dirección +3 obtendrá el primer elemento constante de cadena Una dirección de cuatro caracteres desde la cual se imprime %s para obtener ST . ( En este momento, cpp no ​​tiene ninguna operación real )

 cpp[-1][-1]+1 se puede reescribir como *(*(cpp-1)-1)+1, en este momento cpp apunta a la dirección del segundo elemento de cp, desreferencia para obtener c+2 , luego - 1 Obtenga c+1, que apunta a la dirección del segundo elemento de c, elimine la referencia para obtener el segundo elemento de c, este elemento es la dirección del primer elemento de la constante de cadena "NUEVO", y luego + 1 apunta a La dirección del segundo carácter de la constante de cadena, EW se obtiene imprimiéndola en forma de %s .

 

 

Supongo que te gusta

Origin blog.csdn.net/weixin_59913110/article/details/125597828
Recomendado
Clasificación