Matriz de puntero de lenguaje C y puntero de matriz - Introducción

1. Disposición de la memoria de la matriz de punteros y el puntero de matriz

Los principiantes no siempre pueden diferenciar entre una matriz de punteros y un puntero de matriz. De hecho, es fácil de entender:

Matriz de punteros: Primero, es una matriz. Los elementos de la matriz son punteros. El número de bytes en la matriz está determinado por la propia matriz. Es la abreviatura de "matriz de punteros".

Puntero de matriz: Primero, es un puntero, que apunta a una matriz. En un sistema de 32 bits, siempre ocupa 4 bytes. En cuanto a cuántos bytes apunta, no lo sé. Es la abreviatura de "puntero a matriz".

下面到底哪个是数组指针,哪个是指针数组呢:
A)
int *p1[10];
B)
int (*p2)[10];
每次上课问这个问题,总有弄不清楚的。这里需要明白一个符号之间的优先级问题。

"[]" tiene una prioridad más alta que "*" . p1 se combina primero con "[]" para formar la definición de una matriz. El nombre de la matriz es p1, e int * modifica el contenido de la matriz, es decir, cada elemento de la matriz.

Ahora sabemos que se trata de una matriz, que contiene 10 punteros a datos de tipo int, es decir, una matriz de punteros. En cuanto a p2, es mejor entender. Aquí, la prioridad de "()" es mayor que la de "[]". El signo "*" y p2 constituyen la definición de un puntero. La variable de puntero se llama p2 e int modifica el contenido de la matriz. Es decir, cada elemento de la matriz.

La matriz no tiene nombre aquí, es una matriz anónima. Ahora sabemos que p2 es un puntero, que apunta a una matriz que contiene 10 datos de tipo int, es decir, un puntero de matriz . Podemos utilizar el siguiente diagrama para profundizar nuestra comprensión:Inserte la descripción de la imagen aquí

2. int (*) [10] p2 ----- tal vez el puntero a la matriz debería definirse así

Aquí hay un tema interesante que vale la pena discutir: ¿no solemos definir punteros con nombres de variable de puntero después de tipos de datos? ¿Por qué la definición del puntero p2 no se define de acuerdo con esta sintaxis? Quizás deberíamos definir p2 así:

   int (*)[10] p2;

int (*) [10] es un tipo de puntero y p2 es una variable de puntero. Esto se ve bien, pero se ve un poco incómodo. De hecho, el prototipo del puntero de matriz es de hecho así, pero la variable de puntero p2 se mueve hacia adelante por conveniencia y belleza. Puedes entender esto en privado. Aunque el compilador no lo cree así. _

3. Comente la diferencia entre ay & a nuevamente

En este caso, el problema está aquí. Anteriormente hablamos sobre la diferencia entre a y & a, ahora echemos un vistazo al siguiente código:

int main()
{
   char a[5]={'A','B','C','D'};
   char (*p3)[5] = &a;
   char (*p4)[5] = a;
   return 0;
}

¿Cuál de los usos anteriores de p3 y p4 es correcto? ¿Cuál será el valor de p3 + 1? ¿Cuál será el valor de p4 + 1?
No hay duda de que p3 y p4 son punteros de matriz que apuntan a toda la matriz. & a es la primera dirección de toda la matriz, a es la primera dirección del primer elemento de la matriz, su valor es el mismo pero el significado es diferente.

En lenguaje C, los tipos de datos en ambos lados del símbolo de asignación "=" deben ser iguales. Si son diferentes, se requiere una conversión de tipos explícita o implícita. Los tipos de datos en ambos lados del "=" en la definición de p3 son exactamente los mismos, mientras que los tipos de datos en ambos lados del "=" en la definición de p4 son inconsistentes.

El tipo de la izquierda es un puntero a toda la matriz y el tipo de datos de la derecha es un puntero a un solo carácter. Se da la siguiente advertencia en Visual C ++ 6.0:

   warning C4047: 'initializing' : 'char (*)[5]' differs in levels of indirection from 'char *'。

Afortunadamente, aunque aquí se da una advertencia, ya que los valores de & a y a son los mismos, y cuando la variable se usa como rvalue, el compilador solo toma el valor de la variable, por lo que no hay problemas en la ejecución. Pero todavía te advierto que no uses esto.

Ahora que está claro que tanto p3 como p4 apuntan a toda la matriz, los valores de p3 + 1 y p4 + 1 son fáciles de entender.

Pero si modificas el código, ¿cuál será el problema? ¿Cuáles son los valores de p3 + 1 y p4 + 1?

int main()
{
   char a[5]={'A','B','C','D'};
   char (*p3)[3] = &a;
   char (*p4)[3] = a;
   return 0;
}
甚至还可以把代码再修改:
int main()
{
   char a[5]={'A','B','C','D'};
   char (*p3)[10] = &a;
   char (*p4)[10] = a;
   return 0;
}

