Array de ponteiro de linguagem C e ponteiro de array - Introdução

1. Layout de memória da matriz do ponteiro e do ponteiro da matriz

Iniciantes nem sempre podem dizer a diferença entre array de ponteiro e ponteiro de array. Na verdade, é fácil de entender:

Matriz de ponteiros: primeiro, é uma matriz. Os elementos da matriz são ponteiros. O número de bytes na matriz é determinado pela própria matriz. É a abreviação de "array of pointers".

Ponteiro de matriz: primeiro, é um ponteiro, que aponta para uma matriz. Em um sistema de 32 bits, ele sempre ocupa 4 bytes. Quanto a quantos bytes ele aponta, eu não sei. É a abreviação de "ponteiro para matriz".

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

"[]" tem uma prioridade mais alta do que "*" . p1 é primeiro combinado com "[]" para formar a definição de uma matriz. O nome da matriz é p1 e int * modifica o conteúdo da matriz, ou seja, cada elemento da matriz.

Agora sabemos que este é um array, que contém 10 ponteiros para dados do tipo int, ou seja, um array de ponteiros. Quanto a p2, é melhor entender. Aqui, a prioridade de "()" é maior do que a de "[]". O sinal "*" e p2 constituem a definição de um ponteiro. A variável do ponteiro é chamada de p2 e int modifica o conteúdo da matriz. Ou seja, cada elemento da matriz.

O array não tem um nome aqui, é um array anônimo. Agora sabemos que p2 é um ponteiro, que aponta para um array contendo 10 dados do tipo int, ou seja, um ponteiro de array . Podemos usar o diagrama a seguir para aprofundar nossa compreensão:Insira a descrição da imagem aqui

2. int (*) [10] p2 ----- talvez o ponteiro do array deva ser definido assim

Aqui está um tópico interessante que vale a pena discutir: não costumamos definir ponteiros com nomes de variáveis ​​de ponteiro após tipos de dados? Por que a definição do ponteiro p2 não está definida de acordo com esta sintaxe? Talvez devêssemos definir p2 assim:

   int (*)[10] p2;

int (*) [10] é um tipo de ponteiro e p2 é uma variável de ponteiro. Isso parece bom, mas parece um pouco estranho. Na verdade, o protótipo do ponteiro do array é assim, mas a variável do ponteiro p2 é movida para a frente por conveniência e beleza. Você pode entender isso em particular. Embora o compilador não pense assim. _

3. Discuta a diferença entre a e & a novamente

Nesse caso, o problema está aqui. Anteriormente, falamos sobre a diferença entre a e & a, agora vamos dar uma olhada no seguinte código:

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

Qual dos usos acima de p3 e p4 está correto? Qual será o valor de p3 + 1? Qual será o valor de p4 + 1?
Não há dúvida de que p3 e p4 são ponteiros de array, apontando para todo o array. & a é o primeiro endereço de todo o array, a é o primeiro endereço do primeiro elemento do array, seu valor é o mesmo, mas o significado é diferente.

Na linguagem C, os tipos de dados em ambos os lados do símbolo de atribuição "=" devem ser iguais. Se forem diferentes, é necessária a conversão explícita ou implícita do tipo. Os tipos de dados em ambos os lados de "=" na definição de p3 são exatamente os mesmos, enquanto os tipos de dados em ambos os lados de "=" na definição de p4 são inconsistentes.

O tipo à esquerda é um ponteiro para todo o array e o tipo de dados à direita é um ponteiro para um único caractere. O seguinte aviso é fornecido no Visual C ++ 6.0:

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

Felizmente, embora um aviso seja dado aqui, uma vez que os valores de & a e a são iguais, e quando a variável é usada como um rvalue, o compilador apenas obtém o valor da variável, portanto, não há problema na execução. Mas eu ainda aviso você para não usar isso.

Agora que está claro que p3 e p4 apontam para a matriz inteira, os valores de p3 + 1 e p4 + 1 são fáceis de entender.

Mas se você modificar o código, qual será o problema? Quais são os valores de p3 + 1 e 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;
}