¿Qué tipo de problemas habrá en este momento? ¿Cuáles son los valores de p3 + 1 y p4 + 1?

Espero que los lectores puedan considerar detenidamente los problemas anteriores.

Cuatro, dirección de conversión forzada

Considere primero el siguiente ejemplo:

struct Test
{
   int Num;
   char *pcName;
   short sDate;
   char cha[2];
   short sBa[4];
}*p;
假设p 的值为0x100000。如下表表达式的值分别为多少?
   p + 0x1 = 0x___ ?
   (unsigned long)p + 0x1 = 0x___?
   (unsigned int*)p + 0x1 = 0x___?

Creo que mucha gente no entenderá lo que significa esta pregunta al principio. De hecho, si miramos más de cerca, este conocimiento parece familiar. ¿Cómo analizar una variable de puntero y un entero?

¿Recuerda la diferencia entre nuestra expresión "a + 1" y "& a + 1" antes?

De hecho, es lo mismo aquí. Sumar y restar una variable de puntero a un número entero no es sumar o restar directamente el número entero con la dirección en la variable de puntero. La unidad de este entero no es el byte sino el número de elementos.

Entonces: el valor de p + 0x1 es 0x100000 + sizof (Prueba) * 0x1. En cuanto al tamaño de esta estructura es de 20bytes, se ha explicado en detalle en los capítulos anteriores. Entonces el valor de p + 0x1 es: 0x100014.

¿Qué pasa con el valor de (unsigned long) p + 0x1?
Esto implica coerción, coaccionando el valor almacenado en la variable de puntero p en un entero largo sin signo. Una vez que se coacciona cualquier valor, se cambia su tipo.
Entonces, esta expresión es en realidad un entero largo sin signo más otro entero. Entonces su valor es: 0x100001.

¿Qué pasa con el valor de (unsigned int *) p + 0x1?
La p aquí se convierte en un puntero a un entero sin signo. Entonces su valor es: 0x100000 + sizof (unsigned int) * 0x1, que es igual a 0x100004.

La pregunta anterior no parece tener ningún contenido técnico Aquí hay un contenido técnico: ¿Cuál es el valor en el sistema x86?

intmain()
{
   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;
}

Esta es una pregunta que me hizo un alumno durante mi conferencia, la vio en Internet, se dice que ha dejado perplejos a n personas. Después de leer las preguntas, le dije que esta gente ciertamente no entiende el montaje. Para una persona que entiende el montaje, este tipo de pregunta es realmente un caso pequeño. Analicemos y analicemos este problema a continuación:

Según la explicación anterior, la diferencia entre & a + 1 y a + 1 es clara.

ptr1: convierta a la fuerza el valor de & a + 1 en tipo int , y asígnelo a la variable ptr de tipo int . ptr1 debe apuntar al siguiente tipo de datos int de la matriz a. ptr1 [-1] se analiza como * (ptr1-1), es decir, ptr1 retrocede 4 bytes. Entonces su valor es 0x4.
ptr2: De acuerdo con la explicación anterior, el valor de (int) a + 1 es la dirección del segundo byte del elemento a [0]. Luego, convierta esta dirección en un valor de tipo int y asígnela a ptr2, lo que significa que el valor de ptr2 debe ser el contenido de 4 bytes consecutivos a partir del segundo byte del elemento a [0].

El diseño de la memoria es el siguiente:
Inserte la descripción de la imagen aquí
Bueno, aquí viene el problema, ¿qué se almacena exactamente en estos 4 bytes consecutivos? En otras palabras, ¿cómo se almacenan los valores de los elementos a [0] y a [1]? Esto involucra los modos endian grande y pequeño del sistema, si comprende el ensamblaje, esto no es un problema en absoluto. Como no sabe en qué modo está el sistema actual, debe encontrar una manera de probarlo. El modo small-endian y el método de prueba se discutieron en detalle cuando se explicó la palabra clave union en el Capítulo 1, vaya al otro lugar para verla y no entraré en detalles aquí. Podemos usar la siguiente función para probar el modo actual del sistema.

int checkSystem( )
{
   union check
   {
      int i;
     char ch;
   } c;
   c.i = 1;
   return (c.ch ==1);
}

Si el sistema actual está en modo big-endian, esta función devuelve 0; si está en modo little-endian, la función devuelve 1. Es decir, si el valor de retorno de esta función es 1, el valor de * ptr2 es 0x2000000. Si el valor de retorno de esta función es 0, el valor de * ptr2 es 0x100.

Enlace original: http://c.biancheng.net/cpp/html/476.html

Supongo que te gusta

Origin blog.csdn.net/zhuyin6553/article/details/88380782
Recomendado
Clasificación