Que tipo de problemas haverá neste momento? Quais são os valores de p3 + 1 e p4 + 1?

Espero que os leitores possam considerar cuidadosamente as questões acima.

Quatro, conversão forçada de endereço

Considere o seguinte exemplo primeiro:

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___?

Acredito que muitas pessoas não entenderão o que essa pergunta significa no início. Na verdade, se olharmos mais de perto, esse conhecimento parece familiar. Como analisar uma variável de ponteiro e um inteiro?

Lembra-se da diferença entre nossa expressão "a + 1" e "& a + 1" anteriormente?

Na verdade, é o mesmo aqui. Adicionar e subtrair uma variável de ponteiro a um inteiro não é adicionar ou subtrair diretamente o inteiro com o endereço na variável de ponteiro. A unidade deste inteiro não é o byte, mas o número de elementos.

Portanto: o valor de p + 0x1 é 0x100000 + sizof (Teste) * 0x1. Quanto ao tamanho desta estrutura é de 20 bytes, isso foi explicado em detalhes nos capítulos anteriores. Portanto, o valor de p + 0x1 é: 0x100014.

E quanto ao valor de (longo sem sinal) p + 0x1?
Isso envolve coerção, forçando o valor armazenado na variável de ponteiro p em um inteiro longo sem sinal. Assim que qualquer valor é coagido, seu tipo é alterado.
Portanto, esta expressão é na verdade um inteiro longo sem sinal mais outro inteiro. Portanto, seu valor é: 0x100001.

E quanto ao valor de (int não assinado *) p + 0x1?
Op aqui é coagido em um ponteiro para um inteiro sem sinal. Portanto, seu valor é: 0x100000 + sizof (unsigned int) * 0x1, que é igual a 0x100004.

A pergunta acima não parece ter nenhum conteúdo técnico. Aqui está um conteúdo técnico: Qual é o seu valor no 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;
}

Essa é uma pergunta que um aluno me fez durante a minha palestra, ele viu na Internet, diz-se que surpreendeu n pessoas. Depois de ler as perguntas, eu disse a ele que essas pessoas certamente não entendem de montagem.Para quem entende de montagem, esse tipo de pergunta é realmente um caso pequeno. Vamos analisar e analisar este problema abaixo:

De acordo com a explicação acima, a diferença entre & a + 1 e a + 1 é clara.

ptr1: Coercivamente converte o valor de & a + 1 para o tipo int e atribui-o à variável ptr do tipo int . ptr1 deve apontar para os próximos dados do tipo int na matriz a. ptr1 [-1] é analisado como * (ptr1-1), ou seja, ptr1 retorna 4 bytes. Portanto, seu valor é 0x4.
ptr2: De acordo com a explicação acima, o valor de (int) a + 1 é o endereço do segundo byte do elemento a [0]. Em seguida, force esse endereço a um valor do tipo int e atribua-o a ptr2, o que significa que o valor de ptr2 deve ser o conteúdo de 4 bytes consecutivos a partir do segundo byte do elemento a [0].

O layout da memória é o seguinte:
Insira a descrição da imagem aqui
Ok, aí vem o problema, o que exatamente está armazenado nesses 4 bytes consecutivos? Em outras palavras, como são armazenados os valores nos elementos a [0] e a [1]. Isso envolve os modos de endian grande e pequeno do sistema.Se você entende de montagem, isso não é um problema. Como você não sabe em que modo está o sistema atual, você precisa encontrar uma maneira de testá-lo. O modo small-endian e o método de teste foram discutidos em detalhes quando a palavra-chave union foi explicada no Capítulo 1, por favor, vá para outro lugar para vê-lo e não entrarei em detalhes aqui. Podemos usar a seguinte função para testar o modo do sistema atual.

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

Se o sistema atual estiver no modo big-endian, esta função retornará 0; se estiver no modo little endian, a função retornará 1. Ou seja, se o valor de retorno desta função for 1, o valor de * ptr2 é 0x2000000. Se o valor de retorno desta função for 0, o valor de * ptr2 é 0x100.

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

Acho que você gosta

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